Method#unbind
returns an UnboundMethod
reference to the method, which can later be bound to another object using UnboundMethod#bind
.
class Foo
attr_reader :baz
def initialize(baz)
@baz = baz
end
end
class Bar
def initialize(baz)
@baz = baz
end
end
f = Foo.new(:test1)
g = Foo.new(:test2)
h = Bar.new(:test3)
f.method(:baz).unbind.bind(g).call # => :test2
f.method(:baz).unbind.bind(h).call # => TypeError: bind argument must be an instance of Foo
Initially, I thought this is incredibly awesome, because I expected it would work similarly to JavaScript's Function.prototype.call()
/Function.prototype.apply()
. However, the object to which you want to bind the method must be of the same class.
The only application I can think of is if you unbind a method, lose the original implementation (redefine the method in the original or singleton class) and then rebind and call it.
I'll summarize the good uses I found so far. Neither uses unbind
though.
Firstly, overwriting a method, using the old implementation. Source, thanks to @WandMaker.
Let say you want to do something like this:
class Foo
alias old_bar bar
def bar
old_bar
some_additional_processing
end
end
This will work, but will leave behind old_bar
, which is not something desirable. Instead, one could do:
class Foo
old_bar = instance_method(:bar)
define_method(:bar) do
old_bar.bind(self).call
some_additional_processing
end
end
Secondly, calling another implementation of a method from the hierarchy. Source.
The very practical example given in the post was that often times during debugging, you want to find where a method was defined. Generally speaking you can do that by:
method(:foo).source_location
However, this won't work if the current instance implements a method
method, like is the case with ActionDispatch::Request
. In that case you can do:
Kernel.instance_method(:method).bind(self).call(:foo).source_location
Method and UnboundMethod types expect that the bind target must be subclass of the original class where you have referenced the method. However the Method has a #to_proc
method implemented and with that, you can get rid off the 'same class type' constraint.
You have to use #send
method, as #define_method
is private (you cannot call it directly).
class A
def hoge ; "hoge" ; end
end
class B ; end
hoge = A.new.method(:hoge)
B.send(:define_method, :hoge_in_b, &hoge) #converting to proc
b = B.new
puts b.hoge_in_b
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With