From: Evan Webb Date: 2005-04-05T05:46:28+09:00 Subject: Re: Wrote "Hookable" mixin, what now? See below. On Apr 4, 2005 1:34 PM, Jan 'jast' Krueger wrote: > > To chime in, perhaps we should look to merge Hookable and the class > > that I've been working on, called Maskable. It has a similar aim, > > allows you to attach new methods to run with an original method. > > Looks nice, though I haven't digged through all of the code yet. > > > modified (like Kernel.require). With a few tweaks from the Hookable > > code, it'd be possible to add the hook style stuff too. > > > > Maskable is thread safe as well. > > The problem with Hookable is that hookable methods aren't reentrant. When a > hookable method is run, it's pushed on a stack within the internal state of > the owner class. This happens so you can use "super" in hooks (or the > equivalent for the Proc interface) without having to know what method you > were hooking. The stack makes it possible for one hookable method to call > another, like this: > > def SomeClass > include Hookable > def test1 > test2 > end > def test2 > # nop > end > hookable :test1, :test2 > end > > The stack is only necessary because you might want to do this: > > a = Proc.new do |obj, *args| > # nop > obj.hooked_method *args > # nop > end > > SomeClass.add_hook(:test1, a) > SomeClass.add_hook(:test2, a) > > This could be changed so the Proc gets another argument containing the > method name, I suppose, but it makes the Proc interface just a little bit > more awkward. > > Now for your main question. I think Maskable and Hookable are both useful, > but there's no reason for mixing them--they provide quite different > functionality. > > Even if I misjudged that, your Maskable calls masked methods sequentially > while Hookable calls hooks on the same method nested into each other. It's > probably just not worth the effort rewriting either module. Actually, not true. Thats just the default behavior. A method can change how the subsequent methods are called by calling Method.rest which will run all the methods under it and returns the result. The reason for this is that methods that are added via a mask know they are masking something, so they can call Method.rest and get the result of calling the methods under it so it can act on that result. Whereas when a method is masked, it probably doesnt know it's been masked, so when it returns without calling Method.rest, the next method is run. Below is a quick example of the 2 behaviors. class A def run puts "in A run" end end class B def run puts "in B run" end end module Mask1 def run puts "start mask1" puts "end mask1" end end module Mask2 def run puts "start mask2" Method.rest puts "end mask2" end end A.add_mask Mask1 B.add_mask Mask2 A.new.run # output is: # start mask1 # end mask1 # in A run B.new.run # output is: # start mask2 # in B run # end mask2 > > At first glance, I think Maskable and Hookable can co-exist within one > class, as long as you don't mask a hookable method (which wouldn't make a > lot of sense anyway). > > > Thoughts? > > Even if I don't (yet) like the idea of combining Maskable and Hookable, > you've given me a few things to think about. Thank you! Your welcome! I'm going to take a look at Hookable this evening as well. - Evan > > -- > Best regards, > Jan 'jast' Krueger , Aachen, Germany > (mails to go through less strict spam checking) > >