From: Jacob Fugal Date: 2005-10-22T01:30:41+09:00 Subject: Re: Cut-based AOP On 10/20/05, Alexandru Popescu wrote: > class TransactionAspect < AOP::Aspect > pointcut: transactionalMethod => "*#save*(..) || *#delete*(..)" > > before: transactionalMethod > def assureTransaction > [...] > end > end How about this? Aspect.before( '*#save*', '*#delete*' ) do # advice end Implementation[1]: module Aspect def before( *cut_specifications, &advice ) cut_specifications.each do |spec| unless PointCut === spec spec = PointCut.new( spec ) end spec.joinpoints.each do |joinpoint| joinpoint.before &advice end end end end class PointCut attr_reader :joinpoints def initialize( *cuts ) @joinpoints = [] cuts.each do |cut| module_pattern, method_pattern = cut.split /#/ module_pattern = Regexp.new /^#{module_pattern}$/ method_pattern = Regexp.new /^#{method_pattern}$/ ObjectSpace.each_object(Module).each do |base| if module_pattern.match( base.to_s ) adv = {} base.instance_methods(false).each do |meth| if method_pattern.match( meth.to_s ) @joinpoints << JoinPoint.new( base, meth ) end end end end end end class JoinPoint def initialize( klass, meth ) @klass = klass @method = meth end def before( &advice ) if Class === @klass Cut.new( @klass ) do define_method @method.to_s &advice end else aspect = mod.new do define_method(a,&p) end @klass.module_eval do preclude aspect end end end end Jacob Fugal [1] COMPLETELY UNTESTED. Most likely buggy, ineffecient and/or incomplete. But should give an idea of how to do a cross cut like Alexandru wanted using Cuts as a basis.