2

My question is based on an answer to the topic “redefining a single ruby method on a single instance with a lambda”.

How can I redefine a method and from within the new method call the original definition? Other instances of some_object's class should not become affected.

def some_object.some_method
  # call original `some_object.some_method` here
  do_something_else
end
Community
  • 1
  • 1
  • @AndrewPiliser I have seen that question before but to my understanding it is about redefining a method of all instances of a specific class whereas my question is about redefining a method on a specific object without touching behavior of any other objects. I have changed my question to make this a little clearer. – Daniel A. R. Werner Jul 30 '16 at 00:43
  • There is no such thing as a singleton method. Every method in Ruby is an instance method. What you call a "singleton method" is just an instance method of the singleton class. Every method in Ruby is an instance method in a class, thus there is nothing special, the question applies exactly. (And I'm not saying that because my answer is the accepted one, I don't care about the rep.) Once you understand that, Ruby all of a sudden gets a *lot* simpler. – Jörg W Mittag Jul 30 '16 at 01:29
  • @JörgWMittag [Your answer on the other question](http://stackoverflow.com/a/4471202/1626400) is great but very broad — perfect for a blog post. I feel like my question is different from the one linked above as that one is kind of open for interpretation (the ruby example seems invalid: `Foo` is defined twice and it's not completely clear whether he wants inheritance explained or change `Foo` instances (all of them/one of them?) at runtime. Considering how vague that question is formulated, your answer does in fact do it justice. – Daniel A. R. Werner Aug 01 '16 at 09:15

2 Answers2

5

If some_object.some_method is not a singleton method, then you can just call super in your redefined method.

def some_object.some_method
  super
  do_something_else
end

If some_object.some_method is a singleton method, then

Ruby >= 2.0.0

You can define that method in a module

module SomeModule
  def some_method
    super
    do_something_else
  end
end

And then prepend it to the singleton class of the object

some_object.singleton_class.prepend(SomeModule)

Ruby < 2.0.0

You have to make an alias then redefine, since there is no Module#prepend.

class << some_object  # open the singleton class of some_object
  alias some_method_original some_method

  def some_method
    some_method_original
    do_something_else
  end
end
Aetherus
  • 8,720
  • 1
  • 22
  • 36
  • This [is in fact working well](http://www.tutorialspoint.com/execute_ruby_online.php?PID=0Bw_CjBb95KQMMEVqQVJsaW5qdGs) for me since it is not affecting other instances of `some_object`'s class. – Daniel A. R. Werner Jul 30 '16 at 00:36
1
class Klass
  def greeting
    puts "hiya"
  end

  def add_personal_greeting(str)
    define_singleton_method(:greeting) do
      super
      puts str
    end  
  end
end

Bob gets a handle and tries the standard greeting.

bob = Klass.new
  #=> #<Klass:0x007fa66b084ad0> 
bob.greeting
  # hiya

He finds that too impersonal so he decides to add "I'm Bob" after the greeting. He does that by defining a method greeting on his singleton class that calls Klass's instance method greeting and then adds another line to the greeting.

bob.add_personal_greeting("I'm Bob")

He tries it.

bob.greeting
  # hiya
  # I'm Bob

Much better. Note

bob.singleton_class.superclass
  #=> Klass

Meanwhile, Lucy tries the standard greeting.

lucy = Klass.new
  #=> #<Klass:0x007fa66a9ed050> 
lucy.greeting
  # hiya

She's not wild about it, but it will do.

Bob decides to change his greeting.

bob.add_personal_greeting("I'm Robert")

and tries it.

bob.greeting
  # hiya
  # I'm Robert
Cary Swoveland
  • 106,649
  • 6
  • 63
  • 100
  • Interesting approach with `add_personal_greeting` and `define_singleton_method`. But if I only know `some_object`'s interface or if I do not have control over its class(es) (e.g. it's coming from some library I use) then this approach is not applicable, right? – Daniel A. R. Werner Jul 31 '16 at 12:34