Overview of Aquarium
Agile Freaks took over ownership and maintenance of Aquarium, May 2021.
Aquarium is a framework that implements Aspect-Oriented Programming (AOP) for Ruby. The premise of AOP is that some concerns in an application will cut across the natural object boundaries of the problem domain. Rather than scatter duplicated code in each object to handle the cross-cutting concern, AOP modularizes the specification of which execution points are affected (called join points) and the actions that should be invoked at those points.
For example, persistence of model objects is a cross-cutting concern, in the sense that the desired persistence approach (database, flat files, replication, etc.) is independent of the domain logic represented by the model. So, why should the model code have any persistence logic? Instead, capture the details of mapping the domain to the persistence approach in separate components and programmatically or declaratively modify the model objects to synchronize state changes with the persistent memory of the state.
News
- V0.7.3 (May 9, 2021): Agile Freaks takes over ownership and maintenance of Aquarium.
- V0.7.3 (May 20, 2020): Supports for Ruby 2.7.0. Removed problematic monkey patching. (0.7.2 had doc errors.)
- V0.7.1 (April 23, 2019): Supports for Ruby 2.6.3 and JRuby 9.2.7.0. New hosting location for the documentation.
- V0.6.0 (October 31, 2013): Support for Ruby 2.0.0 and eliminates a known thread-safety issue.
- V0.5.1 (May 1, 2012): Now supports Ruby 1.9.3 and JRuby 1.6.7.
- V0.4.4 (Oct. 4, 2009): Moved the source repository from RubyForge SVN to GitHub. Upgraded to latest JRuby, RSpec, and Webgen.
- V0.4.0: Preliminary support for advising Java classes in JRuby! See the discussion on the [JRuby page].
See also the Aquarium on RubyGems.
Links
How to Use Aquarium
Aquarium provides a Domain Specific Language (DSL) with which you can express "aspectual" system behaviour in a modular way, i.e. using a succinct language and without repeating yourself all over your code base!
Imagine you want to trace all invocations of the public, instance methods in all classes whose names end with "Service". Here's how you can implement that behavior in Aquarium:
1class ServiceTracer 2 include Aquarium::DSL 3 # jp => the current "join point" 4 before :calls_to => :all_methods, :in_types => /Service$/ do |jp, object, *args| 5 names = "#{jp.target_type.name}##{jp.method_name}" 6 log "Entering: #{names}: object = #{object}, args = #{args}" 7 end 8 after :calls_to => :all_methods, :in_types => /Service$/ do |jp, object, *args| 9 names = "#{jp.target_type.name}##{jp.method_name}" 10 log "Leaving: #{names}: object = #{object}, args = #{args}" 11 end 12end
The #before
advice adds behavior that is invoked before each method is invoked, in this case, it logs a message with the name of the executing class and method, followed by the list of arguments passed to the method.
The #after
advice adds similar behavior the is invoked after each method is invoked.
A more succinct implementation of this behavior uses #around
advice:
1class ServiceTracer 2 include Aquarium::DSL 3 around :calls_to => :all_methods, :in_types => /Service$/ do |jp, object, *args| 4 names = "#{jp.target_type.name}##{jp.method_name}" 5 log "Entering: #{names}: object = #{object}, args = #{args}" 6 result = join_point.proceed 7 log "Leaving: #{names}: object = #{object}, args = #{args}" 8 result # block needs to return the result of the "proceed"! 9 end 10end
The special method #proceed
invokes the advised method, passing it the args list (by default). For #around
advice, you must call #proceed
unless you specifically don't want the original method called!
See the Examples and the API Overview section for more details.
Start Here
Install (or upgrade):
$ gem install aquarium $ gem upgrade aquarium