1Moose::Manual::MethodMoUdsiefrieCrosn(t3r)ibuted Perl DoMcouomseen:t:aMtainounal::MethodModifiers(3)
2
3
4
6 Moose::Manual::MethodModifiers - Moose's method modifiers
7
9 version 2.2015
10
12 Moose provides a feature called "method modifiers". You can also think
13 of these as "hooks" or "advice".
14
15 It's probably easiest to understand this feature with a few examples:
16
17 package Example;
18
19 use Moose;
20
21 sub foo {
22 print " foo\n";
23 }
24
25 before 'foo' => sub { print "about to call foo\n"; };
26 after 'foo' => sub { print "just called foo\n"; };
27
28 around 'foo' => sub {
29 my $orig = shift;
30 my $self = shift;
31
32 print " I'm around foo\n";
33
34 $self->$orig(@_);
35
36 print " I'm still around foo\n";
37 };
38
39 Now if I call "Example->new->foo" I'll get the following output:
40
41 about to call foo
42 I'm around foo
43 foo
44 I'm still around foo
45 just called foo
46
47 You probably could have figured that out from the names "before",
48 "after", and "around".
49
50 Also, as you can see, the before modifiers come before around
51 modifiers, and after modifiers come last.
52
53 When there are multiple modifiers of the same type, the before and
54 around modifiers run from the last added to the first, and after
55 modifiers run from first added to last:
56
57 before 2
58 before 1
59 around 2
60 around 1
61 primary
62 around 1
63 around 2
64 after 1
65 after 2
66
68 Method modifiers have many uses. They are often used in roles to alter
69 the behavior of methods in the classes that consume the role. See
70 Moose::Manual::Roles for more information about roles.
71
72 Since modifiers are mostly useful in roles, some of the examples below
73 are a bit artificial. They're intended to give you an idea of how
74 modifiers work, but may not be the most natural usage.
75
77 Method modifiers can be used to add behavior to methods without
78 modifying the definition of those methods.
79
80 Before and after Modifiers
81 Method modifiers can be used to add behavior to a method that Moose
82 generates for you, such as an attribute accessor:
83
84 has 'size' => ( is => 'rw' );
85
86 before 'size' => sub {
87 my $self = shift;
88
89 if (@_) {
90 Carp::cluck('Someone is setting size');
91 }
92 };
93
94 Another use for the before modifier would be to do some sort of
95 prechecking on a method call. For example:
96
97 before 'size' => sub {
98 my $self = shift;
99
100 die 'Cannot set size while the person is growing'
101 if @_ && $self->is_growing;
102 };
103
104 This lets us implement logical checks that don't make sense as type
105 constraints. In particular, they're useful for defining logical rules
106 about an object's state changes.
107
108 Similarly, an after modifier could be used for logging an action that
109 was taken.
110
111 Note that the return values of both before and after modifiers are
112 ignored.
113
114 Around modifiers
115 An around modifier is more powerful than either a before or after
116 modifier. It can modify the arguments being passed to the original
117 method, and you can even decide to simply not call the original method
118 at all. You can also modify the return value with an around modifier.
119
120 An around modifier receives the original method as its first argument,
121 then the object, and finally any arguments passed to the method.
122
123 around 'size' => sub {
124 my $orig = shift;
125 my $self = shift;
126
127 return $self->$orig()
128 unless @_;
129
130 my $size = shift;
131 $size = $size / 2
132 if $self->likes_small_things();
133
134 return $self->$orig($size);
135 };
136
137 Wrapping multiple methods at once
138 "before", "after", and "around" can also modify multiple methods at
139 once. The simplest example of this is passing them as a list:
140
141 before [qw(foo bar baz)] => sub {
142 warn "something is being called!";
143 };
144
145 This will add a "before" modifier to each of the "foo", "bar", and
146 "baz" methods in the current class, just as though a separate call to
147 "before" was made for each of them. The list can be passed either as a
148 bare list, or as an arrayref. Note that the name of the function being
149 modified isn't passed in in any way; this syntax is only intended for
150 cases where the function being modified doesn't actually matter. If the
151 function name does matter, use something like this:
152
153 for my $func (qw(foo bar baz)) {
154 before $func => sub {
155 warn "$func was called!";
156 };
157 }
158
159 Using regular expressions to select methods to wrap
160 In addition, you can specify a regular expression to indicate the
161 methods to wrap, like so:
162
163 after qr/^command_/ => sub {
164 warn "got a command";
165 };
166
167 This will match the regular expression against each method name
168 returned by "get_method_list" in Class::MOP::Class, and add a modifier
169 to each one that matches. The same caveats apply as above.
170
171 Using regular expressions to determine methods to wrap is quite a bit
172 more powerful than the previous alternatives, but it's also quite a bit
173 more dangerous. Bear in mind that if your regular expression matches
174 certain Perl and Moose reserved method names with a special meaning to
175 Moose or Perl, such as "meta", "new", "BUILD", "DESTROY", "AUTOLOAD",
176 etc, this could cause unintended (and hard to debug) problems and is
177 best avoided.
178
179 Execution order of method modifiers and inheritance
180 When both a superclass and an inheriting class have the same method
181 modifiers, the method modifiers of the inheriting class are wrapped
182 around the method modifiers of the superclass, as the following example
183 illustrates:
184
185 Here is the parent class:
186
187 package Superclass;
188 use Moose;
189 sub rant { printf " RANTING!\n" }
190 before 'rant' => sub { printf " In %s before\n", __PACKAGE__ };
191 after 'rant' => sub { printf " In %s after\n", __PACKAGE__ };
192 around 'rant' => sub {
193 my $orig = shift;
194 my $self = shift;
195 printf " In %s around before calling original\n", __PACKAGE__;
196 $self->$orig;
197 printf " In %s around after calling original\n", __PACKAGE__;
198 };
199 1;
200
201 And the child class:
202
203 package Subclass;
204 use Moose;
205 extends 'Superclass';
206 before 'rant' => sub { printf "In %s before\n", __PACKAGE__ };
207 after 'rant' => sub { printf "In %s after\n", __PACKAGE__ };
208 around 'rant' => sub {
209 my $orig = shift;
210 my $self = shift;
211 printf " In %s around before calling original\n", __PACKAGE__;
212 $self->$orig;
213 printf " In %s around after calling original\n", __PACKAGE__;
214 };
215 1;
216
217 And here's the output when we call the wrapped method ("Child->rant"):
218
219 % perl -MSubclass -e 'Subclass->new->rant'
220
221 In Subclass before
222 In Subclass around before calling original
223 In Superclass before
224 In Superclass around before calling original
225 RANTING!
226 In Superclass around after calling original
227 In Superclass after
228 In Subclass around after calling original
229 In Subclass after
230
232 Augment and inner are two halves of the same feature. The augment
233 modifier provides a sort of inverted subclassing. You provide part of
234 the implementation in a superclass, and then document that subclasses
235 are expected to provide the rest.
236
237 The superclass calls "inner()", which then calls the "augment" modifier
238 in the subclass:
239
240 package Document;
241
242 use Moose;
243
244 sub as_xml {
245 my $self = shift;
246
247 my $xml = "<document>\n";
248 $xml .= inner();
249 $xml .= "</document>\n";
250
251 return $xml;
252 }
253
254 Using "inner()" in this method makes it possible for one or more
255 subclasses to then augment this method with their own specific
256 implementation:
257
258 package Report;
259
260 use Moose;
261
262 extends 'Document';
263
264 augment 'as_xml' => sub {
265 my $self = shift;
266
267 my $xml = " <report>\n";
268 $xml .= inner();
269 $xml .= " </report>\n";
270
271 return $xml;
272 };
273
274 When we call "as_xml" on a Report object, we get something like this:
275
276 <document>
277 <report>
278 </report>
279 </document>
280
281 But we also called "inner()" in "Report", so we can continue
282 subclassing and adding more content inside the document:
283
284 package Report::IncomeAndExpenses;
285
286 use Moose;
287
288 extends 'Report';
289
290 augment 'as_xml' => sub {
291 my $self = shift;
292
293 my $xml = ' <income>' . $self->income . '</income>';
294 $xml .= "\n";
295 $xml .= ' <expenses>' . $self->expenses . '</expenses>';
296 $xml .= "\n";
297
298 $xml .= inner() || q{};
299
300 return $xml;
301 };
302
303 Now our report has some content:
304
305 <document>
306 <report>
307 <income>$10</income>
308 <expenses>$8</expenses>
309 </report>
310 </document>
311
312 What makes this combination of "augment" and "inner()" special is that
313 it allows us to have methods which are called from parent (least
314 specific) to child (most specific). This inverts the normal inheritance
315 pattern.
316
317 Note that in "Report::IncomeAndExpenses" we call "inner()" again. If
318 the object is an instance of "Report::IncomeAndExpenses" then this call
319 is a no-op, and just returns false. It's a good idea to always call
320 "inner()" to allow for future subclassing.
321
323 Finally, Moose provides some simple sugar for Perl's built-in method
324 overriding scheme. If you want to override a method from a parent
325 class, you can do this with "override":
326
327 package Employee;
328
329 use Moose;
330
331 extends 'Person';
332
333 has 'job_title' => ( is => 'rw' );
334
335 override 'display_name' => sub {
336 my $self = shift;
337
338 return super() . q{, } . $self->job_title();
339 };
340
341 The call to "super()" is almost the same as calling
342 "$self->SUPER::display_name". The difference is that the arguments
343 passed to the superclass's method will always be the same as the ones
344 passed to the method modifier, and cannot be changed.
345
346 All arguments passed to "super()" are ignored, as are any changes made
347 to @_ before "super()" is called.
348
350 Because all of these method modifiers are implemented as Perl
351 functions, you must always end the modifier declaration with a semi-
352 colon:
353
354 after 'foo' => sub { };
355
357 An exception thrown in a "before" modifier will prevent the method it
358 modifies from being called at all. An exception in an "around" modifier
359 may prevent the modified method from being called, depending on how the
360 "around" modifier is structured. An exception in an "after" modifier
361 obviously cannot prevent the method it wraps from being called.
362
363 Both "override" and "augment" are similar to "around" in that they can
364 decide whether or not to call the method they modify before or after
365 throwing an exception.
366
367 From the caller's perspective, an exception in a method modifier will
368 look like the method it called threw an exception. However, method
369 modifiers are just standard Perl subroutines. This means that they end
370 up on the stack in stack traces as an additional frame.
371
373 These method modification features do not work well with multiple
374 inheritance, due to how method resolution is performed in Perl.
375 Experiment with a test program to ensure your class hierarchy works as
376 expected, or more preferably, don't use multiple inheritance (roles can
377 help with this)!
378
380 • Stevan Little <stevan@cpan.org>
381
382 • Dave Rolsky <autarch@urth.org>
383
384 • Jesse Luehrs <doy@cpan.org>
385
386 • Shawn M Moore <sartak@cpan.org>
387
388 • יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org>
389
390 • Karen Etheridge <ether@cpan.org>
391
392 • Florian Ragwitz <rafl@debian.org>
393
394 • Hans Dieter Pearcey <hdp@cpan.org>
395
396 • Chris Prather <chris@prather.org>
397
398 • Matt S Trout <mstrout@cpan.org>
399
401 This software is copyright (c) 2006 by Infinity Interactive, Inc.
402
403 This is free software; you can redistribute it and/or modify it under
404 the same terms as the Perl 5 programming language system itself.
405
406
407
408perl v5.34.0 2021-07-22 Moose::Manual::MethodModifiers(3)