Change Notes

== Version 0.7.3

(0.7.2 had documentation errors.)

Removed an ill-advised (if you'll pardon the expression...) use of monkey patching to add a `to_camel_case` method to `String`, which I only used in one place! Instead, I just call a utility to do this.

== Version 0.7.1

Adds support for Ruby 2.6. It was tested with 2.6.3p62 (2019-04-16 revision 67580). Basic JRuby 9.2.7.0 (2.5.3) 2019-04-09 8a269e3 support is provided, but using JRuby currently does *not* pass all the custom Java specs in the `jruby/spec` directory, which specifically test working with Java classes. However, JRuby does pass all the Ruby specs in the `spec` directory. This is a long-standing issue with JRuby support in Aquarium. Patches are welcome!

== Version 0.6.0

V0.6.0 fixes thread-unsafe code in Aspect::alias_original_method_text, which
I've known about since the beginning of the project. At the beginning of Aquarium,
circa 2006, the overhead of making copies of JoinPoints in this method was
approximately 30%! So, I sacrificed thread-safety for performance. Now, thread
safety is increasingly important in modern apps, and fortunately, the overhead
on newer machines and newer versions of Ruby is greatly reduced for making these
copies. Hence, this problem is fixed.

The rspec suite does not test thread safety in any rigorous way, so caution is
advised. Please report any problems or better, submit pull requests of better
threading tests and possible bug fixes. As always, thanks in advance.

I also fixed deprecation warnings from the latest version of RSpec. There were a
lot of them!

Now supports Ruby 1.9.X, Ruby 2.0, and JRuby 1.7.4 (please report version-related bugs!)
Drops official support for Ruby 1.8.X.


== Version 0.5.1

V0.5.1 adds support for Ruby 1.8.7, Ruby 1.9.3, JRuby 1.6.7,
RSpec 2.9, and Webgen (0.5.14 - for the build process).

WARNING: Earlier versions of Ruby 1.8, 1.9 and JRuby 1.X are not
supported. JRuby support is limited to "pure" Ruby code; the main
RSpec specifications pass under JRuby, but not the JRuby-specific
specifications in jruby/spec. Restoring full JRuby support is planned,
but the timeframe is TBD.

It also has some minor API changes summarized below.

Enhancements:
22558	Support Ruby 1.9.1 (actually 1.9.3)
27235	Support RSpec 1.2.8 (actually 2.9) and and JRuby 1.3.1 (actually 1.6.7)
27236	Upgrade website generation to webgen 0.5.X (X=14)

The actual versions of these tools supported are more recent versions
shown in parentheses.

There are no API changes in this release, with two exceptions.

First, Most of the code changes are minor fixes to RSpec files. The one
exception is an apparent change that occurred in JRuby 1.3.X with respect
to the access restrictions on Java methods. It now appears that protected
methods are public, that is they are in the method list returned by
:public_methods, but not :protected_methods. Also, private methods are
not returned by any of the :*_methods.

Second, there was a deprecated option to the MethodFinder class,
:options, that has been removed. Use :method_options instead.

I used the upgrade to Webgen 0.5.X as an excuse to refresh the web site's
appearance. The content is mostly the same as before.


== Version 0.4.3

V0.4.3 adds a few bug fixes and enhancements, and several internal
refactorings to improve performance, etc.

Bug fixes:
[none]

Enhancements:
14165	Support Ruby 1.8.2, 1.8.5, 1.8.6, 1.9.X and 2.0 releases and snapshots
21283	Allow "_of" suffix at end of "*_and_descendents", "*_and_ancestors",
  and "*_nested_types"
21924	Should be able to turn off contract-testing aspects globally in the
  Design by Contract extra module
21993	By default, don't advise "system" methods that being with "_", but
  provide an option to do so

Details:
14165: I closed this one because it's too broad. Aquarium currently runs with
  1.8.6. I will open a new enhancement specifically for 1.9.
21283: Sometimes appending "_of" makes the specification read more smoothly,
  so it's now an option.
21924: To class-level methods in DesignByContract, enable_all and disable_all,
  globally turn contracts on or off. See their documentation for details.
21993: Now, by default, MethodFinder won't match any method that starts with
  two underscores ("__"), so you don't have to :exclude_ancestors as much just
  to avoid matching methods like  "__id__" and "__send__". There is also a new
  :method_options called :include_system_methods that will not suppress
  matching these methods. So, I'm calling these special methods "system
  methods". I don't yet provide a way to configure this list (RSpec methods
  would be good additions...). The list is currently defined as an array of
  regex's, MethodFinder::IGNORED_SYSTEM_METHODS. NOTE: This is effectively a
  behavior change, although it's not likely to affect anyone.

== Version 0.4.2

V0.4.2 adds a few bug fixes and enhancements, greatly improved RDoc output,
and internal refactorings to improve performance.

Bug fixes:
15202	Intermittent confusion between classes and objects when invoking advice
19262	Just putting join_point argument in advice block causes mysterious
  method missing error.
19321	Advice overhead is too high (ongoing improvements)

