line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Aspect::Point; |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
=pod |
4
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
=head1 NAME |
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
Aspect::Point - The Join Point context |
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
=head1 SYNOPSIS |
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
# An anonymous function suitable for use as advice code |
12
|
|
|
|
|
|
|
# across all advice types (as it uses no limited access methods) |
13
|
|
|
|
|
|
|
my $advice_code = sub { |
14
|
|
|
|
|
|
|
print $_->type; # The advice type ('before') |
15
|
|
|
|
|
|
|
print $_->pointcut; # The matching pointcut ($pointcut) |
16
|
|
|
|
|
|
|
print $_->enclosing; # Access cflow pointcut advice context |
17
|
|
|
|
|
|
|
print $_->sub_name; # The full package_name::sub_name |
18
|
|
|
|
|
|
|
print $_->package_name; # The package name ('Person') |
19
|
|
|
|
|
|
|
print $_->short_name; # The sub name (a get or set method) |
20
|
|
|
|
|
|
|
print $_->self; # 1st parameter to the matching sub |
21
|
|
|
|
|
|
|
print ($_->args)[1]; # 2nd parameter to the matching sub |
22
|
|
|
|
|
|
|
$_->original->( x => 3 ); # Call matched sub independently |
23
|
|
|
|
|
|
|
$_->return_value(4) # Set the return value |
24
|
|
|
|
|
|
|
}; |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
=head1 DESCRIPTION |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
Advice code is called when the advice pointcut is matched. In this code, |
29
|
|
|
|
|
|
|
there is often a need to access information about the join point context |
30
|
|
|
|
|
|
|
of the advice. Information like: |
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
What is the actual sub name matched? |
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
What are the parameters in this call that we matched? |
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
Sometimes you want to change the context for the matched sub, such as |
37
|
|
|
|
|
|
|
appending a parameter or even stopping the matched sub from being called |
38
|
|
|
|
|
|
|
at all. |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
You do all these things through the C, which is an object |
41
|
|
|
|
|
|
|
that isa L. It is the only parameter provided to the advice |
42
|
|
|
|
|
|
|
code. It provides all the information required about the match context, |
43
|
|
|
|
|
|
|
and allows you to change the behavior of the matched sub. |
44
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
Note: Modifying parameters through the context in the code of an I |
46
|
|
|
|
|
|
|
advice, will have no effect, since the matched sub has already been called. |
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
In a future release this will be fixed so that the context for each advice |
49
|
|
|
|
|
|
|
type only responds to the methods relevant to that context, with the rest |
50
|
|
|
|
|
|
|
throwing an exception. |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
=head2 Cflows |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
If the pointcut of an advice is composed of at least one C the |
55
|
|
|
|
|
|
|
advice code may require not only the context of the advice, but the join |
56
|
|
|
|
|
|
|
point context of the cflows as well. |
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
This is required if you want to find out, for example, what the name of the |
59
|
|
|
|
|
|
|
sub that matched a cflow. In the synopsis example above, which method from |
60
|
|
|
|
|
|
|
C started the chain of calls that eventually reached the get/set |
61
|
|
|
|
|
|
|
on C? |
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
You can access cflow context in the synopsis above, by calling: |
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
$point->enclosing |
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
You get it from the main advice join point by calling a method named after |
68
|
|
|
|
|
|
|
the context key used in the cflow spec (which is "enclosing" if a custom name |
69
|
|
|
|
|
|
|
was not provided, in line with AspectJ terminology). In the synopsis pointcut |
70
|
|
|
|
|
|
|
definition, the cflow part was equivalent to: |
71
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
cflow enclosing => qr/^Company::/ |
73
|
|
|
|
|
|
|
^^^^^^^^^ |
74
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
An L will be created for the cflow, and you can access it |
76
|
|
|
|
|
|
|
using the C method. |
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
=head1 EXAMPLES |
79
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
Print parameters to matched sub: |
81
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
before { |
83
|
|
|
|
|
|
|
print join ',', $_->args; |
84
|
|
|
|
|
|
|
} $pointcut; |
85
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
Append a parameter: |
87
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
before { |
89
|
|
|
|
|
|
|
$_->args( $_->args, 'extra parameter' ); |
90
|
|
|
|
|
|
|
} $pointcut; |
91
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
Don't proceed to matched sub, return 4 instead: |
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
before { |
95
|
|
|
|
|
|
|
shift->return_value(4); |
96
|
|
|
|
|
|
|
} $pointcut; |
97
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
Call matched sub again and again until it returns something defined: |
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
after { |
101
|
|
|
|
|
|
|
my $point = shift; |
102
|
|
|
|
|
|
|
my $return = $point->return_value; |
103
|
|
|
|
|
|
|
while ( not defined $return ) { |
104
|
|
|
|
|
|
|
$return = $point->original($point->params); |
105
|
|
|
|
|
|
|
} |
106
|
|
|
|
|
|
|
$point->return_value($return); |
107
|
|
|
|
|
|
|
} $pointcut; |
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
Print the name of the C object that started the chain of calls |
110
|
|
|
|
|
|
|
that eventually reached the get/set on C: |
111
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
before { |
113
|
|
|
|
|
|
|
print shift->enclosing->self->name; |
114
|
|
|
|
|
|
|
} $pointcut; |
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
=head1 METHODS |
117
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
=cut |
119
|
|
|
|
|
|
|
|
120
|
26
|
|
|
26
|
|
137
|
use strict; |
|
26
|
|
|
|
|
49
|
|
|
26
|
|
|
|
|
885
|
|
121
|
26
|
|
|
26
|
|
132
|
use Carp (); |
|
26
|
|
|
|
|
46
|
|
|
26
|
|
|
|
|
355
|
|
122
|
26
|
|
|
26
|
|
130
|
use Sub::Uplevel (); |
|
26
|
|
|
|
|
43
|
|
|
26
|
|
|
|
|
352
|
|
123
|
26
|
|
|
26
|
|
134
|
use Aspect::Point::Static (); |
|
26
|
|
|
|
|
35
|
|
|
26
|
|
|
|
|
25111
|
|
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
our $VERSION = '1.04'; |
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
###################################################################### |
132
|
|
|
|
|
|
|
# Aspect::Point Methods |
133
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
# sub new { |
135
|
|
|
|
|
|
|
# my $class = shift; |
136
|
|
|
|
|
|
|
# bless { @_ }, $class; |
137
|
|
|
|
|
|
|
# } |
138
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
=pod |
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
=head2 type |
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
The C method is a convenience provided in the situation something has a |
144
|
|
|
|
|
|
|
L method and wants to know the advice declarator it is made for. |
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
Returns C<"before"> in L advice, C<"after"> in |
147
|
|
|
|
|
|
|
L advice, or C<"around"> in |
148
|
|
|
|
|
|
|
L advice. |
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
=cut |
151
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
sub type { |
153
|
|
|
|
|
|
|
$_[0]->{type}; |
154
|
|
|
|
|
|
|
} |
155
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
=pod |
157
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
=head2 pointcut |
159
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
my $pointcut = $_->pointcut; |
161
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
The C method provides access to the original join point specification |
163
|
|
|
|
|
|
|
(as a tree of L objects) that the current join point matched |
164
|
|
|
|
|
|
|
against. |
165
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
Please note that the pointcut returned is the full and complete pointcut tree, |
167
|
|
|
|
|
|
|
due to the heavy optimisation used on the actual pointcut code when it is run |
168
|
|
|
|
|
|
|
there is no way at the time of advice execution to indicate which specific |
169
|
|
|
|
|
|
|
conditions in the pointcut tree matched and which did not. |
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
Returns an object which is a sub-class of L. |
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
=cut |
174
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
sub pointcut { |
176
|
|
|
|
|
|
|
$_[0]->{pointcut}; |
177
|
|
|
|
|
|
|
} |
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
=pod |
180
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
=head2 original |
182
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
$_->original->( 1, 2, 3 ); |
184
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
In a pointcut, the C method returns a C reference to the |
186
|
|
|
|
|
|
|
original function before it was hooked by the L weaving process. |
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
Calls made to the function are unprotected, parameters and calling context will |
189
|
|
|
|
|
|
|
not be replicated into the function, return params and exception will not be |
190
|
|
|
|
|
|
|
caught. |
191
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
=cut |
193
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
sub original { |
195
|
|
|
|
|
|
|
$_[0]->{original}; |
196
|
|
|
|
|
|
|
} |
197
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
=pod |
199
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
=head2 sub_name |
201
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
# Prints "Full::Function::name" |
203
|
|
|
|
|
|
|
before { |
204
|
|
|
|
|
|
|
print $_->sub_name . "\n"; |
205
|
|
|
|
|
|
|
} call 'Full::Function::name'; |
206
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
The C method returns a string with the full resolved function name |
208
|
|
|
|
|
|
|
at the join point the advice code is running at. |
209
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
=cut |
211
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
sub sub_name { |
213
|
|
|
|
|
|
|
$_[0]->{sub_name}; |
214
|
|
|
|
|
|
|
} |
215
|
|
|
|
|
|
|
|
216
|
|
|
|
|
|
|
=pod |
217
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
=head2 package_name |
219
|
|
|
|
|
|
|
|
220
|
|
|
|
|
|
|
# Prints "Just::Package" |
221
|
|
|
|
|
|
|
before { |
222
|
|
|
|
|
|
|
print $_->package_name . "\n"; |
223
|
|
|
|
|
|
|
} call 'Just::Package::name'; |
224
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
The C parameter is a convenience wrapper around the C |
226
|
|
|
|
|
|
|
method. Where C will return the fully resolved function name, the |
227
|
|
|
|
|
|
|
C method will return just the namespace of the package of the |
228
|
|
|
|
|
|
|
join point. |
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
=cut |
231
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
sub package_name { |
233
|
0
|
|
|
0
|
1
|
0
|
my $name = $_[0]->{sub_name}; |
234
|
0
|
0
|
|
|
|
0
|
return '' unless $name =~ /::/; |
235
|
0
|
|
|
|
|
0
|
$name =~ s/::[^:]+$//; |
236
|
0
|
|
|
|
|
0
|
return $name; |
237
|
|
|
|
|
|
|
} |
238
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
=pod |
240
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
=head2 short_name |
242
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
# Prints "name" |
244
|
|
|
|
|
|
|
before { |
245
|
|
|
|
|
|
|
print $_->short_name . "\n"; |
246
|
|
|
|
|
|
|
} call 'Just::Package::name'; |
247
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
The C parameter is a convenience wrapper around the C |
249
|
|
|
|
|
|
|
method. Where C will return the fully resolved function name, the |
250
|
|
|
|
|
|
|
C method will return just the name of the function. |
251
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
=cut |
253
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
sub short_name { |
255
|
0
|
|
|
0
|
1
|
0
|
my $name = $_[0]->{sub_name}; |
256
|
0
|
0
|
|
|
|
0
|
return $name unless $name =~ /::/; |
257
|
0
|
|
|
|
|
0
|
$name =~ /::([^:]+)$/; |
258
|
0
|
|
|
|
|
0
|
return $1; |
259
|
|
|
|
|
|
|
} |
260
|
|
|
|
|
|
|
|
261
|
|
|
|
|
|
|
=pod |
262
|
|
|
|
|
|
|
|
263
|
|
|
|
|
|
|
=head2 args |
264
|
|
|
|
|
|
|
|
265
|
|
|
|
|
|
|
# Add a parameter to the function call |
266
|
|
|
|
|
|
|
$_->args( $_->args, 'more' ); |
267
|
|
|
|
|
|
|
|
268
|
|
|
|
|
|
|
The C method allows you to get or set the list of parameters to a |
269
|
|
|
|
|
|
|
function. It is the method equivalent of manipulating the C<@_> array. |
270
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
It uses a slightly unusual calling convention based on list context, but does |
272
|
|
|
|
|
|
|
so in a way that allows your advice code to read very naturally. |
273
|
|
|
|
|
|
|
|
274
|
|
|
|
|
|
|
To summarise the situation, the three uses of the C method are listed |
275
|
|
|
|
|
|
|
below, along with their C<@_> equivalents. |
276
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
# Get the parameters as a list |
278
|
|
|
|
|
|
|
my @list = $_->args; # my $list = @_; |
279
|
|
|
|
|
|
|
|
280
|
|
|
|
|
|
|
# Get the number of parameters |
281
|
|
|
|
|
|
|
my $count = $_->args; # my $count = @_; |
282
|
|
|
|
|
|
|
|
283
|
|
|
|
|
|
|
# Set the parameters |
284
|
|
|
|
|
|
|
$_->args( 1, 2, 3 ); # @_ = ( 1, 2, 3 ); |
285
|
|
|
|
|
|
|
|
286
|
|
|
|
|
|
|
As you can see from the above example, when C is called in list context |
287
|
|
|
|
|
|
|
it returns the list of parameters. When it is called in scalar context, it |
288
|
|
|
|
|
|
|
returns the number of parameters. And when it is called in void context, it |
289
|
|
|
|
|
|
|
sets the parameters to the passed values. |
290
|
|
|
|
|
|
|
|
291
|
|
|
|
|
|
|
Although this is somewhat unconventional, it does allow the most common existing |
292
|
|
|
|
|
|
|
uses of the older C method to be changed directly to the new C |
293
|
|
|
|
|
|
|
method (such as the first example above). |
294
|
|
|
|
|
|
|
|
295
|
|
|
|
|
|
|
And unlike the original, you can legally call C in such a way as to set |
296
|
|
|
|
|
|
|
the function parameters to be an empty list (which you could not do with the |
297
|
|
|
|
|
|
|
older C method). |
298
|
|
|
|
|
|
|
|
299
|
|
|
|
|
|
|
# Set the function parameters to a null list |
300
|
|
|
|
|
|
|
$_->args(); |
301
|
|
|
|
|
|
|
|
302
|
|
|
|
|
|
|
=cut |
303
|
|
|
|
|
|
|
|
304
|
|
|
|
|
|
|
sub args { |
305
|
94
|
100
|
|
94
|
1
|
419
|
if ( defined CORE::wantarray ) { |
306
|
76
|
|
|
|
|
86
|
return @{$_[0]->{args}}; |
|
76
|
|
|
|
|
1276
|
|
307
|
|
|
|
|
|
|
} else { |
308
|
18
|
|
|
|
|
60
|
@{$_[0]->{args}} = @_[1..$#_]; |
|
18
|
|
|
|
|
375
|
|
309
|
|
|
|
|
|
|
} |
310
|
|
|
|
|
|
|
} |
311
|
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
=pod |
313
|
|
|
|
|
|
|
|
314
|
|
|
|
|
|
|
=head2 self |
315
|
|
|
|
|
|
|
|
316
|
|
|
|
|
|
|
after { |
317
|
|
|
|
|
|
|
$_->self->save; |
318
|
|
|
|
|
|
|
} My::Foo::set; |
319
|
|
|
|
|
|
|
|
320
|
|
|
|
|
|
|
The C method is a convenience provided for when you are writing advice |
321
|
|
|
|
|
|
|
that will be working with object-oriented Perl code. It returns the first |
322
|
|
|
|
|
|
|
parameter to the method (which should be object), which you can then call |
323
|
|
|
|
|
|
|
methods on. |
324
|
|
|
|
|
|
|
|
325
|
|
|
|
|
|
|
The result is advice code that is much more natural to read, as you can see in |
326
|
|
|
|
|
|
|
the above example where we implement an auto-save feature on the class |
327
|
|
|
|
|
|
|
C, writing the contents to disk every time a value is set without |
328
|
|
|
|
|
|
|
error. |
329
|
|
|
|
|
|
|
|
330
|
|
|
|
|
|
|
At present the C method is implemented fairly naively, if used outside |
331
|
|
|
|
|
|
|
of object-oriented code it will still return something (including C in |
332
|
|
|
|
|
|
|
the case where there were no parameters to the join point function). |
333
|
|
|
|
|
|
|
|
334
|
|
|
|
|
|
|
=cut |
335
|
|
|
|
|
|
|
|
336
|
|
|
|
|
|
|
sub self { |
337
|
20
|
|
|
20
|
1
|
1066
|
$_[0]->{args}->[0]; |
338
|
|
|
|
|
|
|
} |
339
|
|
|
|
|
|
|
|
340
|
|
|
|
|
|
|
=pod |
341
|
|
|
|
|
|
|
|
342
|
|
|
|
|
|
|
=head2 wantarray |
343
|
|
|
|
|
|
|
|
344
|
|
|
|
|
|
|
# Return differently depending on the calling context |
345
|
|
|
|
|
|
|
if ( $_->wantarray ) { |
346
|
|
|
|
|
|
|
$_->return_value(5); |
347
|
|
|
|
|
|
|
} else { |
348
|
|
|
|
|
|
|
$_->return_value(1, 2, 3, 4, 5); |
349
|
|
|
|
|
|
|
} |
350
|
|
|
|
|
|
|
|
351
|
|
|
|
|
|
|
The C method returns the L context of the |
352
|
|
|
|
|
|
|
call to the function for the current join point. |
353
|
|
|
|
|
|
|
|
354
|
|
|
|
|
|
|
As with the core Perl C function, returns true if the function is |
355
|
|
|
|
|
|
|
being called in list context, false if the function is being called in scalar |
356
|
|
|
|
|
|
|
context, or C if the function is being called in void context. |
357
|
|
|
|
|
|
|
|
358
|
|
|
|
|
|
|
B |
359
|
|
|
|
|
|
|
|
360
|
|
|
|
|
|
|
Prior to L 0.98 the wantarray context of the call to the join point |
361
|
|
|
|
|
|
|
was available not only via the C method, but the advice code itself |
362
|
|
|
|
|
|
|
was called in matching wantarray context to the function call, allowing you to |
363
|
|
|
|
|
|
|
use plain C in the advice code as well. |
364
|
|
|
|
|
|
|
|
365
|
|
|
|
|
|
|
As all the other information about the join point was available through methods, |
366
|
|
|
|
|
|
|
having this one piece of metadata available different was becoming an oddity. |
367
|
|
|
|
|
|
|
|
368
|
|
|
|
|
|
|
The C context of the join point is now B available by the |
369
|
|
|
|
|
|
|
C method. |
370
|
|
|
|
|
|
|
|
371
|
|
|
|
|
|
|
=cut |
372
|
|
|
|
|
|
|
|
373
|
|
|
|
|
|
|
sub wantarray { |
374
|
|
|
|
|
|
|
$_[0]->{wantarray}; |
375
|
|
|
|
|
|
|
} |
376
|
|
|
|
|
|
|
|
377
|
|
|
|
|
|
|
=pod |
378
|
|
|
|
|
|
|
|
379
|
|
|
|
|
|
|
=head2 exception |
380
|
|
|
|
|
|
|
|
381
|
|
|
|
|
|
|
unless ( $_->exception ) { |
382
|
|
|
|
|
|
|
$_->exception('Kaboom'); |
383
|
|
|
|
|
|
|
} |
384
|
|
|
|
|
|
|
|
385
|
|
|
|
|
|
|
The C method is used to get the current die message or exception |
386
|
|
|
|
|
|
|
object, or to set the die message or exception object. |
387
|
|
|
|
|
|
|
|
388
|
|
|
|
|
|
|
=cut |
389
|
|
|
|
|
|
|
|
390
|
|
|
|
|
|
|
sub exception { |
391
|
33
|
50
|
|
33
|
1
|
211
|
unless ( $_[0]->{type} eq 'after' ) { |
392
|
0
|
|
|
|
|
0
|
Carp::croak("Cannot call exception in $_[0]->{exception} advice"); |
393
|
|
|
|
|
|
|
} |
394
|
33
|
100
|
|
|
|
190
|
return $_[0]->{exception} if defined CORE::wantarray(); |
395
|
29
|
|
|
|
|
735
|
$_[0]->{exception} = $_[1]; |
396
|
|
|
|
|
|
|
} |
397
|
|
|
|
|
|
|
|
398
|
|
|
|
|
|
|
=pod |
399
|
|
|
|
|
|
|
|
400
|
|
|
|
|
|
|
=head2 return_value |
401
|
|
|
|
|
|
|
|
402
|
|
|
|
|
|
|
# Add an extra value to the returned list |
403
|
|
|
|
|
|
|
$_->return_value( $_->return_value, 'thing' ); |
404
|
|
|
|
|
|
|
|
405
|
|
|
|
|
|
|
The C method is used to get or set the return value for the |
406
|
|
|
|
|
|
|
join point function, in a similar way to the normal Perl C keyword. |
407
|
|
|
|
|
|
|
|
408
|
|
|
|
|
|
|
As with the C method, the C method is sensitive to the |
409
|
|
|
|
|
|
|
context in which it is called. |
410
|
|
|
|
|
|
|
|
411
|
|
|
|
|
|
|
When called in list context, the C method returns the join point |
412
|
|
|
|
|
|
|
return value as a list. If the join point is called in scalar context, this will |
413
|
|
|
|
|
|
|
be a single-element list containing the scalar return value. If the join point |
414
|
|
|
|
|
|
|
is called in void context, this will be a null list. |
415
|
|
|
|
|
|
|
|
416
|
|
|
|
|
|
|
When called in scalar context, the C method returns the join |
417
|
|
|
|
|
|
|
point return value as a scalar. If the join point is called in list context, |
418
|
|
|
|
|
|
|
this will be the number of vales in the return list. If the join point is called |
419
|
|
|
|
|
|
|
in void context, this will be C |
420
|
|
|
|
|
|
|
|
421
|
|
|
|
|
|
|
When called in void context, the C method sets the return value |
422
|
|
|
|
|
|
|
for the join point using semantics identical to the C keyword. |
423
|
|
|
|
|
|
|
|
424
|
|
|
|
|
|
|
Because of this change in behavior based on the context in which C |
425
|
|
|
|
|
|
|
is called, you should generally always set C in it's own statement |
426
|
|
|
|
|
|
|
to prevent accidentally calling it in non-void context. |
427
|
|
|
|
|
|
|
|
428
|
|
|
|
|
|
|
# Return null (equivalent to "return;") |
429
|
|
|
|
|
|
|
$_->return_value; |
430
|
|
|
|
|
|
|
|
431
|
|
|
|
|
|
|
In advice types that can be triggered by an exception, or need to determine |
432
|
|
|
|
|
|
|
whether to continue to the join point function, setting a return value via |
433
|
|
|
|
|
|
|
C is seen as implicitly indicating that any exception should be |
434
|
|
|
|
|
|
|
suppressed, or that we do B want to continue to the join point function. |
435
|
|
|
|
|
|
|
|
436
|
|
|
|
|
|
|
When you call the C method this does NOT trigger an immediate |
437
|
|
|
|
|
|
|
C equivalent in the advice code, the lines after C will |
438
|
|
|
|
|
|
|
continue to be executed as normal (to provide an opportunity for cleanup |
439
|
|
|
|
|
|
|
operations to be done and so on). |
440
|
|
|
|
|
|
|
|
441
|
|
|
|
|
|
|
If you use C inside an if/else structure you will still need to |
442
|
|
|
|
|
|
|
do an explicit C if you wish to break out of the advice code. |
443
|
|
|
|
|
|
|
|
444
|
|
|
|
|
|
|
Thus, if you wish to break out of the advice code as well as return with an |
445
|
|
|
|
|
|
|
alternative value, you should do the following. |
446
|
|
|
|
|
|
|
|
447
|
|
|
|
|
|
|
return $_->return_value('value'); |
448
|
|
|
|
|
|
|
|
449
|
|
|
|
|
|
|
This usage of C appears to be contrary to the above instruction |
450
|
|
|
|
|
|
|
that setting the return value should always be done on a standalone line to |
451
|
|
|
|
|
|
|
guarentee void context. |
452
|
|
|
|
|
|
|
|
453
|
|
|
|
|
|
|
However, in Perl the context of the current function is inherited by a function |
454
|
|
|
|
|
|
|
called with return in the manner shown above. Thus the usage of C |
455
|
|
|
|
|
|
|
in this way alone is guarenteed to also set the return value rather than fetch |
456
|
|
|
|
|
|
|
it. |
457
|
|
|
|
|
|
|
|
458
|
|
|
|
|
|
|
=cut |
459
|
|
|
|
|
|
|
|
460
|
|
|
|
|
|
|
sub return_value { |
461
|
100
|
|
|
100
|
1
|
1733
|
my $self = shift; |
462
|
100
|
|
|
|
|
222
|
my $want = $self->{wantarray}; |
463
|
|
|
|
|
|
|
|
464
|
|
|
|
|
|
|
# Handle usage in getter form |
465
|
100
|
100
|
|
|
|
303
|
if ( defined CORE::wantarray() ) { |
466
|
|
|
|
|
|
|
# Let the inherent magic of Perl do the work between the |
467
|
|
|
|
|
|
|
# list and scalar context calls to return_value |
468
|
10
|
0
|
|
|
|
32
|
return @{$self->{return_value} || []} if $want; |
|
0
|
50
|
|
|
|
0
|
|
469
|
10
|
50
|
|
|
|
101
|
return $self->{return_value} if defined $want; |
470
|
0
|
|
|
|
|
0
|
return; |
471
|
|
|
|
|
|
|
} |
472
|
|
|
|
|
|
|
|
473
|
|
|
|
|
|
|
# We've been provided a return value |
474
|
90
|
|
|
|
|
187
|
$self->{exception} = ''; |
475
|
90
|
100
|
|
|
|
1662
|
$self->{return_value} = $want ? [ @_ ] : pop; |
476
|
|
|
|
|
|
|
} |
477
|
|
|
|
|
|
|
|
478
|
|
|
|
|
|
|
sub proceed { |
479
|
45
|
|
|
45
|
0
|
1632
|
my $self = shift; |
480
|
|
|
|
|
|
|
|
481
|
45
|
100
|
|
|
|
171
|
unless ( $self->{type} eq 'around' ) { |
482
|
8
|
|
|
|
|
179
|
Carp::croak("Cannot call proceed in $self->{type} advice"); |
483
|
|
|
|
|
|
|
} |
484
|
|
|
|
|
|
|
|
485
|
37
|
|
|
|
|
46
|
local $_ = ${$self->{topic}}; |
|
37
|
|
|
|
|
94
|
|
486
|
|
|
|
|
|
|
|
487
|
37
|
100
|
|
|
|
142
|
if ( $self->{wantarray} ) { |
|
|
100
|
|
|
|
|
|
488
|
3
|
|
|
|
|
11
|
$self->return_value( |
489
|
|
|
|
|
|
|
Sub::Uplevel::uplevel( |
490
|
|
|
|
|
|
|
2, |
491
|
|
|
|
|
|
|
$self->{original}, |
492
|
3
|
|
|
|
|
9
|
@{$self->{args}}, |
493
|
|
|
|
|
|
|
) |
494
|
|
|
|
|
|
|
); |
495
|
|
|
|
|
|
|
|
496
|
|
|
|
|
|
|
} elsif ( defined $self->{wantarray} ) { |
497
|
26
|
|
|
|
|
121
|
$self->return_value( |
498
|
|
|
|
|
|
|
scalar Sub::Uplevel::uplevel( |
499
|
|
|
|
|
|
|
2, |
500
|
|
|
|
|
|
|
$self->{original}, |
501
|
26
|
|
|
|
|
53
|
@{$self->{args}}, |
502
|
|
|
|
|
|
|
) |
503
|
|
|
|
|
|
|
); |
504
|
|
|
|
|
|
|
|
505
|
|
|
|
|
|
|
} else { |
506
|
8
|
|
|
|
|
31
|
Sub::Uplevel::uplevel( |
507
|
|
|
|
|
|
|
2, |
508
|
|
|
|
|
|
|
$self->{original}, |
509
|
8
|
|
|
|
|
24
|
@{$self->{args}}, |
510
|
|
|
|
|
|
|
); |
511
|
|
|
|
|
|
|
} |
512
|
|
|
|
|
|
|
|
513
|
37
|
|
|
|
|
1207
|
${$self->{topic}} = $_; |
|
37
|
|
|
|
|
91
|
|
514
|
|
|
|
|
|
|
|
515
|
37
|
|
|
|
|
889
|
return; |
516
|
|
|
|
|
|
|
} |
517
|
|
|
|
|
|
|
|
518
|
|
|
|
|
|
|
sub enclosing { |
519
|
|
|
|
|
|
|
$_[0]->{enclosing}; |
520
|
|
|
|
|
|
|
} |
521
|
|
|
|
|
|
|
|
522
|
|
|
|
|
|
|
sub topic { |
523
|
0
|
|
|
0
|
0
|
0
|
Carp::croak("The join point method topic in reserved"); |
524
|
|
|
|
|
|
|
} |
525
|
|
|
|
|
|
|
|
526
|
|
|
|
|
|
|
sub AUTOLOAD { |
527
|
12
|
|
|
12
|
|
1274
|
my $self = shift; |
528
|
12
|
|
|
|
|
27
|
my $key = our $AUTOLOAD; |
529
|
12
|
|
|
|
|
74
|
$key =~ s/^.*:://; |
530
|
12
|
50
|
|
|
|
55
|
Carp::croak "Key does not exist: [$key]" unless exists $self->{$key}; |
531
|
12
|
|
|
|
|
101
|
return $self->{$key}; |
532
|
|
|
|
|
|
|
} |
533
|
|
|
|
|
|
|
|
534
|
|
|
|
|
|
|
# Improves performance by not having to send DESTROY calls |
535
|
|
|
|
|
|
|
# through AUTOLOAD, and not having to check for DESTROY in AUTOLOAD. |
536
|
0
|
|
|
0
|
|
|
sub DESTROY () { } |
537
|
|
|
|
|
|
|
|
538
|
|
|
|
|
|
|
|
539
|
|
|
|
|
|
|
|
540
|
|
|
|
|
|
|
|
541
|
|
|
|
|
|
|
|
542
|
|
|
|
|
|
|
###################################################################### |
543
|
|
|
|
|
|
|
# Optional XS Acceleration |
544
|
|
|
|
|
|
|
|
545
|
|
|
|
|
|
|
BEGIN { |
546
|
26
|
|
|
26
|
|
70
|
local $@; |
547
|
26
|
|
|
26
|
|
3428
|
eval <<'END_PERL'; |
|
26
|
|
|
|
|
174
|
|
|
26
|
|
|
|
|
787
|
|
|
26
|
|
|
|
|
334
|
|
548
|
|
|
|
|
|
|
use Class::XSAccessor 1.08 { |
549
|
|
|
|
|
|
|
replace => 1, |
550
|
|
|
|
|
|
|
getters => { |
551
|
|
|
|
|
|
|
'type' => 'type', |
552
|
|
|
|
|
|
|
'pointcut' => 'pointcut', |
553
|
|
|
|
|
|
|
'original' => 'original', |
554
|
|
|
|
|
|
|
'sub_name' => 'sub_name', |
555
|
|
|
|
|
|
|
'wantarray' => 'wantarray', |
556
|
|
|
|
|
|
|
'enclosing' => 'enclosing', |
557
|
|
|
|
|
|
|
}, |
558
|
|
|
|
|
|
|
}; |
559
|
|
|
|
|
|
|
END_PERL |
560
|
|
|
|
|
|
|
} |
561
|
|
|
|
|
|
|
|
562
|
|
|
|
|
|
|
1; |
563
|
|
|
|
|
|
|
|
564
|
|
|
|
|
|
|
=pod |
565
|
|
|
|
|
|
|
|
566
|
|
|
|
|
|
|
=head1 AUTHORS |
567
|
|
|
|
|
|
|
|
568
|
|
|
|
|
|
|
Adam Kennedy Eadamk@cpan.orgE |
569
|
|
|
|
|
|
|
|
570
|
|
|
|
|
|
|
Marcel GrEnauer Emarcel@cpan.orgE |
571
|
|
|
|
|
|
|
|
572
|
|
|
|
|
|
|
Ran Eilam Eeilara@cpan.orgE |
573
|
|
|
|
|
|
|
|
574
|
|
|
|
|
|
|
=head1 COPYRIGHT |
575
|
|
|
|
|
|
|
|
576
|
|
|
|
|
|
|
Copyright 2001 by Marcel GrEnauer |
577
|
|
|
|
|
|
|
|
578
|
|
|
|
|
|
|
Some parts copyright 2009 - 2013 Adam Kennedy. |
579
|
|
|
|
|
|
|
|
580
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or modify |
581
|
|
|
|
|
|
|
it under the same terms as Perl itself. |
582
|
|
|
|
|
|
|
|
583
|
|
|
|
|
|
|
=cut |