| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package Aspect::AdviceContext; |
|
2
|
|
|
|
|
|
|
|
|
3
|
1
|
|
|
1
|
|
6
|
use strict; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
51
|
|
|
4
|
1
|
|
|
1
|
|
25
|
use warnings; |
|
|
1
|
|
|
|
|
1
|
|
|
|
1
|
|
|
|
|
45
|
|
|
5
|
1
|
|
|
1
|
|
8
|
use Carp; |
|
|
1
|
|
|
|
|
1
|
|
|
|
1
|
|
|
|
|
1187
|
|
|
6
|
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
sub new { |
|
8
|
17
|
|
|
17
|
0
|
8152
|
my ($class, %spec) = @_; |
|
9
|
17
|
50
|
|
|
|
47
|
croak "cannot create with no sub_name" unless $spec{sub_name}; |
|
10
|
95
|
|
|
|
|
173
|
my $self = bless { |
|
11
|
17
|
|
|
|
|
48
|
(map { $_ => $spec{$_} } keys %spec), |
|
12
|
|
|
|
|
|
|
proceed => 1, |
|
13
|
|
|
|
|
|
|
}, $class; |
|
14
|
17
|
|
|
|
|
65
|
return $self; |
|
15
|
|
|
|
|
|
|
} |
|
16
|
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
sub run_original { |
|
18
|
1
|
|
|
1
|
0
|
2
|
my $self = shift; |
|
19
|
1
|
|
|
|
|
13
|
my $original = $self->original; |
|
20
|
1
|
|
|
|
|
5
|
my @params = $self->params; |
|
21
|
1
|
|
|
|
|
1
|
my $return_value; |
|
22
|
1
|
50
|
|
|
|
4
|
if (wantarray) |
|
23
|
0
|
|
|
|
|
0
|
{ $return_value = [$original->(@params)] } |
|
24
|
|
|
|
|
|
|
else |
|
25
|
1
|
|
|
|
|
4
|
{ $return_value = $original->(@params) } |
|
26
|
1
|
|
|
|
|
7
|
$self->return_value($return_value); |
|
27
|
1
|
|
|
|
|
2
|
return $self->return_value; |
|
28
|
|
|
|
|
|
|
} |
|
29
|
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
sub proceed { |
|
31
|
9
|
|
|
9
|
0
|
16
|
my ($self, $value) = @_; |
|
32
|
9
|
50
|
|
|
|
50
|
return $self->get_value('proceed') if @_ == 1; |
|
33
|
0
|
|
|
|
|
0
|
$self->{proceed} = $value; |
|
34
|
0
|
|
|
|
|
0
|
return $self; |
|
35
|
|
|
|
|
|
|
} |
|
36
|
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
sub append_param { |
|
38
|
3
|
|
|
3
|
0
|
11
|
my ($self, @param) = @_; |
|
39
|
3
|
|
|
|
|
4
|
push @{$self->params}, @param; |
|
|
3
|
|
|
|
|
7
|
|
|
40
|
3
|
|
|
|
|
7
|
return $self; |
|
41
|
|
|
|
|
|
|
} |
|
42
|
|
|
|
|
|
|
|
|
43
|
1
|
|
|
1
|
0
|
5
|
sub append_params { shift->append_param(@_) } |
|
44
|
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
sub params { |
|
46
|
18
|
|
|
18
|
0
|
54
|
my ($self, @value) = @_; |
|
47
|
18
|
100
|
|
|
|
73
|
return $self->get_value('params') if @_ == 1; |
|
48
|
1
|
|
|
|
|
3
|
$self->{params} = \@value; |
|
49
|
1
|
|
|
|
|
4
|
return $self; |
|
50
|
|
|
|
|
|
|
} |
|
51
|
|
|
|
|
|
|
|
|
52
|
7
|
|
|
7
|
0
|
41
|
sub self { shift->{params}->[0] } |
|
53
|
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
sub package_name { |
|
55
|
1
|
|
|
1
|
0
|
3
|
my $self = shift; |
|
56
|
1
|
|
|
|
|
7
|
my $name = $self->sub_name; |
|
57
|
1
|
50
|
|
|
|
6
|
return '' unless $name =~ /::/; |
|
58
|
1
|
|
|
|
|
5
|
$name =~ s/::[^:]+$//; |
|
59
|
1
|
|
|
|
|
6
|
return $name; |
|
60
|
|
|
|
|
|
|
} |
|
61
|
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
sub short_sub_name { |
|
63
|
1
|
|
|
1
|
0
|
3
|
my $self = shift; |
|
64
|
1
|
|
|
|
|
7
|
my $name = $self->sub_name; |
|
65
|
1
|
50
|
|
|
|
8
|
return $name unless $name =~ /::/; |
|
66
|
1
|
|
|
|
|
6
|
$name =~ /::([^:]+)$/; |
|
67
|
1
|
|
|
|
|
6
|
return $1; |
|
68
|
|
|
|
|
|
|
} |
|
69
|
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
sub return_value { |
|
71
|
23
|
|
|
23
|
0
|
464
|
my ($self, $value) = @_; |
|
72
|
23
|
100
|
|
|
|
56
|
if (@_ == 1) { |
|
73
|
13
|
|
|
|
|
27
|
my $return_value = $self->get_value('return_value'); |
|
74
|
13
|
50
|
33
|
|
|
120
|
return wantarray && ref $return_value eq 'ARRAY'? |
|
75
|
|
|
|
|
|
|
@$return_value: $return_value; |
|
76
|
|
|
|
|
|
|
} |
|
77
|
10
|
|
|
|
|
36
|
$self->{return_value} = $value; |
|
78
|
10
|
|
|
|
|
20
|
$self->{proceed} = 0; |
|
79
|
10
|
|
|
|
|
22
|
return $self; |
|
80
|
|
|
|
|
|
|
} |
|
81
|
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
sub AUTOLOAD { |
|
83
|
10
|
|
|
10
|
|
1987
|
my $self = shift; |
|
84
|
10
|
|
|
|
|
16
|
my $key = our $AUTOLOAD; |
|
85
|
10
|
50
|
|
|
|
34
|
return if $key =~ /DESTROY$/; |
|
86
|
10
|
|
|
|
|
77
|
$key =~ s/^.*:://; |
|
87
|
10
|
|
|
|
|
31
|
return $self->get_value($key); |
|
88
|
|
|
|
|
|
|
} |
|
89
|
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
sub get_value { |
|
91
|
49
|
|
|
49
|
0
|
60
|
my ($self, $key) = @_; |
|
92
|
49
|
50
|
|
|
|
144
|
croak "Key does not exist: [$key]" unless exists $self->{$key}; |
|
93
|
49
|
|
|
|
|
67
|
my $value = $self->{$key}; |
|
94
|
49
|
100
|
66
|
|
|
277
|
return wantarray && ref $value eq 'ARRAY'? @$value: $value; |
|
95
|
|
|
|
|
|
|
} |
|
96
|
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
1; |
|
98
|
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
=head1 NAME |
|
100
|
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
Aspect::AdviceContext - a pointcut context for advice code |
|
102
|
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
=head1 SYNOPSIS |
|
104
|
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
$pointcut = call qr/^Person::[gs]et_/ & cflow company => qr/^Company::/; |
|
106
|
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
# using in 'before' advice code |
|
108
|
|
|
|
|
|
|
before { |
|
109
|
|
|
|
|
|
|
my $context = shift; # context is only param to advice code |
|
110
|
|
|
|
|
|
|
print $context->type; # 'before': advice type: before/after |
|
111
|
|
|
|
|
|
|
print $context->pointcut; # $pointcut: the pointcut for this advice |
|
112
|
|
|
|
|
|
|
print $context->sub_name; # package + sub name of matched sub |
|
113
|
|
|
|
|
|
|
print $context->package_name; # 'Person': package name of matched sub |
|
114
|
|
|
|
|
|
|
print $context->short_sub_name; # sub name of matched sub |
|
115
|
|
|
|
|
|
|
print $context->self; # 1st parameter to matched sub |
|
116
|
|
|
|
|
|
|
print $context->params->[1]; # 2nd parameter to matched sub |
|
117
|
|
|
|
|
|
|
$context->append_param($rdbms); # append param to matched sub |
|
118
|
|
|
|
|
|
|
$context->append_params($a, $b); # append params to matched sub |
|
119
|
|
|
|
|
|
|
$context->return_value(4) # don't proceed to matched sub, return 4 |
|
120
|
|
|
|
|
|
|
$context->original->(x => 3); # call matched sub, don't proceed |
|
121
|
|
|
|
|
|
|
$context->proceed(1); # do proceed to matched sub after all |
|
122
|
|
|
|
|
|
|
print $context->company->name; # access cflow pointcut advice context |
|
123
|
|
|
|
|
|
|
} $pointcut; |
|
124
|
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
=head1 DESCRIPTION |
|
126
|
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
Advice code is called when the advice pointcut is matched. In this code, |
|
128
|
|
|
|
|
|
|
there is always a need to access information about the context of the |
|
129
|
|
|
|
|
|
|
advice. Information like: what is the actual sub name matched? What are |
|
130
|
|
|
|
|
|
|
the parameters in this call that we matched? Sometimes you want to change |
|
131
|
|
|
|
|
|
|
the context for the matched sub: append a parameter, or even stop the |
|
132
|
|
|
|
|
|
|
matched sub from being called. |
|
133
|
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
You do all these things through the C. It is the only |
|
135
|
|
|
|
|
|
|
parameter provided to the advice code. It provides all the information |
|
136
|
|
|
|
|
|
|
required about the match context, and allows you to change the behavior |
|
137
|
|
|
|
|
|
|
of the matched sub. |
|
138
|
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
Note that modifying parameters through the context, in the code of an |
|
140
|
|
|
|
|
|
|
I advice, will have no effect, since the matched sub has already |
|
141
|
|
|
|
|
|
|
been called. |
|
142
|
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
=head1 CFLOW CONTEXT |
|
144
|
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
If the pointcut of an advice is composed of at least one |
|
146
|
|
|
|
|
|
|
L, advice code may require not only the context |
|
147
|
|
|
|
|
|
|
of the advice, but also the context of the cflows. This is required if |
|
148
|
|
|
|
|
|
|
you want to find out, for example, what is the name of the sub that |
|
149
|
|
|
|
|
|
|
matched a cflow. E.g. for the synopsis example above, what method of |
|
150
|
|
|
|
|
|
|
C started the chain of calls that eventually reached the get/set |
|
151
|
|
|
|
|
|
|
on C? |
|
152
|
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
You can access cflow context in the synopsis above, by calling: |
|
154
|
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
$context->company; |
|
156
|
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
You get it from the main advice context, by calling a method named after |
|
158
|
|
|
|
|
|
|
the context key used in the cflow spec. In the synopsis pointcut |
|
159
|
|
|
|
|
|
|
definition, the cflow part was: |
|
160
|
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
cflow company => qr/^Company::/ |
|
162
|
|
|
|
|
|
|
^^^^^^^ |
|
163
|
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
An C will be created for the cflow, and you can access it |
|
165
|
|
|
|
|
|
|
using the key C. |
|
166
|
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
=head1 EXAMPLES |
|
168
|
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
Print parameters to matched sub: |
|
170
|
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
before { my $c = shift; print join(',', $c->params) } $pointcut; |
|
172
|
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
Append a parameter: |
|
174
|
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
before { shift->append_param('extra-param') } $pointcut; |
|
176
|
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
Don't proceed to matched sub, return 4 instead: |
|
178
|
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
before { shift->return_value(4) } $pointcut; |
|
180
|
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
Call matched sub again, and again, until it returns something defined: |
|
182
|
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
after { |
|
184
|
|
|
|
|
|
|
my $context = shift; |
|
185
|
|
|
|
|
|
|
my $return = $context->return_value; |
|
186
|
|
|
|
|
|
|
while (!defined $return) |
|
187
|
|
|
|
|
|
|
{ $return = $context->original($context->params) } |
|
188
|
|
|
|
|
|
|
$context->return_value($return); |
|
189
|
|
|
|
|
|
|
} $pointcut; |
|
190
|
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
Print the name of the C object that started the chain of calls |
|
192
|
|
|
|
|
|
|
that eventually reached the get/set on C: |
|
193
|
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
before { print shift->company->name } $pointcut; |
|
195
|
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
=head1 SEE ALSO |
|
197
|
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
See the L pod for a guide to the Aspect module. |
|
199
|
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
You can find examples of using the C in any advice code. |
|
201
|
|
|
|
|
|
|
The aspect library for example (e.g. L). |
|
202
|
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
L creates the main C, and |
|
204
|
|
|
|
|
|
|
C creates contexts for each matched call flow. |
|
205
|
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
=cut |
|
207
|
|
|
|
|
|
|
|