Enhancements:
13403	Support recursion into nested types without requiring "tricky" regular
  expressions
13406	"Sugar" for adding methods and attributes to types
18537	Provide a search for all pointcut constants
19666	Improve the RDoc output
19119	Provide an "after_raising" type of advice that lets you handle the
  exception.

#15202: I never figured out the cause of this problem, but it hasn't been seen
  since late last
year, so I suspect it disappeared as a side effect of on-going refactoring and
  enhancements.

#19262: If you just specified "|jp|" for an advice block, you would sometimes
  get a method missing error. I never figured out exactly why, but it was
  somehow related to passing the usual three arguments internally, where the
  last two would be ignored in this case. Now, the code checks the arity and
  only passes the join point in this case.

#19321: I removed some of the wasted object creation and initialization in
  advice invocation,
improving the overhead by about 40%. However, it is still at least 10x higher
  than simple method aliasing, so I want to make more improvements. (I did not
  close this item.)

#13403: I added new options :types_and_nested_types and :types_and_nested that
  are analogous to the similar "ancestors" and "descendents" options. The
  nested option will return the specified types and any types they "enclose".
  There are also corresponding "exclude" options.

#13406: I've decided not to do this, as it really isn't the "simplest thing
  that could possibly work." It's easy enough for the user to define a module
  of new behavior and just use "obj.extend(module)". However, when the user
  needs to do this over a set of types, Aquarium's TypeFinder can be helpful,
  so I added an example to the Examples code and page.

#18537: I've provided an example of the design approach where you define
  pointcuts in a class, as a kind of "aspect interface" and write aspects that
  specify those pointcuts. The problem has been that you had to name every
  single such pointcut explicitly. There was no "finder" option, as for types,
  methods, etc. Now there is a pointcut finder option with a new option
  ":named_pointcuts" for Aspect.new to specify a search for pointcuts in a set
  of types matching a name specification. Either constants or class variables
  will be matched (or both).

#19666: The rdoc for the key classes was cleaned up so it "renders" better.
  Feedback is welcome.

#19119: I finished the previously-incomplete support for allowing advice to
  change the raised exception, in both after and after_raising advice. A
  common scenario is to wrap the thrown exception in another. For example, a
  low-level, service-specific exception (like a database error) in a
  higher-level, more generic application exception.

You still can't rescue the exception completely in :after_raising and :after
advice; the value for the exception in
  joinpoint.context.raised_exception
when the advice returns will be raised by Aquarium. I think that permitting
:after_raising or :after advice to "eat" the exception could cause subtle
issues with scope and variable binding. It would also probably violate the
"principle of least surprise"; the advice code that rescues the exception would
not be as "obvious" to the reader as the familiar idiom of rescue clauses
that we are accustomed to using. Therefore, if you want to recover completely
from an exception, use rescue clauses in around advice.

== Version 0.4.1

V0.4.1 adds a few bug fixes, a few more user examples, internal refactoring and
some performance improvements.

Bug fixes:
19116	When an exception is thrown during advice execution, the error message
  always reports the advice type is :before!
19261	after_raising DSL method provides no way to specify exceptions

Enhancements:
18705	Remove duplication and complexity in options-handling code
19320	Move the Aquarium::...::AspectDSL file to Aquarium::DSL for convenience
19399	Improve the Design by Contract example

I added a new :exceptions argument (synonym :exception) that takes a single
exception or list thereof. You can only use this argument with :after_raising.
If you specify exceptions with the latter and use the :exceptions argument,
the values will be merged.

I thought it was ugly to have to type "include
Aquarium::Aspects::DSL::AspectDSL", so I moved the code so now it's "include
Aquarium::DSL". However, for backwards compatibility, the old module still
works.

== Version 0.4.0

V0.4.0 adds specs to characterize and test advising Java classes when running
on JRuby and adds several API enhancements.

Bug fixes:
17844	JRuby - Advising types, Aquarium thinks the type is a string
17883	Workaround for JRUBY-2089
18090	JoinPoint#invoke_original_join_point only works with :around advice

Enhancements:
17834	Allow :class and :module (and variants) wherever :type is allowed
17881	Add specs that exercise advising Java types and objects using JRuby

#17844 occurred because of the way JRuby encodes Java packages into modules.
  Aquarium now properly handles JRuby types.

#17883 reflected a JRuby bug, so a workaround was required.

#17834 allows the user to substitute the words "class", "classes", "module" or
"modules" anywhere the words "type" and "types" are used in the API, since some
users might naturally want to write aspects like this:

 	around :calls_to => :my_method, :in_class => MyClass do ...; end

However, there is no enforcement to ensure that "class" is only used for
classes and "module" is only used for modules, etc. Note: it's possible we'll
enforce this in some future release, as a way of saying things like "only advise
classes that match ...", etc. Caveat Emptor!

