From: Robert Feldt Date: 2001-01-26T18:43:54+09:00 Subject: [ruby-talk:9919] ANN: AspectR 0.2 Hi, Avi Bryant and me joined forces and merged our two Aspect-oriented Programming (AOP) hacks into AspectR. (Avi will submit to RAA in a couple of hours or so in the mean time you can find it at www.ce.chalmers.se/~feldt/ruby/extensions/aspectr/aspectr-0-2.rb) It's still a hack/pre-alpha release but IOHO it is useable. Be warned that there are probably bugs, though... Below you'll find an excerpt from the readme/header. Would be great if some of you AOP-gurus out there can comment or have some ideas. Thanks. If you wonder what AOP is you can take a look at http://www.parc.xerox.com/csl/projects/aop/. On the more pragmatic side (;-)) you might appreciate the following code for adding logging/tracing to all classes in your project: require 'aspectr' include AspectR module Logger; extend Aspect def tick; "#{Time.now}"; end def log_enter(method, exitstatus, *args) $stderr.puts "#{tick} #{self.class}##{method}: args = #{args.inspect}" end def log_exit(method, exitstatus, *args) $stderr.print "#{tick} #{self.class}##{method}: exited " if exitstatus.kind_of?(Array) $stderr.puts "normally returning #{exitstatus[0].inspect}" elsif exitstatus == true $stderr.puts "with exception '#{$!}'" else $stderr.puts "normally" end end end AspectR.wrap_classes(Logger, :log_enter, :log_exit, classes, methodregexp) where classes is array with your classes and methodregexp is a regexp for the methods to add logging/tracing to. Regards, Robert # AspectR - simple Aspect-Oriented Programming (AOP) in Ruby. # Version 0.2, 2001-01-26. # # AspectR lets a module wrap any number of methods in other classes # (or objects) with the "advice" methods (in the lingo of Aspect/J) # of the module. # Usage: # require 'aspectr' # module MyAspect # extend Aspect # def someAdviceMethod(method, exception, *args) # ... # end # ... some other advice methods ... # end # MyAspect.wrap(someClass, :preAdvice, :postAdvice, ... methods to wrap...) # or # MyAspect.wrap(someClass, :preAdvice, :postAdvice, /patternToWrap/) # or # AspectR.wrap_classes(someAspect, :predAdvice, :postAdvice, # [Class1, Class2], ...methods to wrap...) # # Advice methods are passed a variable number of parameters: # the first is the name of the method currently being wrapped # the second is the exit/return status: # Array with return value(s) if the method exited normally # true if the method exited with an exception # nil if the method hasn't yet exited (for preAdvice) # the rest are the arguments that were passed to the wrapped method. # # Main features of AspectR (in AspectJ lingo): # * Join points: # object receives method/constructor call, and field # accessed (if access is via getter/setter meth) # * Advices: before (pre), after returning and after throwing (post) # * Aspects: declared as modules extending (top-level) module Aspect. This # supports "abstract" Aspects and overriding between advices. # * Wildcards (really regexps) can be used in pointcut designators, ie. # to specify classes and methods to wrap advice's to. # * Pointcut parameters: advices can access object and method receiving # call, arguments to call, exception raised and return values. # # AspectJ feature that AspectR is missing (AOP gurus out there: Any need for # these features? Are they meaningful in Ruby?): # * Join points: method/constructor called, method/constructor executes (?), # exception handler executes # * Most of the pointcut designator primitives # * Composition of pointcut designators (well you can of course specify # several method calls in different classes and objects) # * 'around' advices (should be pretty easy to add if there's a benefit) # * precedence/specificity among advices/aspects # * reflection by sending joinpoint object to advices with context of join # point etc (easily added but why?) # * control-flow based crosscutting (might be possible if we locally attach # a trace func but are they needed?) # # TODO/WishList for AspectR: # * FIX: generate_syntax must handle all special method names. Apply to # Ruby std classes to find the problematic ones. # * FIX: Since Advice's are included their method names might clash with # method names in wrapped classes/objects. # * FIX: Advice methods shouldn't be "renamed" (aliased) when called in # classes since we cannot change them dynamically afterwards... # Or how should it work? What is AOP state-of-the-art? # * Move examples into test file and extend the tests. # * Move stuff from this painstakingly long header into some README ;-) # * Adding method call join points by setting a trace_function in the # dispatch code?! But the perfomrance penalty with trace funcs is # severe... # * Some way to match regexp to methods when wrapping object? Should we # simply match to methods in objects class and then make them singletons? # Probably... # * Find out if it is possible to dynamically control if the aspect will be # called. Would it be a good thing to be able to turn advice dispatch off # when in an advice method? # return #{call} if @@__aop_disabled at the first row of the dispatcher? # Or more complex expressions? Control for each aspect? (Possible # implementation is to have flags in a hash in Advice) # * Check into RAA under lib/Meta? # * Encapsulate all join point information (method name, args, return val, # context, exception etc) into one object (JoinPoint??) that is sent to # advice's? Performance penalty? Maybe you should be able to choose # the kind of data returned? But there will be a lot of params so we'd # really need some keyword args. Matz, are you listening? ;-) # * Add examples: type/error checking, synch, fault tolerance, profiling # * Thread safety?! # * Check what is in AspectJ or other AOP-project/papers and see what we # could/should add: # * Check out the paper Aspect Oriented Programming: A Critical Analysis # of a New Programming Paradigm (1999) Timothy Highley, Michael Lack, # Perry Myers #