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.2203
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 subclassing
282 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 it
313 allows us to have methods which are called from parent (least specific)
314 to child (most specific). This inverts the normal inheritance pattern.
315
316 Note that in "Report::IncomeAndExpenses" we call inner() again. If the
317 object is an instance of "Report::IncomeAndExpenses" then this call is
318 a no-op, and just returns false. It's a good idea to always call
319 inner() to allow for future subclassing.
320
322 Finally, Moose provides some simple sugar for Perl's built-in method
323 overriding scheme. If you want to override a method from a parent
324 class, you can do this with "override":
325
326 package Employee;
327
328 use Moose;
329
330 extends 'Person';
331
332 has 'job_title' => ( is => 'rw' );
333
334 override 'display_name' => sub {
335 my $self = shift;
336
337 return super() . q{, } . $self->job_title();
338 };
339
340 The call to super() is almost the same as calling
341 "$self->SUPER::display_name". The difference is that the arguments
342 passed to the superclass's method will always be the same as the ones
343 passed to the method modifier, and cannot be changed.
344
345 All arguments passed to super() are ignored, as are any changes made to
346 @_ before super() is called.
347
349 Because all of these method modifiers are implemented as Perl
350 functions, you must always end the modifier declaration with a semi-
351 colon:
352
353 after 'foo' => sub { };
354
356 An exception thrown in a "before" modifier will prevent the method it
357 modifies from being called at all. An exception in an "around" modifier
358 may prevent the modified method from being called, depending on how the
359 "around" modifier is structured. An exception in an "after" modifier
360 obviously cannot prevent the method it wraps from being called.
361
362 Both "override" and "augment" are similar to "around" in that they can
363 decide whether or not to call the method they modify before or after
364 throwing an exception.
365
366 From the caller's perspective, an exception in a method modifier will
367 look like the method it called threw an exception. However, method
368 modifiers are just standard Perl subroutines. This means that they end
369 up on the stack in stack traces as an additional frame.
370
372 These method modification features do not work well with multiple
373 inheritance, due to how method resolution is performed in Perl.
374 Experiment with a test program to ensure your class hierarchy works as
375 expected, or more preferably, don't use multiple inheritance (roles can
376 help with this)!
377
379 • Stevan Little <stevan@cpan.org>
380
381 • Dave Rolsky <autarch@urth.org>
382
383 • Jesse Luehrs <doy@cpan.org>
384
385 • Shawn M Moore <sartak@cpan.org>
386
387 • יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org>
388
389 • Karen Etheridge <ether@cpan.org>
390
391 • Florian Ragwitz <rafl@debian.org>
392
393 • Hans Dieter Pearcey <hdp@cpan.org>
394
395 • Chris Prather <chris@prather.org>
396
397 • Matt S Trout <mstrout@cpan.org>
398
400 This software is copyright (c) 2006 by Infinity Interactive, Inc.
401
402 This is free software; you can redistribute it and/or modify it under
403 the same terms as the Perl 5 programming language system itself.
404
405
406
407perl v5.36.0 2023-02-06 Moose::Manual::MethodModifiers(3)