line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Sub::Monkey; |
2
|
|
|
|
|
|
|
|
3
|
1
|
|
|
1
|
|
23261
|
use strict; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
34
|
|
4
|
1
|
|
|
1
|
|
5
|
use warnings; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
295
|
|
5
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
our $VERSION = '0.004'; |
7
|
|
|
|
|
|
|
$Sub::Monkey::Subs = {}; |
8
|
|
|
|
|
|
|
$Sub::Monkey::CanPatch = []; |
9
|
|
|
|
|
|
|
$Sub::Monkey::Classes = []; |
10
|
|
|
|
|
|
|
$Sub::Monkey::Iter = 0; |
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
=head1 NAME |
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
Sub::Monkey - Dynamically and neatly monkey patch a module |
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
=head1 DEPRECATED |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
Please note this module will not be maintained anymore. Instead, please check out C. It's the same project with updated pod and newed methods. Not to mention a namespace that makes a bit more sense.. |
19
|
|
|
|
|
|
|
Code you've made with Sub::Monkey will not break, just change the file where it's used as such: C and you're sorted. |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
=head1 DESCRIPTION |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
In some cases, rare cases, you may need to temporarily patch a module on-the-go. Sub::Monkey can help you achieve this by providing a set of methods to create, override and add hook modifiers, similar to M, but can apply them to remote modules (Not the current one). |
24
|
|
|
|
|
|
|
This type of monkey patching is reasonably safe because you can plainly see what changes are being made to what modules. Obviously monkey patching isn't always the best alternative, but sometimes you may have no other choice. |
25
|
|
|
|
|
|
|
Sub::Monkey also provides the ability to undo any patching you made with C. |
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
=head1 SYNOPSIS |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
use Sub::Monkey qw; |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
method 'needThisMethod' => sub { |
32
|
|
|
|
|
|
|
... |
33
|
|
|
|
|
|
|
}, |
34
|
|
|
|
|
|
|
qw; |
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
We just created a brand new method in the Some::Package class. If you attempt to override an existing method using C, then Sub::Monkey will raise an error, because really you should be using C instead. |
37
|
|
|
|
|
|
|
Remember, to patch a module with Sub::Monkey, you need to explicitly tell it you want to modify a class by importing it when you C |
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
use Sub::Monkey qw; |
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
=head1 METHODS |
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
=cut |
44
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
sub import { |
46
|
1
|
|
|
1
|
|
8
|
my ($class, @args) = @_; |
47
|
1
|
|
|
|
|
2
|
my $pkg = scalar caller; |
48
|
1
|
50
|
|
|
|
5
|
if (scalar @args > 0) { |
49
|
0
|
|
|
|
|
0
|
for my $m (@args) { |
50
|
0
|
|
|
|
|
0
|
push @{$Sub::Monkey::CanPatch}, $m; |
|
0
|
|
|
|
|
0
|
|
51
|
|
|
|
|
|
|
} |
52
|
0
|
|
|
|
|
0
|
_extend_class(\@args, $pkg); |
53
|
|
|
|
|
|
|
} |
54
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
_import_def( |
56
|
1
|
|
|
|
|
4
|
$pkg, |
57
|
|
|
|
|
|
|
undef, |
58
|
|
|
|
|
|
|
qw/ |
59
|
|
|
|
|
|
|
override |
60
|
|
|
|
|
|
|
method |
61
|
|
|
|
|
|
|
before |
62
|
|
|
|
|
|
|
after |
63
|
|
|
|
|
|
|
around |
64
|
|
|
|
|
|
|
unpatch |
65
|
|
|
|
|
|
|
instance |
66
|
|
|
|
|
|
|
original |
67
|
|
|
|
|
|
|
/ |
68
|
|
|
|
|
|
|
); |
69
|
|
|
|
|
|
|
} |
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
sub _extend_class { |
72
|
0
|
|
|
0
|
|
0
|
my ($mothers, $class) = @_; |
73
|
|
|
|
|
|
|
|
74
|
0
|
|
|
|
|
0
|
foreach my $mother (@$mothers) { |
75
|
|
|
|
|
|
|
# if class is unknown to us, import it (FIXME) |
76
|
0
|
0
|
|
|
|
0
|
unless (grep { $_ eq $mother } @$Sub::Monkey::Classes) { |
|
0
|
|
|
|
|
0
|
|
77
|
0
|
|
|
|
|
0
|
eval "use $mother"; |
78
|
0
|
0
|
|
|
|
0
|
warn "Could not load $mother: $@" |
79
|
|
|
|
|
|
|
if $@; |
80
|
|
|
|
|
|
|
|
81
|
0
|
|
|
|
|
0
|
$mother->import; |
82
|
|
|
|
|
|
|
} |
83
|
0
|
|
|
|
|
0
|
push @$Sub::Monkey::Classes, $class; |
84
|
|
|
|
|
|
|
} |
85
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
{ |
87
|
1
|
|
|
1
|
|
6
|
no strict 'refs'; |
|
1
|
|
|
|
|
7
|
|
|
1
|
|
|
|
|
116
|
|
|
0
|
|
|
|
|
0
|
|
88
|
0
|
|
|
|
|
0
|
@{"${class}::ISA"} = @$mothers; |
|
0
|
|
|
|
|
0
|
|
89
|
|
|
|
|
|
|
} |
90
|
|
|
|
|
|
|
} |
91
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
sub _import_def { |
93
|
1
|
|
|
1
|
|
3
|
my ($pkg, $from, @subs) = @_; |
94
|
1
|
|
|
1
|
|
7
|
no strict 'refs'; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
318
|
|
95
|
1
|
50
|
|
|
|
2
|
if ($from) { |
96
|
0
|
|
|
|
|
0
|
for (@subs) { |
97
|
0
|
|
|
|
|
0
|
*{$pkg . "::$_"} = \&{"$from\::$_"}; |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
98
|
|
|
|
|
|
|
} |
99
|
|
|
|
|
|
|
} |
100
|
|
|
|
|
|
|
else { |
101
|
1
|
|
|
|
|
2
|
for (@subs) { |
102
|
8
|
|
|
|
|
10
|
*{$pkg . "::$_"} = \&$_; |
|
8
|
|
|
|
|
37
|
|
103
|
|
|
|
|
|
|
} |
104
|
|
|
|
|
|
|
} |
105
|
|
|
|
|
|
|
} |
106
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
sub _doh { |
108
|
0
|
|
|
0
|
|
|
my $err = shift; |
109
|
0
|
|
|
|
|
|
die $err . "\n"; |
110
|
|
|
|
|
|
|
} |
111
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
sub _check_init { |
113
|
0
|
|
|
0
|
|
|
my $class = shift; |
114
|
|
|
|
|
|
|
|
115
|
0
|
0
|
|
|
|
|
_doh "No class was specified" if ! $class; |
116
|
|
|
|
|
|
|
|
117
|
0
|
|
|
|
|
|
_doh "Not allowed to patch $class" |
118
|
0
|
0
|
|
|
|
|
if ! grep { $_ eq $class } @{$Sub::Monkey::CanPatch}; |
|
0
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
} |
120
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
sub _add_to_subs { |
122
|
0
|
|
|
0
|
|
|
my $sub = shift; |
123
|
0
|
0
|
|
|
|
|
if (! exists $Sub::Monkey::Subs->{$sub}) { |
124
|
0
|
|
|
|
|
|
$Sub::Monkey::Subs->{$sub} = {}; |
125
|
0
|
|
|
|
|
|
$Sub::Monkey::Subs->{$sub} = \&{$sub}; |
|
0
|
|
|
|
|
|
|
126
|
1
|
|
|
1
|
|
6
|
no strict 'refs'; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
162
|
|
127
|
0
|
|
|
|
|
|
*{__PACKAGE__ . "::$sub"} = \&{$sub}; |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
} |
129
|
|
|
|
|
|
|
} |
130
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
sub getscope { |
132
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
133
|
0
|
|
0
|
|
|
|
my $pkg = $self||scalar caller; |
134
|
0
|
|
|
|
|
|
return $pkg; |
135
|
|
|
|
|
|
|
} |
136
|
|
|
|
|
|
|
# modifiers |
137
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
=head2 instance |
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
Patch an instance method instead of an entire class |
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
# Pig.pm |
143
|
|
|
|
|
|
|
package Pig; |
144
|
|
|
|
|
|
|
sub new { return bless {}, shift; } |
145
|
|
|
|
|
|
|
sub says { print "Oink!\n"; } |
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
# test.pl |
148
|
|
|
|
|
|
|
package main; |
149
|
|
|
|
|
|
|
use Sub::Monkey qw; |
150
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
my $pig = Pig->new; |
152
|
|
|
|
|
|
|
my $pig2 = Pig->new; |
153
|
|
|
|
|
|
|
instance 'says' => sub { |
154
|
|
|
|
|
|
|
print "Meow\n"; |
155
|
|
|
|
|
|
|
}, |
156
|
|
|
|
|
|
|
$pig2; |
157
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
# only $pig2 will have its says method overridden |
159
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
=cut |
161
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
sub instance { |
163
|
0
|
|
|
0
|
1
|
|
my($method, $code, $instance) = @_; |
164
|
0
|
|
|
|
|
|
$Sub::Monkey::Iter++; |
165
|
0
|
|
|
|
|
|
my $package = ref($instance) . '::Sub::Monkey' . $Sub::Monkey::Iter; |
166
|
1
|
|
|
1
|
|
5
|
no strict 'refs'; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
286
|
|
167
|
0
|
|
|
|
|
|
@{$package . '::ISA'} = (ref($instance)); |
|
0
|
|
|
|
|
|
|
168
|
0
|
|
|
|
|
|
*{$package . '::' . $method} = $code; |
|
0
|
|
|
|
|
|
|
169
|
0
|
|
|
|
|
|
bless $_[2], $package; |
170
|
|
|
|
|
|
|
} |
171
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
=head2 original |
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
If you want to run the original version of a patched method, but not unpatch it right away |
175
|
|
|
|
|
|
|
you can use C to do so. It will run the old method before it was patched with any arguments you specify, but the actual method will still remain patched. |
176
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
after 'someMethod' => sub { |
178
|
|
|
|
|
|
|
print "Blah\n" |
179
|
|
|
|
|
|
|
}, |
180
|
|
|
|
|
|
|
qw; |
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
original('Foo', 'someMethod', qw); |
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
OR if you prefer, you can just call C(@args)> |
185
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
Sub::Monkey::Foo->someMethod('these', 'are', 'my', 'args); |
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
=cut |
189
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
sub original { |
191
|
0
|
|
|
0
|
1
|
|
my ($class, $method, @args) = @_; |
192
|
0
|
0
|
|
|
|
|
if (exists $Sub::Monkey::Subs->{"$class\::$method"}) { |
193
|
0
|
|
|
|
|
|
$Sub::Monkey::Subs->{"$class\::$method"}->(@args); |
194
|
|
|
|
|
|
|
} |
195
|
|
|
|
|
|
|
else { |
196
|
0
|
|
|
|
|
|
warn "Could not run original method '$method' in class $class. Not found"; |
197
|
0
|
|
|
|
|
|
return 0; |
198
|
|
|
|
|
|
|
} |
199
|
|
|
|
|
|
|
} |
200
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
=head2 override |
202
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
Overrides an already existing method. If the target method doesn't exist then Sub::Monkey will throw an error. |
204
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
override 'foo' => sub { |
206
|
|
|
|
|
|
|
return "foo bar"; |
207
|
|
|
|
|
|
|
}, |
208
|
|
|
|
|
|
|
qw; |
209
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
=cut |
211
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
sub override { |
213
|
0
|
|
|
0
|
1
|
|
my ($method, $code, $class) = @_; |
214
|
|
|
|
|
|
|
|
215
|
0
|
|
|
|
|
|
_check_init($class); |
216
|
|
|
|
|
|
|
|
217
|
0
|
0
|
|
|
|
|
_doh "You need to specify a class to which your overridden method exists" |
218
|
|
|
|
|
|
|
if ! $class; |
219
|
|
|
|
|
|
|
|
220
|
0
|
0
|
|
|
|
|
_doh "Method $method does not exist in $class. Perhaps you meant 'method' instead of 'override'?" |
221
|
|
|
|
|
|
|
if ! $class->can($method); |
222
|
|
|
|
|
|
|
|
223
|
0
|
|
|
|
|
|
_add_to_subs("$class\::$method"); |
224
|
1
|
|
|
1
|
|
6
|
no strict 'refs'; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
184
|
|
225
|
0
|
|
|
0
|
|
|
*$method = sub { $code->(@_) }; |
|
0
|
|
|
|
|
|
|
226
|
0
|
|
|
|
|
|
*{$class . "::$method"} = \*$method; |
|
0
|
|
|
|
|
|
|
227
|
|
|
|
|
|
|
} |
228
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
=head2 method |
230
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
Creates a brand new method in the target module. It will NOT allow you to override an existing one using this, and will throw an error. |
232
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
method 'active_customers' => sub { |
234
|
|
|
|
|
|
|
my $self = shift; |
235
|
|
|
|
|
|
|
return $self->search({ status => 'active' }); |
236
|
|
|
|
|
|
|
}, |
237
|
|
|
|
|
|
|
qw; |
238
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
=cut |
240
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
sub method { |
242
|
0
|
|
|
0
|
1
|
|
my ($method, $code, $class) = @_; |
243
|
|
|
|
|
|
|
|
244
|
0
|
|
|
|
|
|
_check_init($class); |
245
|
0
|
0
|
|
|
|
|
_doh "You need to specify a class to which your created method will be initialised" |
246
|
|
|
|
|
|
|
if ! $class; |
247
|
|
|
|
|
|
|
|
248
|
0
|
0
|
|
|
|
|
_doh "The method '$method' already exists in $class. Did you want to 'override' it instead?" |
249
|
|
|
|
|
|
|
if $class->can($method); |
250
|
|
|
|
|
|
|
|
251
|
0
|
|
|
|
|
|
_add_to_subs("$class\::$method"); |
252
|
1
|
|
|
1
|
|
5
|
no strict 'refs'; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
211
|
|
253
|
0
|
|
|
0
|
|
|
*$method = sub { $code->(@_); }; |
|
0
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
|
255
|
0
|
|
|
|
|
|
*{$class . "::$method"} = \*$method; |
|
0
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
} |
257
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
=head2 before |
259
|
|
|
|
|
|
|
|
260
|
|
|
|
|
|
|
Simply adds code to the target method before the original code is ran |
261
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
# Foo.pm |
263
|
|
|
|
|
|
|
package Foo; |
264
|
|
|
|
|
|
|
|
265
|
|
|
|
|
|
|
sub new { return bless {}, __PACKAGE__; } |
266
|
|
|
|
|
|
|
sub hello { print "Hello, $self->{name}; } |
267
|
|
|
|
|
|
|
1; |
268
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
# test.pl |
270
|
|
|
|
|
|
|
use Sub::Monkey qw; |
271
|
|
|
|
|
|
|
|
272
|
|
|
|
|
|
|
my $foo = Foo->new; |
273
|
|
|
|
|
|
|
before 'hello' => { |
274
|
|
|
|
|
|
|
my $self = shift; |
275
|
|
|
|
|
|
|
$self->{name} = 'World'; |
276
|
|
|
|
|
|
|
}, |
277
|
|
|
|
|
|
|
qw; |
278
|
|
|
|
|
|
|
|
279
|
|
|
|
|
|
|
print $foo->hello . "\n"; |
280
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
=cut |
282
|
|
|
|
|
|
|
|
283
|
|
|
|
|
|
|
sub before { |
284
|
0
|
|
|
0
|
1
|
|
my ($method, $code, $class) = @_; |
285
|
|
|
|
|
|
|
|
286
|
0
|
|
|
|
|
|
_check_init($class); |
287
|
0
|
|
|
|
|
|
my $full; |
288
|
0
|
0
|
|
|
|
|
if (ref($method) eq 'ARRAY') { |
289
|
0
|
|
|
|
|
|
for my $subname (@$method) { |
290
|
0
|
|
|
|
|
|
$full = "$class\::$subname"; |
291
|
0
|
|
|
|
|
|
my $alter_sub; |
292
|
|
|
|
|
|
|
my $new_code; |
293
|
0
|
|
|
|
|
|
my $old_code; |
294
|
0
|
0
|
|
|
|
|
die "Could not find $subname in the hierarchy for $class\n" |
295
|
|
|
|
|
|
|
if ! $class->can($subname); |
296
|
|
|
|
|
|
|
|
297
|
0
|
|
|
|
|
|
$old_code = \&{$full}; |
|
0
|
|
|
|
|
|
|
298
|
1
|
|
|
1
|
|
5
|
no strict 'refs'; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
153
|
|
299
|
|
|
|
|
|
|
*$subname = sub { |
300
|
0
|
|
|
0
|
|
|
$code->(@_); |
301
|
0
|
|
|
|
|
|
$old_code->(@_); |
302
|
0
|
|
|
|
|
|
}; |
303
|
|
|
|
|
|
|
|
304
|
0
|
|
|
|
|
|
_add_to_subs($full); |
305
|
0
|
|
|
|
|
|
*{$full} = \*$subname; |
|
0
|
|
|
|
|
|
|
306
|
|
|
|
|
|
|
} |
307
|
|
|
|
|
|
|
} |
308
|
|
|
|
|
|
|
else { |
309
|
0
|
|
|
|
|
|
$full = "$class\::$method"; |
310
|
0
|
|
|
|
|
|
my $alter_sub; |
311
|
|
|
|
|
|
|
my $new_code; |
312
|
0
|
|
|
|
|
|
my $old_code; |
313
|
0
|
0
|
|
|
|
|
die "Could not find $method in the hierarchy for $class\n" |
314
|
|
|
|
|
|
|
if ! $class->can($method); |
315
|
|
|
|
|
|
|
|
316
|
0
|
|
|
|
|
|
$old_code = \&{$full}; |
|
0
|
|
|
|
|
|
|
317
|
1
|
|
|
1
|
|
5
|
no strict 'refs'; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
201
|
|
318
|
|
|
|
|
|
|
*$method = sub { |
319
|
0
|
|
|
0
|
|
|
$code->(@_); |
320
|
0
|
|
|
|
|
|
$old_code->(@_); |
321
|
0
|
|
|
|
|
|
}; |
322
|
|
|
|
|
|
|
|
323
|
0
|
|
|
|
|
|
_add_to_subs($full); |
324
|
0
|
|
|
|
|
|
*{$full} = \*$method; |
|
0
|
|
|
|
|
|
|
325
|
|
|
|
|
|
|
} |
326
|
|
|
|
|
|
|
} |
327
|
|
|
|
|
|
|
|
328
|
|
|
|
|
|
|
=head2 after |
329
|
|
|
|
|
|
|
|
330
|
|
|
|
|
|
|
Basically the same as C, but appends the code specified to the END of the original |
331
|
|
|
|
|
|
|
|
332
|
|
|
|
|
|
|
=cut |
333
|
|
|
|
|
|
|
|
334
|
|
|
|
|
|
|
sub after { |
335
|
0
|
|
|
0
|
1
|
|
my ($method, $code, $class) = @_; |
336
|
|
|
|
|
|
|
|
337
|
0
|
|
|
|
|
|
_check_init($class); |
338
|
0
|
|
|
|
|
|
my $full = "$class\::$method"; |
339
|
0
|
|
|
|
|
|
my $alter_sub; |
340
|
|
|
|
|
|
|
my $new_code; |
341
|
0
|
|
|
|
|
|
my $old_code; |
342
|
0
|
0
|
|
|
|
|
die "Could not find $method in the hierarchy for $class\n" |
343
|
|
|
|
|
|
|
if ! $class->can($method); |
344
|
|
|
|
|
|
|
|
345
|
0
|
|
|
|
|
|
$old_code = \&{$full}; |
|
0
|
|
|
|
|
|
|
346
|
1
|
|
|
1
|
|
6
|
no strict 'refs'; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
176
|
|
347
|
|
|
|
|
|
|
*$method = sub { |
348
|
0
|
|
|
0
|
|
|
$old_code->(@_); |
349
|
0
|
|
|
|
|
|
$code->(@_); |
350
|
0
|
|
|
|
|
|
}; |
351
|
|
|
|
|
|
|
|
352
|
0
|
|
|
|
|
|
_add_to_subs($full); |
353
|
0
|
|
|
|
|
|
*{$full} = \*$method; |
|
0
|
|
|
|
|
|
|
354
|
|
|
|
|
|
|
} |
355
|
|
|
|
|
|
|
|
356
|
|
|
|
|
|
|
=head2 around |
357
|
|
|
|
|
|
|
|
358
|
|
|
|
|
|
|
Around gives the user a bit more control over the subroutine. When you create an around method the first argument will be the original method, the second is C<$self> and the third is any arguments passed to the original subroutine. In a away this allows you to control the flow of the entire subroutine. |
359
|
|
|
|
|
|
|
|
360
|
|
|
|
|
|
|
package MyFoo; |
361
|
|
|
|
|
|
|
|
362
|
|
|
|
|
|
|
sub greet { |
363
|
|
|
|
|
|
|
my ($self, $name) = @_; |
364
|
|
|
|
|
|
|
|
365
|
|
|
|
|
|
|
print "Hello, $name!\n"; |
366
|
|
|
|
|
|
|
} |
367
|
|
|
|
|
|
|
|
368
|
|
|
|
|
|
|
1; |
369
|
|
|
|
|
|
|
|
370
|
|
|
|
|
|
|
# test.pl |
371
|
|
|
|
|
|
|
|
372
|
|
|
|
|
|
|
use Sub::Monkey qw; |
373
|
|
|
|
|
|
|
|
374
|
|
|
|
|
|
|
# only call greet if any arguments were passed to MyFoo->greet() |
375
|
|
|
|
|
|
|
around 'greet' => sub { |
376
|
|
|
|
|
|
|
my $method = shift; |
377
|
|
|
|
|
|
|
my $self = shift; |
378
|
|
|
|
|
|
|
|
379
|
|
|
|
|
|
|
$self->$method(@_) |
380
|
|
|
|
|
|
|
if @_; |
381
|
|
|
|
|
|
|
}, |
382
|
|
|
|
|
|
|
qw; |
383
|
|
|
|
|
|
|
|
384
|
|
|
|
|
|
|
=cut |
385
|
|
|
|
|
|
|
|
386
|
|
|
|
|
|
|
sub around { |
387
|
0
|
|
|
0
|
1
|
|
my ($method, $code, $class) = @_; |
388
|
|
|
|
|
|
|
|
389
|
0
|
|
|
|
|
|
my $full = "$class\::$method"; |
390
|
0
|
0
|
|
|
|
|
die "Could not find $method in the hierarchy for $class\n" |
391
|
|
|
|
|
|
|
if ! $class->can($method); |
392
|
|
|
|
|
|
|
|
393
|
0
|
|
|
|
|
|
my $old_code = \&{$full}; |
|
0
|
|
|
|
|
|
|
394
|
1
|
|
|
1
|
|
6
|
no strict 'refs'; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
206
|
|
395
|
|
|
|
|
|
|
*$method = sub { |
396
|
0
|
|
|
0
|
|
|
$code->($old_code, @_); |
397
|
0
|
|
|
|
|
|
}; |
398
|
|
|
|
|
|
|
|
399
|
0
|
|
|
|
|
|
_add_to_subs($full); |
400
|
0
|
|
|
|
|
|
*{$full} = \*$method; |
|
0
|
|
|
|
|
|
|
401
|
|
|
|
|
|
|
} |
402
|
|
|
|
|
|
|
|
403
|
|
|
|
|
|
|
=head2 unpatch |
404
|
|
|
|
|
|
|
|
405
|
|
|
|
|
|
|
Undoes any modifications made to patched methods, restoring it to its original state. |
406
|
|
|
|
|
|
|
|
407
|
|
|
|
|
|
|
override 'this' => sub { print "Blah\n"; }, qw; |
408
|
|
|
|
|
|
|
|
409
|
|
|
|
|
|
|
unpatch 'this' => 'FooClass'; |
410
|
|
|
|
|
|
|
|
411
|
|
|
|
|
|
|
=cut |
412
|
|
|
|
|
|
|
|
413
|
|
|
|
|
|
|
sub unpatch { |
414
|
0
|
|
|
0
|
1
|
|
my ($method, $class) = @_; |
415
|
|
|
|
|
|
|
|
416
|
0
|
|
|
|
|
|
my $sub = "$class\::$method"; |
417
|
|
|
|
|
|
|
|
418
|
0
|
0
|
|
|
|
|
if (! exists $Sub::Monkey::Subs->{$sub}) { |
419
|
0
|
|
|
|
|
|
warn "Could not restore $method in $class because I have no recollection of it"; |
420
|
0
|
|
|
|
|
|
return 0; |
421
|
|
|
|
|
|
|
} |
422
|
|
|
|
|
|
|
|
423
|
1
|
|
|
1
|
|
6
|
no strict 'refs'; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
58
|
|
424
|
0
|
|
|
|
|
|
*{$sub} = $Sub::Monkey::Subs->{$sub}; |
|
0
|
|
|
|
|
|
|
425
|
|
|
|
|
|
|
} |
426
|
|
|
|
|
|
|
|
427
|
|
|
|
|
|
|
=head1 AUTHOR |
428
|
|
|
|
|
|
|
|
429
|
|
|
|
|
|
|
Brad Haywood |
430
|
|
|
|
|
|
|
|
431
|
|
|
|
|
|
|
=head1 LICENSE |
432
|
|
|
|
|
|
|
|
433
|
|
|
|
|
|
|
You may distribute this code under the same terms as Perl itself. |
434
|
|
|
|
|
|
|
|
435
|
|
|
|
|
|
|
=cut |
436
|
|
|
|
|
|
|
|
437
|
|
|
|
|
|
|
1; |