I've been doing some thinking on AOP ...

There are three fundematnal implementations types of AOP: Static Weaving, 
Dynamic Weaving and Dynamic Triggering (Event-based). 

So how do these differ?

Static weaving simply looks at source and based on it determines where to add 
(and possibly remove) code.[1] Thus it is limited to the program definition 
and cannot alter the program based on any execution state. This works okay 
for static languages like C, but would never do for a dynamic language like 
Ruby simply b/c the code itself can change on the fly. That's where Dynamic 
Weaving comes in. It is the same as Static Weaving except that it can react 
to dynamic code changes; it is thus an AOP necessity for any dynamic language 
like Ruby. But that is really all it is --it simply adjusts for weaves based 
on code changes, NOT state changes. While it is possible for Dynamic Weaving 
to dynamically add and (potentially remove) weaves based on state changes, 
doing so is exceedingly hackish --it is much easier to check for state 
changes within permanently weaved advice. To properly aspect code based on 
state one must move to full-fledged Dynamic Event-based Triggering AOP.

In my experimentation with "legacy" AOP implementations like that of AspectJ 
and AspectR, I've come to the conclusion that they are of only minor use in a 
language as dynamic as Ruby. With a good mechanism for weaving, like `class 
cuts`, reentrant classes, and a good set of callbacks, one can do everything 
AspectJ, or like lib, can do in a way generally more fitting the actual 
problem. Consider:

  class AnAspect < Aspect
    def pointcut( jp )
      :advice if jp.klass.name =~ /^T/ && jp.meth.to_s =~ /^t/
    end
    def advice(*args)
      puts "Log #{target.meth} args.inspect" 
    end
  end

vs. 

  class Class
    def method_added( meth )
      if self.name =~ /^T/ && meth.to_s =~ /^t/
        Cut.new( self ).send(:define_method, meth) do |*args|
          puts "Log #{meth} args.inspect"
        end
      end
    end
  end

The former "traditional" AspectJ-esque way is a bit easier to read, which is 
nice, but only a bit. Any implementation of an AspectJ-like lib for Ruby will 
essentially translate the former into something akin to the later (albiet a 
more efficient implementation [2])

So it does not strike me as largely significant to design yet another YAAR 
(Yet Another Aspect lib for Ruby) --on the whole the matter is fairly 
straight forward.

I need to take a break. I will be following this up with some more thoughts on 
Event-based AOP.

T.


== FOOTNOTES ==

1  An interesting thought is whether it could weave code based on its own 
previous weaves --and thus the potential for an infinite aspecting. Ouch.

2  Peter you might notice why I used the #clearcut method in dynaop.rb from 
the above example. With it I was able to advise methods individually while 
minimizing the number of Cuts added to a class (fro efficiency). This makes 
me think that an excellent support method for cuts would be exactly that:

  Class.define_cut_method( sym ) { |*args| ... }

This would define a method in the nearest cut of class lacking the method 
#sym, or create a new cut for if need be. Then the above implmentation 
becomes simply:

  class Class
    def method_added( meth )
      if self.name =~ /^T/ && meth.to_s =~ /^t/
        self.define_cut_method( meth ) do |*args|
          puts "Log #{meth} args.inspect"
        end
      end
    end
  end

And perhaps a better name for that method is simply #wrap ;)