File Coverage

blib/lib/Aspect.pm
Criterion Covered Total %
statement 116 121 95.8
branch 3 8 37.5
condition n/a
subroutine 44 45 97.7
pod 13 15 86.6
total 176 189 93.1


line stmt bran cond sub pod time code
1             package Aspect;
2              
3             =pod
4              
5             =head1 NAME
6              
7             Aspect - Aspect-Oriented Programming (AOP) for Perl
8              
9             =head1 SYNOPSIS
10              
11             use Aspect;
12            
13            
14            
15             # Run some code "Advice" before a particular function
16             before {
17             print "About to call create\n";
18             } call 'Person::create';
19            
20            
21            
22             # Run Advice after several methods and hijack their return values
23             after {
24             print "Called getter/setter " . $_->sub_name . "\n";
25             $_->return_value(undef);
26             } call qr/^Person::[gs]et_/;
27            
28            
29            
30             # Run Advice conditionally based on multiple factors
31             before {
32             print "Calling a get method in void context within Tester::run_tests";
33             } wantvoid
34             & ( call qr/^Person::get_/ & ! call 'Person::get_not_trapped' )
35             & cflow 'Tester::run_tests';
36            
37            
38            
39             # Context-aware runtime hijacking of a method if certain condition is true
40             around {
41             if ( $_->self->customer_name eq 'Adam Kennedy' ) {
42             # Ensure I always have cash
43             $_->return_value('One meeeelion dollars');
44             } else {
45             # Take a dollar off everyone else
46             $_->proceed;
47             $_->return_value( $_->return_value - 1 );
48             }
49             } call 'Bank::Account::balance';
50            
51            
52            
53             # Catch and handle unexpected exceptions in a function into a formal object
54             after {
55             $_->exception(
56             Exception::Unexpected->new($_->exception)
57             );
58             } throwing()
59             & ! throwing('Exception::Expected')
60             & ! throwing('Exception::Unexpected');
61            
62            
63            
64             # Run Advice only on the outmost of a recursive series of calls
65             around {
66             print "Starting recursive child search\n";
67             $_->proceed;
68             print "Finished recursive child search\n";
69             } call 'Person::find_child' & highest;
70            
71            
72            
73             # Run Advice only during the current lexical scope
74             SCOPE: {
75             my $hook = before {
76             print "About to call create\n";
77             } call 'Person::create';
78            
79             # Advice will run for this call
80             Person->create('Bob');
81             }
82            
83             # Advice won't run for this call
84             Person->create('Tom');
85            
86            
87            
88             # Use a pre-packaged collection "Aspect" of Advice rules to change a class
89             aspect Singleton => 'Foo::new';
90            
91            
92            
93             # Define debugger breakpoints with high precision and conditionality
94             aspect Breakpoint => call qr/^Foo::.+::Bar::when_/ & wantscalar & highest;
95            
96            
97            
98             =head1 DESCRIPTION
99              
100             =head2 What is Aspect-Oriented Programming?
101              
102             Aspect-Oriented Programming (AOP) allows you to modularise concerns that
103             would otherwise cut across many parts of a program and be problematic to
104             implement and maintain.
105              
106             One common example is logging, where many small fragments code are typically
107             spread throughout your entire codebase.
108              
109             Another example is the implementation of design patterns, which combine or
110             manipulate various kinds of classes in particular ways produce a known type of
111             higher order behavior.
112              
113             Because Aspect-Oritented Programming moves this scattered code into a single
114             place, another major benefit is conditional compilation.
115              
116             Features implemented via Aspects can be compiled in only in certain situations,
117             and because of this Aspects are useful when debugging or testing large complex
118             programs.
119              
120             Aspects can implement features necesary for correctness of programs such as
121             reactivity or synchronisation, and it can be used to add checking assertions
122             to your or other people's modules.
123              
124             If necesary (although not recommended) you can also do "Monkey Patching",
125             hijacking the functionality of some other module to act different when used in
126             your program than when other everywhere else.
127              
128             Aspects can be used to implement space or time optimisations. One popular use
129             case is to add caching to a module or function that does not natively implement
130             caching.
131              
132             See L for more info.
133              
134             =head2 About This Implementation
135              
136             The Perl B module tries to closely follow the terminology of the
137             Java AspectJ project wherever possible (L).
138              
139             However due to the dynamic nature of the Perl language, several C
140             features are useless for us: exception softening, mixin support, out-of-class
141             method declarations, annotations, and others.
142              
143             The Perl B module is focused on subroutine matching and wrapping.
144              
145             It allows you to select collections of subroutines and conditions using a
146             flexible pointcut language, and modify their behavior in any way you want.
147              
148             In this regard it provides a similar set of functionality to L,
149             but with much more precision and with much more control and maintainability
150             as the complexity of what you are doing increases.
151              
152             In addition, where the Java implementation of Aspect-Oriented Programming is
153             only able to integrate at compile time, the nature of Perl means that the
154             B module can weave in aspect code at run-time, and pointcuts can take
155             advantage of run-time information and Perl-specific features like closures.
156              
157             This allows the Perl implementation of Aspect-Oriented Programming to be
158             stateful and adaptive in a way that Java nroamlly cannot be.
159              
160             =head2 Terminology
161              
162             One of the more opaque aspects (no pun intended) of Aspect-Oriented programming
163             is that it has an entire unique set of terms that can be confusing for people
164             learning to use the B module.
165              
166             In this section, we will attempt to define all the major terms in a way that
167             will hopefully make sense to Perl programmers.
168              
169             =head3 What is an Aspect?
170              
171             An I is a modular unit of cross-cutting implementation, consisting of
172             "Advice" on "Pointcuts" (we'll define those two shortly, don't worry if they
173             don't make sense for now).
174              
175             In Perl, this would typically mean a package or module containing declarations
176             of where to inject code, the code to run at these points, and any variables or
177             support functions needed by the injected functionality.
178              
179             The most critical point here is that the Aspect represents a collection of
180             many different injection points which collectively implement a single function
181             or feature and which should be enabled on an all or nothing basis.
182              
183             For example, you might implement the Aspect B as a module
184             which will inject hooks into a dozen different strategic places in your
185             program to watch for valid-but-suspicious values and report these values to
186             an external network server.
187              
188             Aspects can often written to be highly reusable, and be released via the CPAN.
189             When these generic aspects are written in the special namespace
190             L they can be called using the following special shorthand.
191              
192             use Aspect;
193            
194             # Load and enable the Aspect::Library::NYTProf aspect to constrain profiling
195             # to only the object constructors for each class in your program.
196             aspect NYTProf => call qr/^MyProgram\b.*::new$/;
197              
198             =head3 What is a Pointcut?
199              
200             A I is a well-defined location at a point in the execution of a
201             program at which Perl can inject functionality, in effect joining two different
202             bits of code together.
203              
204             In the Perl B implementation, this consists only of the execution of
205             named subroutines on the symbol table such as C.
206              
207             In other languages, additional join points can exist such as the instantiation
208             or destruction of an object or the static initialisation of a class.
209              
210             A I is a well-defined set of join points, and any conditions that
211             must be true when at these join points.
212              
213             Example include "All public methods in class C" or "Any non-recursive
214             call to the function C".
215              
216             We will discuss each of the available pointcut types later in this document.
217              
218             In addition to the default pointcut types it is possible to write your own
219             specialised pointcut types, although this is challenging due to the complex
220             API they follow to allow aggressive multi-pass optimisation.
221              
222             See L for more information.
223              
224             =head3 What is Advice?
225              
226             I is code designed to run automatically at all of the join points in
227             a particular pointcut. Advice comes in several types, instructing that the
228             code be run C, C or C (in place of) the different join
229             points in the pointcut.
230              
231             Advice code is introduced lexically to the target join points. That is, the
232             new functionality is injected in place to the existing program rather the
233             class being extended into some new version.
234              
235             For example, function C may not support caching
236             because it is unsafe to do so in the general case. But you know that in the
237             case of your program, the reasons it is unsafe in the general case don't apply.
238              
239             So for your program you might use the L aspect to
240             "Weave" Advice code into the C class which adds caching to the function
241             by integrating it with L.
242              
243             Each of the different advice types needs to be used slightly differently, and
244             are best employed for different types of jobs. We will discuss the use of each
245             of the different advice types later in this document.
246              
247             But in general, the more specific advice type you use, the more optimisation
248             can be applied to your advice declaration, and the less impact the advice will
249             have on the speed of your program.
250              
251             In addition to the default pointcut types, it is (theoretically) possible to
252             write your own specialised Advice types, although this would be extremely
253             difficult and probably involve some form of XS programming.
254              
255             For the brave, see L and the source for the different advice
256             classes for more information.
257              
258             =head3 What is Weaving?
259              
260             I is the installation of advice code to the subs that match a pointcut,
261             or might potentially match depending on certain run-time conditions.
262              
263             In the Perl B module, weaving happens on the declaration of each
264             advice block. Unweaving happens when a lexically-created advice variable goes
265             out of scope.
266              
267             Unfortunately, due to the nature of the mechanism B uses to hook into
268             function calls, unweaving can never be guarenteed to be round-trip clean.
269              
270             While the pointcut matching logic and advice code will never be run for unwoven
271             advice, it may be necesary to leave the underlying hooking artifact in place on
272             the join point indefinitely (imposing a small performance penalty and preventing
273             clean up of the relevant advice closure from memory).
274              
275             Programs that repeatedly weave and unweave during execution will thus gradually
276             slow down and leak memory, and so is discouraged despite being permitted.
277              
278             If advice needs to be repeatedly enabled and disabled you should instead
279             consider using the C pointcut and a variable in the aspect package or
280             a closure to introduce a remote "on/off" switch for the aspect.
281              
282             into the advice code.
283              
284             package My::Aspect;
285            
286             my $switch = 1;
287            
288             before {
289             print "Calling Foo::bar\n";
290             } call 'Foo::bar' & true { $switch };
291            
292             sub enable {
293             $switch = 1;
294             }
295            
296             sub disable {
297             $switch = 0;
298             }
299            
300             1;
301              
302             Under the covers weaving is done using a mechanism that is very similar to
303             the venerable L, although in some areas B will try to
304             make use of faster mechanisms if it knows these are safe.
305              
306             =head2 Feature Summary
307              
308             =over
309              
310             =item *
311              
312             Create permanent pointcuts, advice, and aspects at compile time or run-time.
313              
314             =item *
315              
316             Flexible pointcut language: select subs to match using string equality,
317             regexp, or C ref. Match currently running sub, a sub in the call
318             flow, calls in particular void, scalar, or array contexts, or only the highest
319             call in a set of recursive calls.
320              
321             =item *
322              
323             Build pointcuts composed of a logical expression of other pointcuts,
324             using conjunction, disjunction, and negation.
325              
326             =item *
327              
328             In advice code, you can modify parameter list for matched sub, modify return
329             value, throw or supress exceptions, decide whether or not to proceed to matched
330             sub, access a C ref for matched sub, and access the context of any call
331             flow pointcuts that were matched, if they exist.
332              
333             =item *
334              
335             Add/remove advice and entire aspects lexically during run-time. The scope of
336             advice and aspect objects, is the scope of their effect (This does, however,
337             come with some caveats).
338              
339             =item *
340              
341             A basic library of reusable aspects. A base class makes it easy to create your
342             own reusable aspects. The L aspect is an
343             example of how to interface with AOP-like modules from CPAN.
344              
345             =back
346              
347             =head2 Using Aspect.pm
348              
349             The B package allows you to create pointcuts, advice, and aspects in a
350             simple declarative fashion. This declarative form is a simple facade on top of
351             the Perl AOP framework, which you can also use directly if you need the
352             increased level of control or you feel the declarative form is not clear enough.
353              
354             For example, the following two examples are equivalent.
355              
356             use Aspect;
357            
358             # Declarative advice creation
359             before {
360             print "Calling " . $_->sub_name . "\n";
361             } call 'Function::one'
362             | call 'Function::two';
363            
364             # Longhand advice creation
365             Aspect::Advice::Before->new(
366             Aspect::Pointcut::Or->new(
367             Aspect::Pointcut::Call->new('Function::one'),
368             Aspect::Pointcut::Call->new('Function::two'),
369             ),
370             sub {
371             print "Calling " . $_->sub_name . "\n";
372             },
373             );
374              
375             You will be mostly working with this package (B) and the
376             L package, which provides the methods for getting information
377             about the call to the join point within advice code.
378              
379             When you C you will import a family of around fifteen
380             functions. These are all factories that allow you to create pointcuts,
381             advice, and aspects.
382              
383             =head1 FUNCTIONS
384              
385             The following functions are exported by default (and are documented as such)
386             but are also available directly in Aspect:: namespace as well if needed.
387              
388             They are documented in order from the simplest and and most common pointcut
389             declarator to the highest level declarator for enabling complete aspect classes.
390              
391             =cut
392              
393 21     21   442549 use 5.008002;
  21         64  
394 21     21   99 use strict;
  21         29  
  21         460  
395 21     21   108 use warnings;
  21         33  
  21         644  
396              
397             # Added by eilara as hack around caller() core dump
398             # NOTE: Now we've switched to Sub::Uplevel can this be removed?
399             # -- ADAMK
400 21     21   10510 use Carp::Heavy ();
  21         2979  
  21         431  
401 21     21   107 use Carp ();
  21         33  
  21         410  
402 21     21   10817 use Params::Util 1.00 ();
  21         99355  
  21         668  
403 21     21   10964 use Sub::Install 0.92 ();
  21         33250  
  21         552  
404 21     21   7319 use Sub::Uplevel 0.2002 ();
  21         15962  
  21         500  
405 21     21   9728 use Aspect::Pointcut ();
  21         61  
  21         478  
406 21     21   130 use Aspect::Pointcut::Or ();
  21         29  
  21         288  
407 21     21   75 use Aspect::Pointcut::And ();
  21         27  
  21         256  
408 21     21   74 use Aspect::Pointcut::Not ();
  21         28  
  21         254  
409 21     21   8097 use Aspect::Pointcut::True ();
  21         36  
  21         375  
410 21     21   7696 use Aspect::Pointcut::Call ();
  21         34  
  21         431  
411 21     21   8343 use Aspect::Pointcut::Cflow ();
  21         49  
  21         425  
412 21     21   8337 use Aspect::Pointcut::Highest ();
  21         47  
  21         374  
413 21     21   7797 use Aspect::Pointcut::Throwing ();
  21         44  
  21         391  
414 21     21   98 use Aspect::Pointcut::Returning ();
  21         26  
  21         250  
415 21     21   7677 use Aspect::Pointcut::Wantarray ();
  21         43  
  21         433  
416 21     21   7305 use Aspect::Advice ();
  21         37  
  21         454  
417 21     21   7799 use Aspect::Advice::After ();
  21         37  
  21         367  
418 21     21   8503 use Aspect::Advice::Around ();
  21         42  
  21         355  
419 21     21   7887 use Aspect::Advice::Before ();
  21         43  
  21         350  
420 21     21   109 use Aspect::Point ();
  21         25  
  21         287  
421 21     21   78 use Aspect::Point::Static ();
  21         27  
  21         265  
422 21     21   75 use Aspect::Point::After ();
  21         22  
  21         246  
423 21     21   74 use Aspect::Point::Around ();
  21         23  
  21         236  
424 21     21   67 use Aspect::Point::Before ();
  21         24  
  21         17591  
425              
426             our $VERSION = '0.97_06';
427              
428             # Track the location of exported functions so that pointcuts
429             # can avoid accidentally binding them.
430             our %EXPORTED = ();
431              
432              
433              
434              
435              
436             ######################################################################
437             # Public (Exported) Functions
438              
439             =pod
440              
441             =head2 call
442              
443             my $single = call 'Person::get_address';
444             my $multiple = call qr/^Person::get_/;
445             my $complex = call sub { lc($_[0]) eq 'person::get_address' };
446             my $object = Aspect::Pointcut::Call->new('Person::get_address');
447              
448             The most common pointcut is C. All three of the examples will match the
449             calling of C as defined in the symbol table at the
450             time an advice is declared.
451              
452             The C declarator takes a single parameter which is the pointcut spec,
453             and can be provided in three different forms.
454              
455             B
456              
457             Select only the specific full resolved subroutine whose name is equal to the
458             specification string.
459              
460             For example C will only match the plain C method
461             and will not match the longer C method.
462              
463             B
464              
465             Select all subroutines whose name matches the regular expression.
466              
467             The following will match all the subs defined on the C class, but not
468             on the C or any other child classes.
469              
470             $p = call qr/^Person::\w+$/;
471              
472             B
473              
474             Select all subroutines where the supplied code returns true when passed a
475             full resolved subroutine name as the only parameter.
476              
477             The following will match all calls to subroutines whose names are a key in the
478             hash C<%subs_to_match>:
479              
480             $p = call sub {
481             exists $subs_to_match{$_[0]};
482             }
483              
484             For more information on the C pointcut see L.
485              
486             =cut
487              
488             sub call ($) {
489 138     138 1 62131 Aspect::Pointcut::Call->new(@_);
490             }
491              
492             =pod
493              
494             =head2 cflow
495              
496             before {
497             print "Called My::foo somewhere within My::bar\n";
498             } call 'My::foo'
499             & cflow 'My::bar';
500              
501             The C declarator is used to specify that the join point must be somewhere
502             within the control flow of the C function. That is, at the time
503             C is being called somewhere up the call stack is C.
504              
505             The parameters to C are identical to the parameters to C.
506              
507             Due to an idiosyncracy in the way C is implemented, they do not always
508             parse properly well when joined with an operator. In general, you should use
509             any C operator last in your pointcut specification, or use explicit
510             braces for it.
511              
512             # This works fine
513             my $x = call 'My::foo' & cflow 'My::bar';
514            
515             # This will error
516             my $y = cflow 'My::bar' & call 'My::foo';
517            
518             # Use explicit braces if you can't have the flow last
519             my $z = cflow('My::bar') & call 'My::foo';
520              
521             For more information on the C pointcut, see L.
522              
523             =cut
524              
525             sub cflow ($;$) {
526 7     7 1 49 Aspect::Pointcut::Cflow->new(@_);
527             }
528              
529             =pod
530              
531             =head2 wantlist
532              
533             my $pointcut = call 'Foo::bar' & wantlist;
534              
535             The C pointcut traps a condition based on Perl C context,
536             when a function is called in list context. When used with C, this
537             pointcut can be used to trap list-context calls to one or more functions, while
538             letting void or scalar context calls continue as normal.
539              
540             For more information on the C pointcut see
541             L.
542              
543             =cut
544              
545             sub wantlist () {
546 13     13 1 78 Aspect::Pointcut::Wantarray->new(1);
547             }
548              
549             =pod
550              
551             =head2 wantscalar
552              
553             my $pointcut = call 'Foo::bar' & wantscalar;
554              
555             The C pointcut traps a condition based on Perl C context,
556             when a function is called in scalar context. When used with C, this
557             pointcut can be used to trap scalar-context calls to one or more functions,
558             while letting void or list context calls continue as normal.
559              
560             For more information on the C pointcut see
561             L.
562              
563             =cut
564              
565             sub wantscalar () {
566 10     10 1 55 Aspect::Pointcut::Wantarray->new('');
567             }
568              
569             =pod
570              
571             =head2 wantvoid
572              
573             my $bug = call 'Foo::get_value' & wantvoid;
574              
575             The C pointcut traps a condition based on Perl C context,
576             when a function is called in void context. When used with C, this pointcut
577             can be used to trap void-context calls to one or more functions, while letting
578             scalar or list context calls continue as normal.
579              
580             This is particularly useful for methods which make no sense to call in void
581             context, such as getters or other methods calculating and returning a useful
582             result.
583              
584             For more information on the C pointcut see
585             L.
586              
587             =cut
588              
589             sub wantvoid () {
590 9     9 1 56 Aspect::Pointcut::Wantarray->new(undef);
591             }
592              
593             =pod
594              
595             =head2 highest
596              
597             my $entry = call 'Foo::recurse' & highest;
598              
599             The C pointcut is used to trap the first time a particular function
600             is encountered, while ignoring any subsequent recursive calls into the same
601             pointcut.
602              
603             It is unusual in that unlike all other types of pointcuts it is stateful, and
604             so some detailed explaination is needed to understand how it will behave.
605              
606             Pointcut declarators follow normal Perl precedence and shortcutting in the same
607             way that a typical set of C might do for regular code.
608              
609             When the C is evaluated for the first time it returns true and a
610             counter is to track the depth of the call stack. This counter is bound to the
611             join point itself, and will decrement back again once we exit the advice code.
612              
613             If we encounter another function that is potentially contained in the same
614             pointcut, then C will always return false.
615              
616             In this manner, you can trigger functionality to run only at the outermost
617             call into a recursive series of functions, or you can negate the pointcut
618             with C and look for recursive calls into a function when there
619             shouldn't be any recursion.
620              
621             In the current implementation, the semantics and behaviour of pointcuts
622             containing multiple highest declarators is not defined (and the current
623             implementation is also not amenable to supporting it).
624              
625             For these reasons, the usage of multiple highest declarators such as in the
626             following example is not support, and so the following will throw an exception.
627              
628             before {
629             print "This advice will not compile\n";
630             } wantscalar & (
631             (call 'My::foo' & highest)
632             |
633             (call 'My::bar' & highest)
634             );
635              
636             This limitation may change in future releases. Feedback welcome.
637              
638             For more information on the C pointcut see
639             L.
640              
641             =cut
642              
643             sub highest () {
644 3     3 1 21 Aspect::Pointcut::Highest->new;
645             }
646              
647             =pod
648              
649             =head2 throwing
650              
651             my $string = throwing qr/does not exist/;
652             my $object = throwing 'Exception::Class';
653              
654             The C pointcut is used with the C (and C) to
655             restrict the pointcut so advice code is only fired for a specific die message
656             or a particular exception class (or subclass).
657              
658             The C declarator takes a single parameter which is the pointcut spec,
659             and can be provided in two different forms.
660              
661             B
662              
663             If a regular expression is passed to C it will be matched against
664             the exception if and only if the exception is a plain string.
665              
666             Thus, the regexp form can be used to trap unstructured errors emitted by C
667             or C while B trapping any formal exception objects of any kind.
668              
669             B
670              
671             If a string is passed to C it will be treated as a class name and
672             will be matched against the exception via an C method call if and only
673             if the exception is an object.
674              
675             Thus, the string form can be used to trap and handle specific types of
676             exceptions while allowing other types of exceptions or raw string errors to
677             pass through.
678              
679             For more information on the C pointcut see
680             L.
681              
682             =cut
683              
684             sub throwing (;$) {
685 0     0 1 0 Aspect::Pointcut::Throwing->new(@_);
686             }
687              
688             =pod
689              
690             =head2 returning
691              
692             after {
693             print "No exception\n";
694             } call 'Foo::bar' & returning;
695              
696             The C pointcut is used with C advice types to indicate the
697             join point should only occur when a function is returning B throwing
698             an exception.
699              
700             =cut
701              
702             sub returning () {
703 1     1 1 12 Aspect::Pointcut::Returning->new;
704             }
705              
706             =pod
707              
708             =head2 true
709              
710             # Intercept an adjustable random percentage of calls to a function
711             our $RATE = 0.01;
712            
713             before {
714             print "The few, the brave, the 1%\n";
715             } call 'My::foo'
716             & true {
717             rand() < $RATE
718             };
719              
720             Because of the lengths that B goes to internally to optimise the
721             selection and interception of calls, writing your own custom pointcuts can
722             be very difficult.
723              
724             When a custom or unusual pattern of interception is needed, often all that is
725             desired is to extend a relatively normal pointcut with an extra caveat.
726              
727             To allow for this scenario, B provides the C pointcut.
728              
729             This pointcut allows you to specify any arbitrary code to match on. This code
730             will be executed at run-time if the join point matches all previous conditions.
731              
732             The join point matches if the function or closure returns true, and does not
733             match if the code returns false or nothing at all.
734              
735             =cut
736              
737             sub true (&) {
738 1     1 1 13 Aspect::Pointcut::True->new(@_);
739             }
740              
741             =pod
742              
743             =head2 before
744              
745             before {
746             # Don't call the function, return instead
747             $_->return_value(1);
748             } call 'My::foo';
749              
750             The B advice declaration is used to defined advice code that will be
751             run instead of the code originally at the join points, but continuing on to the
752             real function if no action is taken to say otherwise.
753              
754             When called in void context, as shown above, C will install the advice
755             permanently into your program.
756              
757             When called in scalar context, as shown below, C will return a guard
758             object and enable the advice for as long as that guard object continues to
759             remain in scope or otherwise avoid being destroyed.
760              
761             SCOPE: {
762             my $guard = before {
763             print "Hello World!\n";
764             } call 'My::foo';
765            
766             # This will print
767             My::foo();
768             }
769            
770             # This will NOT print
771             My::foo();
772              
773             Because the end result of the code at the join points is irrelevant to this
774             type of advice and the Aspect system does not need to hang around and maintain
775             control during the join point, the underlying implementation is done in a way
776             that is by far the fastest and with the least impact (essentially none) on the
777             execution of your program.
778              
779             You are B encouraged to use C advice wherever possible for the
780             current implementation, resorting to the other advice types when you truly need
781             to be there are the end of the join point execution (or on both sides of it).
782              
783             For more information, see L.
784              
785             =cut
786              
787             sub before (&$) {
788 25     25 1 277 Aspect::Advice::Before->new(
789             lexical => defined wantarray,
790             code => $_[0],
791             pointcut => $_[1],
792             );
793             }
794              
795             =pod
796              
797             =head2 after
798              
799             # Confuse a program by bizarely swapping return values and exceptions
800             after {
801             if ( $_->exception ) {
802             $_->return_value($_->exception);
803             } else {
804             $_->exception($_->return_value);
805             }
806             } call 'My::foo' & wantscalar;
807              
808             The C declarator is used to create advice in which the advice code will
809             be run after the join point has run, regardless of whether the function return
810             correctly or throws an exception.
811              
812             This advice should be used when you need to deal flexibly with return values,
813             but might also want to handle exceptions. Use of this advice is relatively
814             rare, as most of the time you want something more flexible like C,
815             or something more specific like C or C.
816              
817             For more information, see L.
818              
819             =cut
820              
821             sub after (&$) {
822 24     24 1 256 Aspect::Advice::After->new(
823             lexical => defined wantarray,
824             code => $_[0],
825             pointcut => $_[1],
826             );
827             }
828              
829             sub after_returning (&$) {
830 18     18 0 197 Aspect::Advice::After->new(
831             lexical => defined wantarray,
832             code => $_[0],
833             pointcut => Aspect::Pointcut::And->new(
834             Aspect::Pointcut::Returning->new,
835             $_[1],
836             ),
837             );
838             }
839              
840             sub after_throwing (&$) {
841 16     16 0 125 Aspect::Advice::After->new(
842             lexical => defined wantarray,
843             code => $_[0],
844             pointcut => Aspect::Pointcut::And->new(
845             Aspect::Pointcut::Throwing->new,
846             $_[1],
847             ),
848             );
849             }
850              
851             =pod
852              
853             =head2 around
854              
855             # Trace execution time for a function
856             around {
857             my @start = Time::HiRes::gettimeofday();
858             $_->proceed;
859             my @stop = Time::HiRes::gettimeofday();
860            
861             my $elapsed = Time::HiRes::tv_interval( \@start, \@stop );
862             print "My::foo executed in $elapsed seconds\n";
863             } call 'My::foo';
864              
865             The C declarator is used to create the most general form of advice,
866             and can be used to implement the most high level functionality.
867              
868             It allows you to make changes to the calling parameters, to change the result
869             of the function, to subvert or prevent the calling altogether, and to do so
870             while storing extra lexical state of your own across the join point.
871              
872             For example, the code shown above tracks the time at which a single function
873             is called and returned, and then uses the two pieces of information to track
874             the execution time of the call.
875              
876             Similar functionality to the above is used to implement the CPAN modules
877             L and the more complex L.
878              
879             Within the C advice code, the C<$_-Eproceed> method is used to call
880             the original function with whatever the current parameter context is, storing
881             the result (whether return values or an exception) in the context as well.
882              
883             Alternatively, you can use the C method to get access to a reference
884             to the original function and call it directly without using context
885             parameters and without storing the function results.
886              
887             around {
888             $_->original->('alternative param');
889             $_->return_value('fake result');
890             } call 'My::foo';
891              
892             The above example calls the original function directly with an alternative
893             parameter in void context (regardless of the original C context)
894             ignoring any return values. It then sets an entirely made up return value of
895             it's own.
896              
897             Although it is the most powerful advice type, C is also the slowest
898             advice type with the highest memory cost per join point. Where possible, you
899             should try to use a more specific advice type.
900              
901             For more information, see L.
902              
903             =cut
904              
905             sub around (&$) {
906 25     25 1 290 Aspect::Advice::Around->new(
907             lexical => defined wantarray,
908             code => $_[0],
909             pointcut => $_[1],
910             );
911             }
912              
913             =pod
914              
915             =head2 aspect
916              
917             aspect Singleton => 'Foo::new';
918              
919             The C declarator is used to enable complete reusable aspects.
920              
921             The first parameter to C identifies the aspect library class. If the
922             parameter is a fully resolved class name (i.e. it contains double colons like
923             Foo::Bar) the value it will be used directly. If it is a simple C
924             without colons then it will be interpreted as C.
925              
926             If the aspect class is not loaded, it will be loaded for you and validated as
927             being a subclass of C.
928              
929             And further paramters will be passed on to the constructor for that class. See
930             the documentation for each class for more information on the appropriate
931             parameters for that class.
932              
933             As with each individual advice type complete aspects can be defined globally
934             by using C in void context, or lexically via a guard object by calling
935             C in scalar context.
936              
937             # Break on the topmost call to function for a limited time
938             SCOPE: {
939             my $break = aspect Breakpoint => call 'My::foo' & highest;
940            
941             do_something();
942             }
943              
944             For more information on writing reusable aspects, see L.
945              
946             =cut
947              
948             sub aspect {
949 7     7 1 914 my $class = _LIBRARY(shift);
950 7         785 return $class->new(
951             lexical => defined wantarray,
952             args => [ @_ ],
953             );
954             }
955              
956              
957              
958              
959              
960              
961             ######################################################################
962             # Import Logic
963              
964             sub import {
965 21     21   186 my $class = shift;
966 21         31 my $legacy = 0;
967 21         62 my $into = caller();
968 21         384 while ( @_ ) {
969 0         0 my $value = shift;
970 0 0       0 if ( $value eq ':legacy' ) {
971 0         0 $legacy = 1;
972             } else {
973 0         0 Carp::croak("Unknown or unsupported import param '$value'");
974             }
975             }
976              
977             # Install unchanged legacy functions
978 21         42 foreach ( qw{ aspect before call cflow } ) {
979 84         287 Sub::Install::install_sub( {
980             code => $_,
981             into => $into,
982             } );
983 84         4169 $EXPORTED{"${into}::$_"} = 1;
984             }
985              
986             # Install functions that change between API versions
987             Sub::Install::install_sub( {
988 21 50       122 code => $legacy ? 'after_returning' : 'after',
989             as => 'after',
990             into => $into,
991             } );
992 21         712 $EXPORTED{"${into}::after"} = 1;
993              
994 21 50       70 unless ( $legacy ) {
995             # Install new generation API functions
996 21         38 foreach ( qw{
997             around
998             throwing returning
999             wantlist wantscalar wantvoid
1000             true highest
1001             } ) {
1002 168         381 Sub::Install::install_sub( {
1003             code => $_,
1004             into => $into,
1005             } );
1006 168         5329 $EXPORTED{"${into}::$_"} = 1;
1007             }
1008             }
1009              
1010 21         36294 return 1;
1011             }
1012              
1013              
1014              
1015              
1016              
1017             ######################################################################
1018             # Private Functions
1019              
1020             # Run-time use call
1021             # NOTE: Do we REALLY need to do this as a use?
1022             # If the ->import method isn't important, change to native require.
1023             sub _LIBRARY {
1024 7     7   17 my $package = shift;
1025 7 50       198 if ( Params::Util::_IDENTIFIER($package) ) {
1026 7         109 $package = "Aspect::Library::$package";
1027             }
1028 7         152 Params::Util::_DRIVER($package, 'Aspect::Library');
1029             }
1030              
1031             1;
1032              
1033             =pod
1034              
1035             =head1 OPERATORS
1036              
1037             =head2 Pointcut &
1038              
1039             Overloading of bitwise C<&> for pointcut declarations allows a natural looking
1040             boolean "and" logic for pointcuts. When using the C<&> operator the combined
1041             pointcut expression will match if all pointcut subexpressions match.
1042              
1043             In the original Java AspectJ framework, the subexpressions are considered to
1044             be a union without an inherent order at all. In Perl you may treat them as
1045             ordered since they are ordered internally, but since all subexpressions run
1046             anyway you should probably not do anything that relies on this order. The
1047             optimiser may do interesting things with order in future, or we may move to an
1048             unordered implementation.
1049              
1050             For more information, see L.
1051              
1052             =head2 Pointcut |
1053              
1054             Overloading of bitwise C<|> for pointcut declarations allows a natural looking
1055             boolean "or" logic for pointcuts. When using the C<|> operator the combined
1056             pointcut expression will match if either pointcut subexpressions match.
1057              
1058             The subexpressions are ostensibly considered without any inherent order, and
1059             you should treat them that way when you can. However, they are internally
1060             ordered and shortcutting will be applied as per normal Perl expressions. So for
1061             speed reasons, you may with to put cheap pointcut declarators before expensive
1062             ones where you can.
1063              
1064             The optimiser may do interesting things with order in future, or we may move to
1065             an unordered implementation. So as a general rule, avoid things that require
1066             order while using order to optimise where you can.
1067              
1068             For more information, see L.
1069              
1070             =head2 Pointcut !
1071              
1072             Overload of negation C for pointcut declarations allows a natural looking
1073             boolean "not" logic for pointcuts. When using the C operator the resulting
1074             pointcut expression will match if the single subexpression does B match.
1075              
1076             For more information, see L.
1077              
1078             =head1 ADVICE CONTEXT METHODS
1079              
1080             The following methods are available in the advice code for one or more advice
1081             types. Different sets of methods are available for the different advice types.
1082              
1083             The actual objects involved are those within the L tree.
1084              
1085             =head2 type
1086              
1087             The C method is a convenience provided in the situation something has a
1088             L method and wants to know the advice declarator it is made for.
1089              
1090             Returns C<"before"> for L advice, C<"after"> for
1091             L advice, or C<"around"> for
1092             L advice.
1093              
1094             =head1 LIBRARY
1095              
1096             The main L distribution ships with the following set of libraries. These
1097             are not necesarily recommended or the best on offer. The are shipped with
1098             B for convenience, because they have no additional CPAN dependencies.
1099              
1100             Their purpose is summarised below, but see their own documentation for more
1101             information.
1102              
1103             =head2 Aspect::Library::Singleton
1104              
1105             L can be used to convert an existing class to
1106             function as a singleton and return the same object for every constructor call.
1107              
1108             =head2 Aspect::Library::Breakpoint
1109              
1110             L allows you to inject debugging breakpoints into
1111             a program using the full power and complexity of the C pointcuts.
1112              
1113             =head2 Aspect::Library::Wormhole
1114              
1115             L is a tool for passing objects down a call flow,
1116             without adding extra arguments to the frames between the source and the target,
1117             letting a function implicit context.
1118              
1119             =head2 Aspect::Library::Listenable
1120              
1121             L assysts in the implementation of the "Listenable"
1122             design pattern. It lets you define a function as emitting events that can be
1123             registed for by subscribers, and then add/remove subscribers for these events
1124             over time.
1125              
1126             When the functions that are listenable are called, registered subscribers will
1127             be notified. This lets you build a general event subscription system for your
1128             program. This could be as part of a plugin API or just for your own convenience.
1129              
1130             =head1 INTERNALS
1131              
1132             Due to the dynamic nature of Perl, there is no need for processing of source
1133             or byte code, as required in the Java and .NET worlds.
1134              
1135             The implementation is conceptually very simple: when you create advice, its
1136             pointcut is matched to find every sub defined in the symbol table that might
1137             match against the pointcut (potentially subject to further runtime conditions).
1138              
1139             Those that match, will get a special wrapper installed. The wrapper only
1140             executes if, during run-time, a compiled context test for the pointcut
1141             returns true.
1142              
1143             The wrapper code creates an advice context, and gives it to the advice code.
1144              
1145             Most of the complexity comes from the extensive optimisation that is used to
1146             reduce the impact of both weaving of the advice and the run-time costs of the
1147             wrappers added to your code.
1148              
1149             Some pointcuts like C are static and their full effect is known at
1150             weave time, so the compiled run-time function can be optimised away entirely.
1151              
1152             Some pointcuts like C are dynamic, so they are not used to select
1153             the functions to hook, but impose a run-time cost to determine whether or not
1154             they match.
1155              
1156             To make this process faster, when the advice is installed, the pointcut
1157             will not use itself directly for the compiled run-time function but will
1158             additionally generate a "curried" (optimised) version of itself.
1159              
1160             This curried version uses the fact that the run-time check will only be
1161             called if it matches the C pointcut pattern, and so no C
1162             pointcuts needed to be tested at run-time unless they are in deep and
1163             complex nested coolean logic. It also handles collapsing any boolean logic
1164             impacted by the safe removal of the C pointcuts.
1165              
1166             Further, where possible the pointcuts will be expressed as Perl source
1167             (including logic operators) and compiled into a single Perl expression. This
1168             not only massively reduces the number of functions to be called, but allows
1169             further optimisation of the pointcut by the opcode optimiser in perl itself.
1170              
1171             If you use only C pointcuts (alone or in boolean combinations)
1172             the currying results in a null test (the pointcut is optimised away
1173             entirely) and so the need to make a run-time point test will be removed
1174             altogether from the generated advice hooks, reducing call overheads
1175             significantly.
1176              
1177             If your pointcut does not have any static conditions (i.e. C) then
1178             the wrapper code will need to be installed into every function on the symbol
1179             table. This is highly discouraged and liable to result in hooks on unusual
1180             functions and unwanted side effects, potentially breaking your program.
1181              
1182             =head1 LIMITATIONS
1183              
1184             =head2 Inheritance Support
1185              
1186             Support for inheritance is lacking. Consider the following two classes:
1187              
1188             package Automobile;
1189            
1190             sub compute_mileage {
1191             # ...
1192             }
1193            
1194             package Van;
1195            
1196             use base 'Automobile';
1197              
1198             And the following two advice:
1199              
1200             before {
1201             print "Automobile!\n";
1202             } call 'Automobile::compute_mileage';
1203            
1204             before {
1205             print "Van!\n";
1206             } call 'Van::compute_mileage';
1207              
1208             Some join points one would expect to be matched by the call pointcuts
1209             above, do not:
1210              
1211             $automobile = Automobile->new;
1212             $van = Van->new;
1213             $automobile->compute_mileage; # Automobile!
1214             $van->compute_mileage; # Automobile!, should also print Van!
1215              
1216             C will never be printed. This happens because B installs
1217             advice code on symbol table entries. C does not
1218             have one, so nothing happens. Until this is solved, you have to do the
1219             thinking about inheritance yourself.
1220              
1221             =head2 Performance
1222              
1223             You may find it very easy to shoot yourself in the foot with this module.
1224             Consider this advice:
1225              
1226             # Do not do this!
1227             before {
1228             print $_->sub_name;
1229             } cflow 'MyApp::Company::make_report';
1230              
1231             The advice code will be installed on B sub loaded. The advice code
1232             will only run when in the specified call flow, which is the correct
1233             behavior, but it will be I on every sub in the system. This
1234             can be extremely slow because the run-time cost of checking C will
1235             occur on every single function called in your program.
1236              
1237             It happens because the C pointcut matches I subs during weave-time.
1238             It matches the correct sub during run-time. The solution is to narrow the
1239             pointcut:
1240              
1241             # Much better
1242             before {
1243             print $_->sub_name;
1244             } call qr/^MyApp::/
1245             & cflow 'MyApp::Company::make_report';
1246              
1247             =head1 TO DO
1248              
1249             There are a many things that could be added, if people have an interest
1250             in contributing to the project.
1251              
1252             =head2 Documentation
1253              
1254             * cookbook
1255              
1256             * tutorial
1257              
1258             * example of refactoring a useful CPAN module using aspects
1259              
1260             =head2 Pointcuts
1261              
1262             * New pointcuts: execution, cflowbelow, within, advice, calledby. Sure
1263             you can implement them today with Perl treachery, but it is too much
1264             work.
1265              
1266             * We need a way to match subs with an attribute, attributes::get()
1267             will currently not work.
1268              
1269             * isa() support for method pointcuts as Gaal Yahas suggested: match
1270             methods on class hierarchies without callbacks
1271              
1272             * Perl join points: phasic- BEGIN/INIT/CHECK/END
1273              
1274             =head2 Weaving
1275              
1276             * The current optimation has gone as far as it can, next we need to look into
1277             XS acceleration and byte code manipulation with B:: modules.
1278              
1279             * A debug flag to print out subs that were matched during weaving
1280              
1281             * Warnings when over 1000 methods wrapped
1282              
1283             * Allow finer control of advice execution order
1284              
1285             * Centralised hooking in wrappers so that each successive advice won't need
1286             to wrap around the previous one.
1287              
1288             * Allow lexical aspects to be safely removed completely, rather than being left
1289             in place and disabled as in the current implementation.
1290              
1291             =head1 SUPPORT
1292              
1293             Please report any bugs or feature requests through the web interface at
1294             L.
1295              
1296             =head1 INSTALLATION
1297              
1298             See L for information and options on installing Perl modules.
1299              
1300             =head1 AVAILABILITY
1301              
1302             The latest version of this module is available from the Comprehensive Perl
1303             Archive Network (CPAN). Visit to find a CPAN
1304             site near you. Or see L.
1305              
1306             =head1 AUTHORS
1307              
1308             Adam Kennedy Eadamk@cpan.orgE
1309              
1310             Marcel GrEnauer Emarcel@cpan.orgE
1311              
1312             Ran Eilam Eeilara@cpan.orgE
1313              
1314             =head1 SEE ALSO
1315              
1316             You can find AOP examples in the C directory of the
1317             distribution.
1318              
1319             L
1320              
1321             L
1322              
1323             L
1324              
1325             =head1 COPYRIGHT
1326              
1327             Copyright 2001 by Marcel GrEnauer
1328              
1329             Some parts copyright 2009 - 2011 Adam Kennedy.
1330              
1331             This library is free software; you can redistribute it and/or modify
1332             it under the same terms as Perl itself.
1333              
1334             =cut