Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Monkey patching: Does define_method take precedence over bind?

Tags:

ruby

In the below code snippet, I monkey patch Foo#bar with a define_method block. After I initialize a new instance of Foo, I overwrite it with a bind call to the parent class bar method, but when I call the method the block defined by the define_method block is called. Why doesn't the bind call change the behavior of the method?

class OriginalFoo
  def bar
    puts 'in OriginalFoo!'
  end
end

class Foo < OriginalFoo
  def bar
    puts 'in Foo'
  end
end

class Foo < OriginalFoo
  old_bar = instance_method(:bar)
  define_method(:bar) do
    puts 'in define_method block'
    old_bar.bind(self).call
  end
end

foo_instance = Foo.new # => #<Foo:0x00007fe3ff037038>
OriginalFoo.instance_method(:bar).bind(foo_instance) # => #<Method: OriginalFoo#bar>
foo_instance.bar
# >> in define_method block
# >> in Foo
like image 779
wils484 Avatar asked Mar 06 '23 12:03

wils484


1 Answers

You're misunderstanding how UnboundMethod#bind works. You call Module#instance_method to get an UnboundMethod (i.e. a method without a self):

OriginalFoo.instance_method(:bar)
# #<UnboundMethod: ... >

Then you call UnboundMethod#bind to attach a self to that method, that returns a Method instance:

m = OriginalFoo.instance_method(:bar).bind(foo_instance)
# => #<Method: ...>

But that won't alter the method in foo_instance, all it does is make self your foo_instance when (or if) you said m.call: um.bind(obj) doesn't do anything to obj, it just gives you um as a Method that has obj as its self.

like image 109
mu is too short Avatar answered May 13 '23 03:05

mu is too short