Commit | Line | Data |
92cd015f |
1 | =pod |
2 | |
3 | =head1 NAME |
4 | |
d67ce58f |
5 | Moose::Manual::MethodModifiers - Moose's method modifiers |
92cd015f |
6 | |
7 | =head1 WHAT IS A METHOD MODIFIER? |
8 | |
646e0fb0 |
9 | Moose provides a feature called "method modifiers". You can also think |
10 | of these as "hooks" or "advice". |
92cd015f |
11 | |
12 | It's probably easiest to understand this feature with a few examples: |
13 | |
14 | package Example; |
15 | |
16 | use Moose; |
17 | |
18 | sub foo { |
08f950aa |
19 | print "foo\n"; |
92cd015f |
20 | } |
21 | |
22 | before 'foo' => sub { print "about to call foo\n"; }; |
08f950aa |
23 | after 'foo' => sub { print "just called foo\n"; }; |
92cd015f |
24 | |
25 | around 'foo' => sub { |
26 | my $orig = shift; |
27 | my $self = shift; |
28 | |
29 | print "I'm around foo\n"; |
30 | |
31 | $self->$orig(@_); |
32 | |
33 | print "I'm still around foo\n"; |
34 | }; |
35 | |
36 | Now if I call C<< Example->new->foo >> I'll get the following output: |
37 | |
38 | about to call foo |
39 | I'm around foo |
40 | foo |
41 | I'm still around foo |
42 | just called foo |
43 | |
44 | You probably could have figured that out from the names "before", |
45 | "after", and "around". |
46 | |
47 | Also, as you can see, the before modifiers come before around |
48 | modifiers, and after modifiers come last. |
49 | |
50 | When there are multiple modifiers of the same type, the before and |
51 | around modifiers run from the last added to the first, and after |
52 | modifiers run from first added to last: |
53 | |
54 | before 2 |
55 | before 1 |
56 | around 2 |
57 | around 1 |
58 | primary |
59 | around 1 |
60 | around 2 |
61 | after 1 |
62 | after 2 |
63 | |
64 | =head1 WHY USE THEM? |
65 | |
66 | Method modifiers have many uses. One very common use is in roles. This |
67 | lets roles alter the behavior of methods in the classes that use |
646e0fb0 |
68 | them. See L<Moose::Manual::Roles> for more information about roles. |
92cd015f |
69 | |
dab94063 |
70 | Since modifiers are mostly useful in roles, some of the examples below |
71 | are a bit artificial. They're intended to give you an idea of how |
72 | modifiers work, but may not be the most natural usage. |
92cd015f |
73 | |
74 | =head1 BEFORE, AFTER, AND AROUND |
75 | |
dab94063 |
76 | Method modifiers can be used to add behavior to a method that Moose |
77 | generates for you, such as an attribute accessor: |
92cd015f |
78 | |
79 | has 'size' => ( is => 'rw' ); |
80 | |
81 | before 'size' => sub { |
82 | my $self = shift; |
83 | |
84 | if (@_) { |
85 | Carp::cluck('Someone is setting size'); |
86 | } |
87 | }; |
88 | |
89 | Another use for the before modifier would be to do some sort of |
6549b0d1 |
90 | prechecking on a method call. For example: |
92cd015f |
91 | |
92 | before 'size' => sub { |
93 | my $self = shift; |
94 | |
95 | die 'Cannot set size while the person is growing' |
96 | if @_ && $self->is_growing; |
97 | }; |
98 | |
646e0fb0 |
99 | This lets us implement logical checks that don't make sense as type |
100 | constraints. In particular, they're useful for defining logical rules |
101 | about an object's state changes. |
92cd015f |
102 | |
103 | Similarly, an after modifier could be used for logging an action that |
104 | was taken. |
105 | |
106 | Note that the return values of both before and after modifiers are |
107 | ignored. |
108 | |
109 | An around modifier is a bit more powerful than either a before or |
646e0fb0 |
110 | after modifier. It can modify the arguments being passed to the |
111 | original method, and you can even decide to simply not call the |
dab94063 |
112 | original method at all. You can also modify the return value with an |
113 | around modifier. |
92cd015f |
114 | |
115 | An around modifier receives the original method as its first argument, |
116 | I<then> the object, and finally any arguments passed to the method. |
117 | |
118 | around 'size' => sub { |
119 | my $orig = shift; |
120 | my $self = shift; |
121 | |
122 | return $self->$orig() |
123 | unless @_; |
124 | |
125 | my $size = shift; |
126 | $size = $size / 2 |
127 | if $self->likes_small_things(); |
128 | |
129 | return $self->$orig($size); |
130 | }; |
131 | |
78946cf8 |
132 | C<before>, C<after>, and C<around> can also modify multiple methods |
133 | at once. The simplest example of this is passing them as a list: |
134 | |
135 | before qw(foo bar baz) => sub { |
136 | warn "something is being called!"; |
137 | }; |
138 | |
139 | This will add a C<before> modifier to each of the C<foo>, C<bar>, |
140 | and C<baz> methods in the current class, just as though a separate |
141 | call to C<before> was made for each of them. The list can be passed |
142 | either as a bare list, or as an arrayref. Note that the name of the |
143 | function being modified isn't passed in in any way; this syntax is |
144 | only intended for cases where the function being modified doesn't |
145 | actually matter. If the function name does matter, something like: |
146 | |
147 | for my $func (qw(foo bar baz)) { |
148 | before $func => sub { |
149 | warn "$func was called!"; |
150 | }; |
151 | } |
152 | |
153 | would be more appropriate. |
154 | |
155 | In addition, you can specify a regular expression to indicate the |
156 | methods to wrap, like so: |
157 | |
158 | after qr/^command_/ => sub { |
159 | warn "got a command"; |
160 | }; |
161 | |
162 | This will match the regular expression against each method name |
163 | returned by L<Class::MOP::Class/get_method_list>, and add a modifier |
164 | to each one that matches. The same caveats apply as above, regarding |
165 | not being given the name of the method being modified. Using regular |
166 | expressions to determine methods to wrap is quite a bit more powerful |
167 | than the previous alternatives, but it's also quite a bit more |
168 | dangerous. In particular, you should make sure to avoid wrapping |
169 | methods with a special meaning to Moose or Perl, such as C<meta>, |
170 | C<BUILD>, C<DESTROY>, C<AUTOLOAD>, etc., as this could cause |
171 | unintended (and hard to debug) problems. |
172 | |
92cd015f |
173 | =head1 INNER AND AUGMENT |
174 | |
175 | Augment and inner are two halves of the same feature. The augment |
176 | modifier provides a sort of inverted subclassing. You provide part of |
177 | the implementation in a superclass, and then document that subclasses |
178 | are expected to provide the rest. |
179 | |
180 | The superclass calls C<inner()>, which then calls the C<augment> |
181 | modifier in the subclass: |
182 | |
183 | package Document; |
184 | |
185 | use Moose; |
186 | |
187 | sub as_xml { |
188 | my $self = shift; |
189 | |
190 | my $xml = "<document>\n"; |
191 | $xml .= inner(); |
192 | $xml .= "</document>\n"; |
193 | |
194 | return $xml; |
195 | } |
196 | |
197 | Using C<inner()> in this method makes it possible for one or more |
198 | subclasses to then augment this method with their own specific |
199 | implementation: |
200 | |
201 | package Report; |
202 | |
203 | use Moose; |
204 | |
205 | extends 'Document'; |
206 | |
207 | augment 'as_xml' => sub { |
208 | my $self = shift; |
209 | |
210 | my $xml = "<report>\n"; |
211 | $xml .= inner(); |
212 | $xml .= "</report>\n"; |
213 | |
214 | return $xml; |
215 | }; |
216 | |
217 | When we call C<as_xml> on a Report object, we get something like this: |
218 | |
219 | <document> |
220 | <report> |
221 | </report> |
222 | </document> |
223 | |
224 | But we also called C<inner()> in C<Report>, so we can continue |
225 | subclassing and adding more content inside the document: |
226 | |
227 | package Report::IncomeAndExpenses; |
228 | |
229 | use Moose; |
230 | |
231 | extends 'Report'; |
232 | |
233 | augment 'as_xml' => sub { |
234 | my $self = shift; |
235 | |
236 | my $xml = '<income>' . $self->income . '</income>'; |
237 | $xml .= "\n"; |
ec4161a5 |
238 | $xml .= '<expenses>' . $self->expenses . '</expenses>'; |
92cd015f |
239 | $xml .= "\n"; |
240 | |
241 | $xml .= inner() || q{}; |
242 | |
243 | return $xml; |
244 | }; |
245 | |
246 | Now our report has some content: |
247 | |
248 | <document> |
249 | <report> |
250 | <income>$10</income> |
251 | <expenses>$8</expenses> |
252 | </report> |
253 | </document> |
254 | |
255 | What makes this combination of C<augment> and C<inner()> special is |
ce5e6e3c |
256 | that it allows us to have methods which are called from parent (least |
646e0fb0 |
257 | specific) to child (most specific). This inverts the normal |
258 | inheritance pattern. |
92cd015f |
259 | |
260 | Note that in C<Report::IncomeAndExpenses> we call C<inner()> again. If |
261 | the object is an instance of C<Report::IncomeAndExpenses> then this |
262 | call is a no-op, and just returns false. |
263 | |
264 | =head1 OVERRIDE AND SUPER |
265 | |
266 | Finally, Moose provides some simple sugar for Perl's built-in method |
267 | overriding scheme. If you want to override a method from a parent |
268 | class, you can do this with C<override>: |
269 | |
270 | package Employee; |
271 | |
272 | use Moose; |
273 | |
274 | extends 'Person'; |
275 | |
276 | has 'job_title' => ( is => 'rw' ); |
277 | |
278 | override 'display_name' => sub { |
279 | my $self = shift; |
280 | |
281 | return super() . q{, } . $self->title(); |
282 | }; |
283 | |
284 | The call to C<super()> is almost the same as calling C<< |
285 | $self->SUPER::display_name >>. The difference is that the arguments |
286 | passed to the superclass's method will always be the same as the ones |
287 | passed to the method modifier, and cannot be changed. |
288 | |
289 | All arguments passed to C<super()> are ignored, as are any changes |
290 | made to C<@_> before C<super()> is called. |
291 | |
292 | =head1 SEMI-COLONS |
293 | |
294 | Because all of these method modifiers are implemented as Perl |
295 | functions, you must always end the modifier declaration with a |
296 | semi-colon: |
297 | |
298 | after 'foo' => sub { }; |
299 | |
300 | =head1 AUTHOR |
301 | |
302 | Dave Rolsky E<lt>autarch@urth.orgE<gt> |
303 | |
304 | =head1 COPYRIGHT AND LICENSE |
305 | |
646e0fb0 |
306 | Copyright 2008-2009 by Infinity Interactive, Inc. |
92cd015f |
307 | |
308 | L<http://www.iinteractive.com> |
309 | |
310 | This library is free software; you can redistribute it and/or modify |
311 | it under the same terms as Perl itself. |
312 | |
313 | =cut |