Evan Webb
4/4/2005 8:46:00 PM
See below.
On Apr 4, 2005 1:34 PM, Jan 'jast' Krueger <usenet@zoidberg.org> 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 <usenet@zoidberg.org>, Aachen, Germany
> (mails to <jast@...> go through less strict spam checking)
>
>