From: "Mauricio Fernández" Date: 2002-10-17T02:09:23+09:00 Subject: Re: Hooking on method invocation On Wed, Oct 16, 2002 at 04:10:14PM +0000, ahoward wrote: > > > > > Is there a way to hook on invocation of *any* instance method of > > > > an > > > > object? > ... > [snip] > ... > > > > Code follows: > > > > module Observable > ... > [snip] > ... > > theproxy.another > > > that seems pretty complicated - it seems like what is needed is a > specialization of a class, espcially since only the assignment methods > need > overridden. isn't this *the* job of inheritence? eg: In fact this could be meaningful w/ any method that changes the state of an object, assignment or not. > > > def assignment_hook(*args) > re = /`([^']+)'/ > m = re.match caller(1)[0] > m or raise 'FAILED TO LOOKUP METHOD NAME' > methodname = m[1] > > # notify observer here... > puts "hook for #{methodname}(#{args.join ','}) called..." > end > > class Original > def foo=(*args) > # do something > end > end > > class Hooked < Original > def foo=(*args) > assignment_hook *args > super *args > end > end > > > h = Hooked.new > h.foo= 0,1,2 # --> hook for foo=(0,1,2) called... > > > simple : yes > fast : yes > safe : yes > typing : yes Yes, but you have to redefine all the methods needing some kind of "write barrier". The way I showed before, the BarrierKeeper is in fact a proxy which decides whether a method call should be forwarded or not; and it is easily mixed with the Observer pattern. What I don't like about inheritance is having to type def method(*args) hook(*args) super *args end which is of course more of a matter of taste. And then again, it would be possible to create something like set_barrier :method_name, proc { |method, args| ... } which could work either via inheritance or delegation. Delegation gives you more freedom, for a BarrierKeeper could potentially take care of different objects during runtime, even those of an unknown class! If you use inheritance, you end up having to know the class of the object _or_ using lots of singleton methods. And you'd have to use the evil eval :-) Guess it's just another case of object vs class design pattern... -- _ _ | |__ __ _| |_ ___ _ __ ___ __ _ _ __ | '_ \ / _` | __/ __| '_ ` _ \ / _` | '_ \ | |_) | (_| | |_\__ \ | | | | | (_| | | | | |_.__/ \__,_|\__|___/_| |_| |_|\__,_|_| |_| Running Debian GNU/Linux Sid (unstable) batsman dot geo at yahoo dot com I once witnessed a long-winded, month-long flamewar over the use of mice vs. trackballs... It was very silly. -- Matt Welsh