NAME
   Aspect - Aspect-Oriented Programming (AOP) for Perl

SYNOPSIS
     package Person;

 sub create {
         # ...
     }

 sub set_name {
         # ...
     }

 sub get_address {
         # ...
     }

 package main;

 use Aspect;

 ### USING REUSABLE ASPECTS

 # There can only be one.
     aspect Singleton => 'Person::create';

 # Profile all setters to find any slow ones
     aspect Profiler => call qr/^Person::set_/;

 ### WRITING YOUR OWN ADVICE

 # Defines a collection of events
     my $pointcut = call qr/^Person::[gs]et_/;

 # Advice will live as long as $before is in scope
     my $before = before {
         print "g/set will soon be next";
     } $pointcut;

 # Advice will live forever, because it is created in void context
     after {
         print "g/set has just been called";
     } $pointcut;

 # Advice runs conditionally based on multiple factors
     before {
         print "get will be called next, and we are within Tester::run_tests";
     } call qr/^Person::get_/
     & cflow tester => 'Tester::run_tests';

 # Complex condition hijack of a method if some condition is true
     around {
         if ( $_->self->customer_name eq 'Adam Kennedy' ) {
             # Ensure I always have cash
             $_->return_value('One meeeelion dollars');
         } else {
             # Take a dollar off everyone else
             $_->proceed;
             $_->return_value( $_->return_value - 1 );
         }
     } call 'Bank::Account::balance';

