== Version 0.2.0 V0.2.0 changes the parameter list used for advice blocks and adds numerous enhancements, robustness improvements and more complete "spec'ing". Bug fixes: none Enhancements: 13402 Support a subclass syntax like AspectJ's "Type+" 13984 More flexible argument list to the advise block 14053 Remove JoinPoint#type, JoinPoint#type=, JoinPoint#object, and JoinPoint#object= 14061 Add a control flow mechanism to skipping (sic) intermediate advice 15164 Deprecate ObjectFinder 15413 Remove ObjectFinder 15710 Eliminate redundant public methods in various "finders" #13402 adds new invocation options to specify types and their descendents (subclasses or modules that include the specified module(s)) and ancestors. The latter should be used cautiously as it will include things like Kernel, Object, and Class! I used new command options rather than the AspectJ "+" suffix (and the proposed, but never implemented "-" suffix for ancestors), because the "+" would be confusing with regular expressions and not in the spirit of trying to make the pointcut language "easy to read". So, the following are now available: :type_and_ancestors :types_and_ancestors :type_and_descendents :types_and_descendents And the corresponding: :exclude_type_and_ancestors :exclude_types_and_ancestors :exclude_type_and_descendents :exclude_types_and_descendents If you want both the ancestors and descendents, just use both options with the same value. #13984 adds the object as the second argument to the advice block parameter list. This change reflects the fact that the object is often needed, but calling jp.context.advised_object is a bit tedious. THIS CHANGE BREAKS BACKWARDS COMPATIBILITY!! An exception is raised if advice has the signature |jp, *args|. #14061 adds a new method, JoinPoint#invoke_original_join_point, which will invoke the original method without intermediate advice. If called within around advice, you can write advice that vetoes all subsequent advice, yet invokes the original method. Use this technique cautiously, however, since you may not always know what other advices are involved and what side effects this control-flow change might cause. #15164 and 15413 remove ObjectFinder because it is not used and it requires ObjectSpace, which has high overhead and won't be enabled, by default, in JRuby (it will be optional). #15710 removes redundant methods that were becoming a maintenance issue, in particular, MethodFinder#find_all_by and TypeFinder#find_by_name. This is a non-backwards-compatible API change. Finally, note that I have not yet been able to resolve bug #15202, "Intermittent confusion between classes and objects when invoking advice." I believe this is a very rare occurrence and only likely to ever happen during the "torture-test" of running the RSpec suite. Please post a comment to Tracker if you encounter it! == Version 0.1.8 V0.1.7 did not successfully "register" at rubyforge. This releases fixes that problem and also adds several feature enhancements and refactorings. There are no known upgrade issues. Bug fixes: none Enhancements: 13399 Add :exclusion options for methods and types. 14707 :exclude_ancestor_methods as synonym for :suppress_ancestor_methods 13399 adds new :exclude_(pointcuts|join_points|types|objects|methods|attributes) options for Aspect.new, and Pointcut.new that make it easier to specify a list or regular expression for various "items" and then to exclude particular items, e.g., Aspect.new :around, :types => /nterestingType/, :exclude_types => UninterestingType ... The :exclude_ancestor_methods option is now preferred over :suppress_ancestor_methods, since the former is more consistent with the new :exclude_* options. == Version 0.1.7 Bug fixes: 14946 Advice fails when instrumenting methods containing special characters 15038 Spec for pointcut example variation #1 15039 Spec for pointcut example variation #2 15085 Specifying just :attributes for aspects also matches all methods, as if :methods => :all specified Enhancements: 13396 Unify internal handling of types vs. objects 15038 and 15039 were bugs in one of the examples (actually in the comments). However, experimenting with them also revealed the nasty 15085 bug! I previously handled some special characters in method names, but not all the possible ones, hence 14946. Aquarium should now properly handle any valid Ruby method name. == Version 0.1.6 Bug fixes: 14353 Advising subclass method that calls super raises exception when method executed 14356 Regexps for types must cover the whole name, which is inconsistent with method/attribute regexps 14384 Design by Contract "extra" does not return correct value "invar" handling 13410 Fix funky navigation bar on website 14353 was kind of bad, but it's actually a Ruby bug with a good workaround. If you advised a method that called "super", Ruby would use the wrong method name to lookup the class in the parent. See the bug description for the details. For 14356, type regular expressions now match on parts of names; they don't have to match the whole name. The exception is regular expressions with module separators "::". In this case, it seems to make more sense for the regular expression to be interpreted as follows: If the expression is /A::B::C::D/, then for the the outermost types, the expression behaves as /^.*A/, for the types between two "::", the expressions behave as /^B$/ and /^C$/, and the trailing expression behaves as /D.*$/. 14384 was an easy mistake to make with "around" advice; you have to remember to return the result of the "join_point.proceed" call, unless you specifically want to change the returned value! Here are two ways to do it: do_something_before(...) result = join_point.proceed do_something_after(...) return result or begin do_something_before(...) join_point.proceed ensure do_something_after(...) end The latter approach looks "asymmetrical" and it will behave differently if "proceed" raises! However, it eliminates the temporary, if you find that desirable. Enhancements: 13407 Pick a better method name for JoinPoint#type, which hides the Module#type 14385 Pointcut.new should accept a :join_point => jp argument 14386 Aspect.new ..., :pointcut => should accept a join point object 14440 Add good warning message when "proceed" used for non-around advice For 13407, new attribute methods have been added * JoinPoint#target_type return the type that the join_point matches. * JoinPoint#target_type= set the type that the join_point matches. * JoinPoint#target_object return the object that the join_point matches. * JoinPoint#target_object= set the object that the join_point matches. The following, older methods are now deprecated and will be removed in the 0.2.0 release (#14053): * JoinPoint#type * JoinPoint#type= * JoinPoint#object * JoinPoint#object= JoinPoint#type method is deprecated because it hides Module#type, which returns the type of the corresponding object. For "symmetry", the other three methods are also now deprecated and they will be removed in a future release. Until then, all will print a warning message to STDOUT. (If you really want the type of what could be a JoinPoint object, you should use #class anyway, as Module#type is also deprecated!) == Version 0.1.5 Bug fixes: 13514 Protected and private methods are made public when advised and left that way when unadvised 13650 Loading Aquarium interferes with Rails filters 13864 Bug with negative object_id Enhancements: 13392 Convert examples to specs. 13463 Support running in JRuby Fixing 13650 required an API change, which is why I've tagged this release "0.1.5" instead of something like "0.1.1" (and the changes don't seem big enough to warrant "0.2.0"...). Previously, requiring "aquarium.rb" in the top-level "lib" directory would implicitly require lib/aquarium/aspects/dsl/aspect_dsl.rb, which has Object include the AspectDSL module. This module adds methods like :before and :after to Object. Unfortunately, those methods collide with methods of the same name that Rails adds to Object. It was also a bit presumptuous of me to assume that everyone wanted those methods on Object ;) In this release, aspect_dsl.rb is still implicitly included and it still defines the AspectDSL module. Now, however, it does not include the AspectDSL module in Object. Instead, if you want this behavior for all types, you must require the new lib/aquarium/aspects/dsl/object_dsl.rb explicitly. As an alternative, if you just want the AspectDSL module included selectively in certain types, then do the following: class MyClass # reopen "MyClass" # Add the methods as _class_ methods include Aquarium::Aspects::DSL::AspectDSL end or, use (class|module)_eval: require 'aquarium/aspects/dsl/aspect_dsl' MyClass.class_eval do # Add the methods as _class_ methods include Aquarium::Aspects::DSL::AspectDSL end To add the methods as _instance_ methods on individual objects: object = MyClass.new object.extend(Aquarium::Aspects::DSL::AspectDSL) Note: as discussed at http://practicalruby.blogspot.com/2007/02/reopen-with-moduleeval.html, using "class_eval" or "module_eval" is safer that just reopening a class if you're not sure that "MyClass" has actually been defined yet. However, in our particular case, it probably doesn't matter, as AspectDSL doesn't change anything about the type, like aliasing existing methods. Still, we can't guarantee that this won't change in the future. == Version 0.1.0 This is the initial version.