From: Avi Bryant Date: 2001-01-26T19:35:45+09:00 Subject: [ruby-talk:9923] Re: ANN: AspectR 0.2 Robert, Having now actually looked over all of your modifications to my unassuming little hack ;-), I'm wondering if there might be a way of doing this that doesn't require quite so much textual manipulation of code... it's pushing the limit right now of what I'm comfortable with, although maybe that's just squeamishness on my part. what about using method_missing as a dispatcher for wrapped methods? That is, to wrap a method: -alias it, as we do now, to some mangled variation of its name -undef it -add the pre/post advice methods to a hash under the method name's key (in a hash local to the class, not a global one like you have now) method_missing then checks if it's been given a wrapped method, and if so pulls the advice methods out of the hash, uses send() to make the calls, etc. It's a little bit of extra overhead (send instead of direct method call, and the extra call to method_missing) but it should make things a fair bit cleaner, nu? Is there any reason this wouldn't work? Avi On Fri, 26 Jan 2001, Robert Feldt wrote: > 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 > # >