Class | Hookable::Wrapper |
In: |
Hookable.rb
|
Parent: | Object |
Wrapper manages a number of instance methods that can easily be wrapped around instance methods of another class (as can be done with Hookable::ClassMethods#add_hook).
There are class methods to add, remove, enable or disable one or all instance methods for one target class. You can, for example, wrap one method of a Wrapper subclass around a method in Foo and, at the same time, all methods of the same Wrapper subclass around the corresponding methods in Foo.
Your wrapper method will get exactly the same arguments as the wrapped method, plus a prepended Hookable::State argument.
In your wrapper methods you can use super to run the method you’re wrapping around. See "Oddities" below.
This is probably not helpful, so here’s an example:
require 'Hookable' class Something include Hookable def test_inner *args puts "In Something#test_inner(#{args.inspect})" end hookable :test_inner def test *args puts "In Something#test(#{args.inspect})" test_inner(*args) end hookable :test end class MyWrapper < Hookable::Wrapper def test_inner state, *args puts "BEGIN wrapper around test_inner" super puts "END wrapper around test_inner" end def test state, *args puts "BEGIN wrapper around test" super puts "END wrapper around test" end end # See 'Oddities' below! Kernel.send(:undef_method, :test) MyWrapper.add_all_to Something s = Something.new s.test(1,2,3) MyWrapper.disable_in Something, :test_inner s.test(4,5,6) MyWrapper.enable_all_in Something s.test(7,8,9)
This will produce the following output:
BEGIN wrapper around test In Something#test([1, 2, 3]) BEGIN wrapper around test_inner In Something#test_inner([1, 2, 3]) END wrapper around test_inner END wrapper around test BEGIN wrapper around test In Something#test([4, 5, 6]) In Something#test_inner([4, 5, 6]) END wrapper around test BEGIN wrapper around test In Something#test([7, 8, 9]) BEGIN wrapper around test_inner In Something#test_inner([7, 8, 9]) END wrapper around test_inner END wrapper around test
There is one very important thing that might be frustrating if you happen to stumble upon it: if one if your wrappers has the same name as an instance method in Class (that includes all Kernel methods), super will not work. The error message will be very confusing, too.
Consider the code above. I have removed Kernel#test because I defined MyWrapper#test, which—as I’ve said—won’t work. If I hadn’t done that, I would have been very confused. Try it yourself if you like.
When you run into this problem, please use Hookable::State#call.