For #18090, a bug prevented JoinPoint#invoke_original_join_point (which allows
you to bypass all advices at the join point) from working except for :around
advice (and yes, the specs didn't cover this adequately - gasp!). Now fixed.

For #17881, I created a separate set of specs for JRuby, so it's easier to run
the "regular" Aquarium specs using MRI and the JRuby-specific specs separately
with JRuby. The new "jruby" directory contains a Rakefile, another set of specs,
and Java example code for the specs to use. The default Rakefile task re-runs
the main Aquarium spec suite using JRuby, to confirm that the suite passes
successfully, then it runs a set of different specs that load sample Java
interfaces and classes into JRuby and then advises them with Aquarium.

I found a few JRuby bugs and other behavior differences between MRI during this
release. I was able to handle them with modifications to the Aquarium code. If
you "grep" the Aquarium "lib" and "spec" directories for the word "jruby"
(ignoring case), you'll find notes about these issues and the workarounds I
implemented.

The separate JRuby spec suite shows what you can and cannot do with Java types.
As a side benefit, it also demonstrates how Java types, objects, and methods
are mapped to Ruby. There are some important limitations, however. See the
jruby.html page on the website or the README for more details.

Note: JRuby 1.1RC2 was used.

== Version 0.3.1

V0.3.1 adds numerous performance improvements, especially in the RSpec suite,
and some minor API additions.

Bug fixes:
N.A.

Enhancements:
14447	Unify internal handling of reporting errors to the user
17514	Provide an Aquarium library-wide logger with configuration parameters and
  instance overrides
17515	Add an optional warning if an aspect doesn't match any join points
17516	Remove unnecessary examples that use :types_and_descendents to shorten
  time to run the RSpec suite
17565	JoinPoint.new should convert a type name, symbol, or regex to the type
  and only allow one type

These first two enhancements are related. There is a now an
Aquarium::Utils::DefaultLogger module with static accessors for getting and
setting the "system-wide" logger.

When instance-level overrides are necessary, the Aquarium::Utils::OptionsUtils
provides "universal" options (but currently used only by Aspect and Pointcut)
for specifying a logger (with the new :logger parameter), or alternatively,
specifying just the output stream (:logger_stream) and/or the severity
(:severity, one of the standard library's Logger::Severity-defined constants).
If either of the latter two options is specified, a separate logger instance is
created, rather than changing parameters for the global logger.

OptionsUtils also supports a :noop parameter, which classes interpret to mean
do none (or perhaps only some) of the processing. Useful for debugging.

#17515 adds a helpful warning to the system (or aspect-instance's) logger if
  an aspect matches no join points. This warning will be suppressed if (i) the
  severity level for the logger is above WARN or (ii) the aspect was created
  with the option :ignore_no_matching_join_points => true.

#17516 fixes halved the long execution times for the whole RSpec suite by
refactoring some examples that used type finders with the :types_and_descendents
option unnecessarily. It is a very intensive computation! Note that I stubbed
out these calls using an aspect with around advise, a useful "development-time"
aspect. See Aquarium::TypeUtilsStub (in spec_example_types.rb) and how it's used
in pointcut_spec.rb. Using this technique and other optimizations, the time to
run the suite was reduced from ~5 minutes to about 1 minute.

#17565 fixes a "hole" in JoinPoint, where it doesn't confirm that a specified
type string, symbol or regex matches a class that exists and only one class. Now
it does and it stores the type, rather than the original "specification" for it.

== Version 0.3.0

V0.3.0 adds numerous improvements to the DSL, making aspect specification more
intuitive and English-like. For example, where you previously wrote, e.g.,

	around :methods => :all, :types => [Foo, Bar], :advice => advice_proc
	after  :attribute => name, :attribute_options => [:readers], :objects => [foo, bar] ...

Now you can write the same aspects as follows:

	around :calls_to => :all_methods, :within_types => [Foo, Bar], :use_advice => advice_proc
	after  :reading => name, :on_objects => [foo, bar] ...

Other improvements include performance and robustness enhancements and
miscellaneous internal refactoring and DRY improvements.

Bug fixes:
16267	gem not updating

Enhancements:
17154	More intuitive synonyms for specifying types, methods and attributes

For #17154, the following changes were made:
Added :all_methods as a synonym for the :all special value.
Added :reading as a synonym for :attributes => ..., :attribute_options =>
  [:readers]
Added :writing and :changing as synonyms for :attributes => ...,
  :attribute_options => [:writers]
Added :accessing as a synonym for :attributes => ...
Added :calls_to, :calling, :invoking, :sending_message_to  as synonyms for
  :methods.
Added :on_types, :in_types, :within_types and :for_types as synonyms for :types.
  The same set of prefixes is supported for :type, :objects, :object, and the
  various :exclude_*, :*_and_ancestors, and :*_and_descendents.

The full list of possible synonyms are shown in the spec examples. In
particular, see "pointcut_spec.rb".

== 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/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::DSL
	end

or, use (class|module)_eval:

	require 'aquarium/dsl/aspect_dsl'

	MyClass.class_eval do
		# Add the methods as _class_ methods
		include Aquarium::DSL
	end

To add the methods as _instance_ methods on individual objects:

	object = MyClass.new
	object.extend(Aquarium::DSL)


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.

V0.7.3
  • gem install aquarium
  • gem update aquarium

Menu

Other Links