File Coverage

blib/lib/Aspect.pm
Criterion Covered Total %
statement 108 112 96.4
branch 8 12 66.6
condition 3 6 50.0
subroutine 40 40 100.0
pod 13 14 92.8
total 172 184 93.4


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