Module | Hookable |
In: |
Hookable.rb
|
Hookable provides you with the ability to hook into methods. Mix Hookable into a class and you can designate methods that can be hooked into.
Please see Hookable::Wrapper. All other methods are of little interest to you if you want to use the high-level interface.
A hook is a Proc that gets passed the object the hooked method is bound to, and the list of arguments passed to the hooked method. This Proc can then do whatever it wants to do and call the original method in the process.
The following example demonstrates the low-level interface. All methods used below are documented in Hookable::ClassMethods. state is a Hookable::State object which is documented as well.
require 'Hookable' class Something include Hookable def test *args puts "In Something#test(#{args.inspect})" end # Allow others to install hooks into test hookable :test end test_wrap1 = Proc.new do |state, *args| puts "BEGIN first wrapper around test" state.call *args puts "END first wrapper around test" end test_wrap2 = Proc.new do |state, *args| puts "BEGIN second wrapper around test" state.call *args puts "END second wrapper around test" end # Wrap test_wrap1 and test_wrap2 around Something#test Something.add_hook :test, test_wrap1 Something.add_hook :test, test_wrap2 s = Something.new s.test(1,2,3) # Temporarily prevent test_wrap1 from being called when Something#test runs Something.disable_hook :test, test_wrap1 s.test(4,5,6)
The output would be:
BEGIN second wrapper around test BEGIN first wrapper around test In Something#test([1, 2, 3]) END first wrapper around test END second wrapper around test BEGIN second wrapper around test In Something#test([4, 5, 6]) END second wrapper around test
a = Extender.method(:test_wrap1).to_proc b = Extender.method(:test_wrap1).to_proc puts a == b
This will return false. Why? Because Ruby creates two different Proc objects when you use Method#to_proc twice. As a result, calling Something.add_hook(:test, a) and then Something.remove_hook(:test, b) will not work.