DESCRIPTION
   Aspect-Oriented Programming (AOP) is a programming method developed by
   Xerox PARC and others. The basic idea is that in complex class systems
   there are certain aspects or behaviors that cannot normally be expressed
   in a coherent, concise and precise way. One example of such aspects are
   design patterns, which combine various kinds of classes to produce a
   common type of behavior. Another is logging. See <http://www.aosd.net>
   for more info.

   The Perl "Aspect" module closely follows the terminology of the AspectJ
   project (<http://eclipse.org/aspectj>). However due to the dynamic
   nature of the Perl language, several "AspectJ" features are useless for
   us: exception softening, mixin support, out-of-class method
   declarations, and others.

   The Perl "Aspect" module is focused on subroutine matching and wrapping.
   It allows you to select collections of subroutines using a flexible
   pointcut language, and modify their behavior in any way you want.

 Terminology
   Join Point
       An event that occurs during the running of a program. Currently only
       calls to subroutines are recognized as join points.

   Pointcut
       An expression that selects a collection of join points. For example:
       all calls to the class "Person", that are in the call flow of some
       "Company", but *not* in the call flow of "Company::make_report".
       "Aspect" supports "call()", and "cflow()" pointcuts, and logical
       operators ("&", "|", "!") for constructing more complex pointcuts.
       See the Aspect::Pointcut documentation.

   Advice
       A pointcut, with code that will run when it matches. The code can be
       run before or after the matched sub is run.

   Advice Code
       The code that is run before or after a pointcut is matched. It can
       modify the way that the matched sub is run, and the value it
       returns.

   Weave
       The installation of advice code on subs that match a pointcut.
       Weaving happens when you create the advice. Unweaving happens when
       the advice goes out of scope.

   The Aspect
       An object that installs advice. A way to package advice and other
       Perl code, so that it is reusable.

 Features
   *   Create and remove pointcuts, advice, and aspects.

   *   Flexible pointcut language: select subs to match using string
       equality, regexp, or "CODE" ref. Match currently running sub, or a
       sub in the call flow. Build pointcuts composed of a logical
       expression of other pointcuts, using conjunction, disjunction, and
       negation.

   *   In advice code, you can: modify parameter list for matched sub,
       modify return value, decide if to proceed to matched sub, access
       "CODE" ref for matched sub, and access the context of any call flow
       pointcuts that were matched, if they exist.

   *   Add/remove advice and entire aspects during run-time. Scope of
       advice and aspect objects, is the scope of their effect.

   *   A reusable aspect library. The Wormhole, aspect, for example. A base
       class makes it easy to create your own reusable aspects. The Memoize
       aspect is an example of how to interface with AOP-like modules from
       CPAN.

 Why create this module?
   Perl is a highly dynamic language, where everything this module does can
   be done without too much difficulty. All this module does, is make it
   even easier, and bring these features under one consistent interface. I
   have found it useful in my work in several places:

   *   Saves me from typing an entire line of code for almost every
       "Test::Class" test method, because I use the TestClass aspect.

   *   I use the Wormhole aspect, so that my methods can acquire implicit
       context, and so I don't need to pass too many parameters all over
       the place. Sure I could do it with "caller()" and "Hook::LexWrap",
       but this is much easier.

   *   Using custom advice to modify class behavior: register objects when
       constructors are called, save object state on changes to it, etc.
       All this, while cleanly separating these concerns from the effected
       class. They exist as an independent aspect, so the class remains
       unpolluted.

   The "Aspect" module is different from "Hook::Lexwrap" (which it uses for
   the actual wrapping) in two respects:

   *   Select join points using flexible pointcut language instead of the
       sub name. For example: select all calls to "Account" objects that
       are in the call flow of "Company::make_report".

   *   More options when writing the advice code. You can, for example, run
       the original sub, or append parameters to it.

 Using Aspect.pm
   This package is a facade on top of the Perl AOP framework. It allows you
   to create pointcuts, advice, and aspects in a simple declarative
   fastion.

   You will be mostly working with this package ("Aspect"), and the advice
   context package.

   When you "use Aspect;" you will import a family of around a dozen
   functions. These are all factories that allow you to create pointcuts,
   advice, and aspects.

 Pointcuts
   Pointcuts select join points, so that an advice can run code when they
   happen. The most common pointcut you will probably use is "call()". For
   example:

     $p = call 'Person::get_address';

   This selects the calling of "Person::get_address()" as defined in the
   symbol table during weave-time. The string is a pointcut spec, and can
   be expressed in three ways:

   "string"
       Select only the sub whose name is equal to the spec string.

   "regexp"
       Select only the subs whose name matches the regexp. The following
       will match all the subs defined on the "Person" class, but not on
       the "Person::Address" class.

         $p = call qr/^Person::\w+$/;

   "CODE" ref
       Select only subs, where the supplied code, when run with the sub
       name as only parameter, returns true. The following will match all
       calls to subs whose name isa key in the hash %subs_to_match:

         $p = call sub { exists $subs_to_match{shift()} }

   Pointcuts can be combined to form logical expressions, because they
   overload "&", "|", and "!", with factories that create composite
   pointcut objects. Be careful not to use the non-overloadable "&&", and
   "||" operators, because you will get no error message.

   Select all calls to "Person", which are not calls to the constructor:

     $p = call qr/^Person::\w+$/ & ! call 'Person::create';

   The second pointcut you can use, is "cflow()". It selects only the subs
   that are in call flow of its spec. Here we select all calls to "Person",
   only if they are in the call flow of some method in "Company":

     $p = call qr/^Person::\w+$/ & cflow company => qr/^Company::\w+$/;

   The "cflow()" pointcut takes two parameters: a context key, and a
   pointcut spec. The context key is used in advice code to access the
   context (params, sub name, etc.) of the sub found in the call flow. In
   the example above, the key can be used to access the name of the
   specific sub on "Company" that was found in the call flow of the
   "Person" method.The second parameter is a pointcut spec, that should
   match the sub required from the call flow.

   See the Aspect::Pointcut docs for more info.

 Advice
   An advice definition is just some code that will run on a match of some
   pointcut. The "advice" can run around the entire call to allow lexical
   variables to capture custom information on the way into the function
   that will be needed when it exists, or it can be more specific and only
   run before the sub, after the sub runs and returns, after the sub throws
   an exception, or after the sub runs regardless of the result.

   Using a more specific advice type will allow the optimiser to generate
   smaller and faster hooks into your code.

   You create advice using "around", "before", "after_returning",
   "after_throwing" or "after()".

   These take a "CODE" ref, and a pointcut, and install the code on the
   subs that match the pointcut. For example:

     after {
         print "Person::get_address has returned!\n";
     } call 'Person::get_address';

   The advice code is run with one parameter: the advice context. You use
   it to learn how the matched sub was run, modify parameters, return
   value, and if it is run at all.

   When the advice is created in void context, it remains enabled until the
   interpreter dies, or the symbol table reloaded.

   However, advice code can also be applied to matching pointcuts (i.e. the
   advice is enabled) for only a specific scope by declare it in scalar
   context and storing the returned guard object.

   This allows you to neatly control enabling and disabling of advice:

     SCOPE: {
        my $advice = before { print "called!\n" } $pointcut;

    # Do something while the device is enabled
     }

 # The advice is now disabled

   Please note that due to the internal mechanism used to achieve this
   lexical scoping, you may see a slight loss of memory and a slight slow
   down of the function, even after the advice has gone out of scope.

   Lexically creating and removing advice many times is recommended
   against, and doing so hundreds or thousands of times may result in
   significant memory consumption of performance loss for the functions
   matched by your pointcut.

 Aspects
   Aspects are just plain old Perl objects, that install advice, and do
   other AOP-like things, like install methods on other classes, or mess
   around with the inheritance hierarchy of other classes. A good base
   class for them is Aspect::Modular, but you can use any Perl object as
   long as the class inherits from Aspect::Library.

   If the aspect class exists immediately below the namespace
   "Aspect::Library", then it can be easily created with the following
   shortcut.

     aspect Singleton => 'Company::create';

   This will create an Aspect::Library::Singleton object. This reusable
   aspect is included in the "Aspect" distribution, and forces singleton
   behavior on some constructor, in this case, "Company::create()".

   Such aspects share a similar behaviour to advice. If enabled in void
   context they will be installed permanently, but if called in scalar
   context they will return a guard object that allows the aspect to be
   enabled only until the end of the current scope.

 Internals
   Due to the dynamic nature of Perl, there is no need for processing of
   source or byte code, as required in the Java and .NET worlds.

   The implementation is very simple: when you create advice, its pointcut
   is matched using "match_define()" to find every sub defined in the
   symbol table that might match against the pointcut (potentially subject
   to further runtime conditions).

   Those that match, will get a special wrapper installed. The wrapper only
   executes if, during run-time, a compiled context test for the pointcut
   returns true.

   The wrapper code creates an advice context, and gives it to the advice
   code.

   Some pointcuts like "call()" are static, so the compiled run-time
   function always returns true, and "match_define()" returns true if the
   sub name matches the pointcut spec.

   Some pointcuts like "cflow()" are dynamic, so "match_define()" always
   returns true, but the compiled run-time function returns true only if
   some condition within the point is true.

   To make this process faster, when the advice is installed, the pointcut
   will not use itself directly for the compiled run-time function but will
   additionally generate a "curried" (optimised) version of itself.

   This curried version uses the fact that the run-time check will only be
   called if it matches the "call()" pointcut pattern, and so no "call()"
   pointcuts needed to be tested at run-time unless they are in deep and
   complex nested coolean logic. It also handles collapsing any boolean
   logic impacted by the safe removal of the "call()" pointcuts.

   If you use only "call()" pointcuts (alone or in boolean combinations)
   the currying results in a null test (the pointcut is optimised away
   entirely) and so the need to make a run-time point test will be removed
   altogether from the generated advice hooks, reducing call overheads
   significantly.

   If your pointcut does not have any static conditions (i.e. "call") then
   the wrapper code will need to be installed into every function on the
   symbol table. This is highly discouraged and liable to result in hooks
   on unusual functions and unwanted side effects.

FUNCTIONS
   TO BE COMPLETED

LIMITATIONS
 Inheritance Support
   Support for inheritance is lacking. Consider the following two classes:

     package Automobile;
     ...
     sub compute_mileage { ... }

 package Van;
     use base 'Automobile';

   And the following two advice:

     before { print "Automobile!\n" } call 'Automobile::compute_mileage';
     before { print "Van!\n"        } call 'Van::compute_mileage';

   Some join points one would expect to be matched by the call pointcuts
   above, do not:

     $automobile = Automobile->new;
     $van = Van->new;
     $automobile->compute_mileage; # Automobile!
     $van->compute_mileage;        # Automobile!, should also print Van!

   "Van!" will never be printed. This happens because "Aspect" installs
   advice code on symbol table entries. "Van::compute_mileage" does not
   have one, so nothing happens. Until this is solved, you have to do the
   thinking about inheritance yourself.

 Performance
   You may find it very easy to shoot yourself in the foot with this
   module. Consider this advice:

     # Do not do this!
     before {
         print $_->sub_name;
     } cflow company => 'MyApp::Company::make_report';

   The advice code will be installed on every sub loaded. The advice code
   will only run when in the specified call flow, which is the correct
   behavior, but it will be *installed* on every sub in the system. This
   can be slow. It happens because the "cflow()" pointcut matches *all*
   subs during weave-time. It matches the correct sub during run-time. The
   solution is to narrow the pointcut:

     # Much better
     before {
         print $_->sub_name;
     } call qr/^MyApp::/
     & cflow company => 'MyApp::Company::make_report';

TO DO
   There are a number of things that could be added, if people have an
   interest in contributing to the project.

Documentation
   * cookbook

   * tutorial

   * example of refactoring a useful CPAN module using aspects

 Pointcuts
   * new pointcuts: execution, cflowbelow, within, advice, calledby. Sure
   you can implement them today with Perl treachery, but it is too much
   work.

   * need a way to match subs with an attribute, attributes::get() will not
   work for some reason

   * isa() support for method pointcuts as Gaal Yahas suggested: match
   methods on class hierarchies without callbacks

   * Perl join points: phasic- BEGIN/INIT/CHECK/END

   * The previous items indicate a need for a real join point specification
   language

 Weaving
   * look into byte code manipulation with B:: modules- could be faster, no
   need to mess with caller, and could add many more pointcut types. All we
   need to do for sub pointcuts is add 2 gotos to selected subs.

   * a debug flag to print out subs that were matched on match_define

   * warnings when over 1000 methods wrapped

   * support more pulling (vs. pushing) of aspects into packages:
   attributes, package specific join points

   * add whatever constructs required for mocking packages, objects,
   builtins

   * allow finer control of advice execution order

 Reusable Aspects
   * need better example for wormhole- something less tedius

   * use Scalar-Footnote for adding aspect state to objects, e.g. in
   Listenable. Problem is it is still in developer release state

   * Listenable: when listeners go out of scope, they should be removed
   from listenables, so you don't have to remember to remove them manually

   * Listenable: should overload some operator on listenables so that it is
   easier to add/remove listeners, e.g.: $button += (click => sub { print
   'click!' });

   * design aspects: DBC, threading, more GOF patterns

   * middleware aspects: security, load balancing, timeout/retry,
   distribution

   * Perl aspects: add use strict/warning/Carp to all matched packages.
   Actually, Spiffy, Toolkit, and Toolset do this already very nicely.

   * interface with existing Perl modules for logging, tracing, param
   checking, generally all things that are AOPish on CPAN. One should be
   able to use it all through one consistent interface. If I have a good
   set of pointcuts, I should be able to do all kinds of cross- cutting
   things with them.

   * UnderscoreContext aspect: subs that match will, if called with no
   parameters, get $_, and if in void context, return value will set $_.
   Allows you to use your subs like builtins, that fall back on $_. So if
   we have a sub:

        sub replace_foo { my $in = shift; $in =~ s/foo/bar; $in }

     Then both calls would be equivalent:

        $_ = replace_foo($_);
        replace_foo;

   * a generic FriendParamAppender aspect, that adds to a param list for
   affected methods, any object the method requires. Heuristics are applied
   to find the friend: maybe it is available in the call flow? Perhaps
   someone in the call flow has an accessor that can get it? Maybe a
   lexical in some sub in the call flow has it? The point is to cover all
   cases where we pass objects around, so that we don't have to. A
   generalization of the wormhole aspect.

SUPPORT
   Please report any bugs or feature requests through the web interface at
   <http://rt.cpan.org/Public/Dist/Display.html?Name=Aspect>.

INSTALLATION
   See perlmodinstall for information and options on installing Perl
   modules.

AVAILABILITY
   The latest version of this module is available from the Comprehensive
   Perl Archive Network (CPAN). Visit <http://www.perl.com/CPAN/> to find a
   CPAN site near you. Or see <http://search.cpan.org/perldoc?Aspsect.pm>.

AUTHORS
   Adam Kennedy <[email protected]>

   Marcel Gr�nauer <[email protected]>

   Ran Eilam <[email protected]>

SEE ALSO
   You can find AOP examples in the "examples/" directory of the
   distribution.

   Aspect::Library::Memoize

   Aspect::Library::Profiler

   Aspect::Library::Trace

COPYRIGHT
   Copyright 2001 by Marcel Gr�nauer

   Some parts copyright 2009 - 2010 Adam Kennedy.

   This library is free software; you can redistribute it and/or modify it
   under the same terms as Perl itself.