From: Erik Veenstra Date: 2006-07-22T22:21:07+09:00 Subject: Re: Meta-Meta-Programming, revisited > I don't think the reciever of the wrap should be an argument. > Instead just let it be ther reciever of the pre_ call. For > example Instead of: > > pre_condition(Module, :method_added) do |*args| > > Module.pre_condition(:method_added) do |*args| # NOT THE SAME Module is not the receiver! The argument Module is just an indicator (stupid abuse), so pre_condition knows that is has to wrap a module method (with "class << self" in wrap_module_method) instead of an instance method. I should have called it pre_module_condition. (Like wrap_module_method instead of wrap_method.) I was just sick of creating more methods... ;] > Also, #wrap_method seems like it could do with some > simplification. Taking that to the furthest case, is their a > reason the the following definition isn't enough? > > def wrap_method( sym, &blk ) > raise ArgumentError, "method does not exist" unless method_defined?( sym ) > old = instance_method(sym) > define_method(sym) { |*args| blk.call(old.bind(self), *args) } > end Well, life isn't that easy... (Have a look at the code below.) First thoughts: * You definitely want to pass the block from the original invocation to the original definition... Really... (In Ruby 1.9, this could be done your way, since blocks do get blocks. But not in Ruby 1.8.) * I wanted to be able to wrap non-existing methods. * When wrapping :initialize in Bar, your wrap_method complains with "method does not exist". * When wrapping methods in both the class and the superclass, going up and down, you can't (at wrap-time) determine the order in which the blocks are to be executed (at run-time). If I run the code below with your wrap_method (after removing the "method does not exist" check), this :wrap_Foo is gone! It's not what _I_ expected... ;] (See [1] for a more complicated example. I'll try to make a diagram.) It's complicated stuff... I tried to hide this complexity for the user, by providing a clean interface (wrap_method) and an even cleaner interface (pre_condition). I hope you find them easy to use. gegroet, Erik V. - http://www.erikveen.dds.nl/ [1] http://www.erikveen.dds.nl/monitorfunctions/index.html#5.1.0 ---------------------------------------------------------------- class Foo def initialize(&block) p [:initialize, block] end end class Bar < Foo wrap_method(:initialize) do |m, *a| p [:wrap_Bar] m.call(*a) end end class Foo wrap_method(:initialize) do |m, *a| p [:wrap_Foo] m.call(*a) end end Bar.new{} ----------------------------------------------------------------