Lautaro urtiaga
Lautaro urtiaga

Reputation: 152

Redefining a singleton_class method to behave exactly as it was behaving before but also do something else

I want to change a singleton_class method of a certain class for it to do the same as it was doing before but also do something else, For example apart from what it was doing, to do:

Ok, so i know how to redefine a normal method of a class to actually do the same as it was doing before but also do something else, it would be like this:

class Class
   def addHelloToMethod(methodName)
       unboundMethod = instance_method(methodName)

       define_method(methodName) do |*args, &block|

          result =unboundMethod.bind(self).(*args, &block)
          puts "hello"
          result
      end
   end
end

What i need is to actually add this "hello" to a singleton_class method so i tried this:

class Class
   def addHelloToSingletonClassMethod(methodName)
       unboundMethod = singleton_class.instance_method(methodName)

       singleton_class.define_method(methodName) do |*args, &block|

          result =unboundMethod.bind(self).(*args, &block)
          puts "hello"
          result
      end
   end
end

What am i doing wrong here?

Upvotes: 1

Views: 102

Answers (2)

fphilipe
fphilipe

Reputation: 10054

One way of doing this is to prepend an anonymous module that overrides the desired method, prints hello, and calls super to invoke the actual implementation.

I'm not sure why you're adding this method to Class. Is your goal to call the addHelloToSingletonClassMethod on an instance of a class such as this?

irb> s = "foo"
irb> s.addHelloToSingletonClassMethod(:upcase)
irb> s.upcase
hello
=> "FOO"

If so, define the following on Object:

class Object
   def addHelloToSingletonClassMethod(methodName)
     mod = Module.new
     mod.define_method(methodName) do |*args, &blk|
       puts "hello"
       super(*args, &blk)
     end

     singleton_class.prepend(mod)
   end
end

Or in more typical Ruby naming convention:

class Object
  def add_hello_to_method(name)
    mod = Module.new
    mod.define_method(name) do |*args, &blk|
      puts "hello"
      super(*args, &blk)
    end

    singleton_class.prepend(mod)
  end
end

If your goal on the other hand is to be able to call it on a class as follows

irb> String.addHelloToSingletonClassMethod(:upcase)
irb> "foo".upcase
hello
=> "FOO"

then you want to define it on Class:

class Class
  def add_hello_to_method(name)
    mod = Module.new
    mod.define_method(name) do |*args, &blk|
      puts "hello"
      super(*args, &blk)
    end

    prepend(mod)
  end
end

Upvotes: 3

Change change addHelloToSingletonClassMethod to self.addHelloToSingletonClassMethod. It should be a class method.

Upvotes: 0

Related Questions