File Coverage

blib/lib/Aspect/Advice/After.pm
Criterion Covered Total %
statement 263 277 94.9
branch 136 146 93.1
condition n/a
subroutine 12 12 100.0
pod n/a
total 411 435 94.4


line stmt bran cond sub pod time code
1             package Aspect::Advice::After;
2              
3 26     26   1387 use strict;
  26         49  
  26         3335  
4              
5             # Added by eilara as hack around caller() core dump
6             # NOTE: Now we've switched to Sub::Uplevel can this be removed? --ADAMK
7 26     26   4604 use Carp::Heavy ();
  26         50  
  26         1705  
8 26     26   218 use Carp ();
  26         42  
  26         405  
9 26     26   136 use Sub::Uplevel ();
  26         1412  
  26         582  
10 26     26   18223 use Aspect::Hook ();
  26         394  
  26         454  
11 26     26   148 use Aspect::Advice ();
  26         50  
  26         396  
12 26     26   130 use Aspect::Point ();
  26         42  
  26         7194  
13              
14             our $VERSION = '1.04';
15             our @ISA = 'Aspect::Advice';
16              
17             # NOTE: To simplify debugging of the generated code, all injected string
18             # fragments will be defined in $UPPERCASE, and all lexical variables to be
19             # accessed via the closure will be in $lowercase.
20             sub _install {
21 65     65   134 my $self = shift;
22 65         167 my $pointcut = $self->pointcut;
23 65         295 my $code = $self->code;
24 65         324 my $lexical = $self->lexical;
25              
26             # Get the curried version of the pointcut we will use for the
27             # runtime checks instead of the original.
28             # Because $MATCH_RUN is used in boolean conditionals, if there
29             # is nothing to do the compiler will optimise away the code entirely.
30 65         516 my $curried = $pointcut->curry_runtime;
31 65 100       473 my $compiled = $curried ? $curried->compiled_runtime : undef;
32 65 100       231 my $MATCH_RUN = $compiled ? '$compiled->()' : 1;
33              
34             # When an aspect falls out of scope, we don't attempt to remove
35             # the generated hook code, because it might (for reasons potentially
36             # outside our control) have been recursively hooked several times
37             # by both Aspect and other modules.
38             # Instead, we store an "out of scope" flag that is used to shortcut
39             # past the hook as quickely as possible.
40             # This flag is shared between all the generated hooks for each
41             # installed Aspect.
42             # If the advice is going to last lexical then we don't need to
43             # check or use the $out_of_scope variable.
44 65         115 my $out_of_scope = undef;
45 65 100       187 my $MATCH_DISABLED = $lexical ? '$out_of_scope' : '0';
46              
47             # Find all pointcuts that are statically matched
48             # wrap the method with advice code and install the wrapper
49 65         445 foreach my $name ( $pointcut->match_all ) {
50 94         203 my $NAME = $name; # For completeness
51              
52 26     26   149 no strict 'refs';
  26         50  
  26         2373  
53 94         459 my $original = *$name{CODE};
54 94 50       312 unless ( $original ) {
55 0         0 Carp::croak("Can't wrap non-existent subroutine ", $name);
56             }
57              
58             # Any way to set prototypes other than eval?
59 94         204 my $PROTOTYPE = prototype($original);
60 94 100       323 $PROTOTYPE = defined($PROTOTYPE) ? "($PROTOTYPE)" : '';
61              
62             # Generate the new function
63 26     26   147 no warnings 'redefine';
  26         50  
  26         5751  
64 94 50   26   57810 eval <<"END_PERL"; die $@ if $@;
  94 100       373  
  26 100       2389  
  19 100       40  
  19 100       246  
  3 100       6  
  3 100       20  
  3 100       202  
  3 100       60  
  2 100       12  
  1 100       3  
  2 100       34  
  2 100       11  
  2 100       32  
  2 0       12  
  6 100       19  
  5 100       18  
  15 100       62  
  10 100       683  
  10 100       62  
  10 100       228  
  10 100       104  
  6 100       143  
  4 100       14  
  8 100       89  
  5 100       20  
  5 100       33  
  5 50       58  
  5 100       58  
  6 100       12  
  6 100       25  
  6 100       243  
  6 100       111  
  5 100       44  
  3 100       4665  
  2 100       8  
  2 50       8  
  1 100       2  
  1 50       12  
  0 100       0  
  12 100       5734  
  11 100       25  
  11 100       44  
  2 100       3  
  2 100       10  
  2 100       98  
  2 100       56  
  2 100       15  
  1 100       9  
  1 100       5  
  1 100       2  
  1 100       5  
  1 100       10  
  2 50       34  
  1 100       9  
  8 100       30  
  4 100       9  
  4 100       21  
  4 100       171  
  4 100       99  
  3 50       30  
  1 100       10  
  1 50       2  
  2 100       8  
  2 100       9  
  2 100       257  
  2 100       16  
  5         13  
  5         23  
  5         255  
  5         117  
  2         9  
  15         5181  
  9         18  
  9         30  
  4         54  
  4         26  
  3         121  
  12         2097  
  12         27  
  12         50  
  4         74  
  4         39  
  3         119  
  3         64  
  5         14  
  3         8  
  5         28  
  5         122  
  5         91  
  5         36  
  3         11  
  3         91  
  11         51  
  7         25  
  7         32  
  7         302  
  7         235  
  5         26  
  4         34  
  4         12  
  4         88  
  4         17  
  3         14  
  3         69  
  4         11  
  4         23  
  3         172  
  3         86  
  3         17  
  3         28  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  15         6824  
  13         30  
  13         49  
  4         17  
  4         80  
  4         174  
  4         91  
  2         15  
  1         3  
  3         8  
  3         21  
  2         68  
  2         21  
  1         2  
  1         23  
  9         39  
  4         11  
  4         24  
  4         373  
  4         110  
  2         42  
  1         2  
  4         13  
  3         33  
  3         116  
  3         25  
  2         17  
  5         19  
  5         25  
  5         270  
  5         138  
  3         28  
  1         9  
  3         10  
  3         14  
  3         62  
  3         97  
  1         2  
  16         3139  
  13         30  
  13         44  
  4         12  
  4         30  
  3         161  
  3         81  
  2         14  
  1         9  
  1         3  
  1         5  
  1         42  
  1         5  
  1         3  
  5         1082  
  11         38  
  6         16  
  4         20  
  4         207  
  4         102  
  1         8  
  0         0  
  3         8  
  3         16  
  3         68  
  3         22  
  2         23  
  5         11  
  5         24  
  7         236  
  6         137  
  3         13  
  3         29  
  4         12  
  3         15  
  3         64  
  4         26  
  3         24  
  10         6649  
  10         23  
  10         54  
  3         8  
  3         13  
  3         118  
  3         216  
  3         13  
  3         27  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  1         3  
  8         28  
  5         16  
  4         41  
  4         209  
  4         105  
  2         14  
  1         9  
  2         25  
  2         12  
  2         920  
  2         19  
  1         12  
  4         14  
  4         20  
  4         289  
  4         131  
  2         7  
  2         13  
  3         12  
  3         825  
  3         49  
  3         34  
  0         0  
65             package Aspect::Hook;
66              
67             *$NAME = sub $PROTOTYPE {
68             # Is this a lexically scoped hook that has finished
69             goto &\$original if $MATCH_DISABLED;
70              
71             my \$wantarray = wantarray;
72             if ( \$wantarray ) {
73             my \$return = eval { [
74             Sub::Uplevel::uplevel(
75             2, \$original, \@_,
76             )
77             ] };
78              
79             local \$Aspect::POINT = bless {
80             type => 'after',
81             pointcut => \$pointcut,
82             original => \$original,
83             sub_name => \$name,
84             wantarray => \$wantarray,
85             args => \\\@_,
86             return_value => \$return,
87             exception => \$\@,
88             }, 'Aspect::Point';
89              
90             unless ( $MATCH_RUN ) {
91             return \@\$return unless \$Aspect::POINT->{exception};
92             die \$Aspect::POINT->{exception};
93             }
94              
95             # Execute the advice code
96             local \$_ = \$Aspect::POINT;
97             &\$code(\$Aspect::POINT);
98              
99             # Throw the same (or modified) exception
100             my \$exception = \$_->{exception};
101             die \$exception if \$exception;
102              
103             # Get the (potentially) modified return value
104             return \@{\$_->{return_value}};
105             }
106              
107             if ( defined \$wantarray ) {
108             my \$return = eval {
109             Sub::Uplevel::uplevel(
110             2, \$original, \@_,
111             )
112             };
113              
114             local \$Aspect::POINT = bless {
115             type => 'after',
116             pointcut => \$pointcut,
117             original => \$original,
118             sub_name => \$name,
119             wantarray => \$wantarray,
120             args => \\\@_,
121             return_value => \$return,
122             exception => \$\@,
123             }, 'Aspect::Point';
124              
125             unless ( $MATCH_RUN ) {
126             return \$return unless \$Aspect::POINT->{exception};
127             die \$Aspect::POINT->{exception};
128             }
129              
130             # Execute the advice code
131             local \$_ = \$Aspect::POINT;
132             &\$code(\$Aspect::POINT);
133              
134             # Throw the same (or modified) exception
135             my \$exception = \$_->{exception};
136             die \$exception if \$exception;
137              
138             # Return the potentially-modified value
139             return \$_->{return_value};
140              
141             }
142              
143             eval {
144             Sub::Uplevel::uplevel(
145             2, \$original, \@_,
146             )
147             };
148              
149             local \$Aspect::POINT = bless {
150             type => 'after',
151             pointcut => \$pointcut,
152             original => \$original,
153             sub_name => \$name,
154             wantarray => \$wantarray,
155             args => \\\@_,
156             return_value => undef,
157             exception => \$\@,
158             }, 'Aspect::Point';
159              
160             unless ( $MATCH_RUN ) {
161             return unless \$Aspect::POINT->{exception};
162             die \$Aspect::POINT->{exception};
163             }
164              
165             # Execute the advice code
166             local \$_ = \$Aspect::POINT;
167             &\$code(\$Aspect::POINT);
168              
169             # Throw the same (or modified) exception
170             my \$exception = \$_->{exception};
171             die \$exception if \$exception;
172              
173             return;
174             };
175             END_PERL
176 94         478 $self->{installed}++;
177             }
178              
179             # If this will run lexical we don't need a descoping hook
180 65 100       381 return unless $lexical;
181              
182             # Return the lexical descoping hook.
183             # This MUST be stored and run at DESTROY-time by the
184             # parent object calling _install. This is less bullet-proof
185             # than the DESTROY-time self-executing blessed coderef
186 44     44   465 return sub { $out_of_scope = 1 };
  44         334  
187             }
188              
189             1;
190              
191             __END__