| 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 | 
| 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 |