Commit | Line | Data |
daa0fd7d |
1 | package Moose::Manual::MethodModifiers; |
2 | |
3 | # ABSTRACT: Moose's method modifiers |
92cd015f |
4 | |
daa0fd7d |
5 | __END__ |
92cd015f |
6 | |
daa0fd7d |
7 | =pod |
92cd015f |
8 | |
9 | =head1 WHAT IS A METHOD MODIFIER? |
10 | |
646e0fb0 |
11 | Moose provides a feature called "method modifiers". You can also think |
12 | of these as "hooks" or "advice". |
92cd015f |
13 | |
14 | It's probably easiest to understand this feature with a few examples: |
15 | |
16 | package Example; |
17 | |
18 | use Moose; |
19 | |
20 | sub foo { |
909103e1 |
21 | print " foo\n"; |
92cd015f |
22 | } |
23 | |
24 | before 'foo' => sub { print "about to call foo\n"; }; |
08f950aa |
25 | after 'foo' => sub { print "just called foo\n"; }; |
92cd015f |
26 | |
27 | around 'foo' => sub { |
28 | my $orig = shift; |
29 | my $self = shift; |
30 | |
909103e1 |
31 | print " I'm around foo\n"; |
92cd015f |
32 | |
33 | $self->$orig(@_); |
34 | |
909103e1 |
35 | print " I'm still around foo\n"; |
92cd015f |
36 | }; |
37 | |
38 | Now if I call C<< Example->new->foo >> I'll get the following output: |
39 | |
40 | about to call foo |
909103e1 |
41 | I'm around foo |
42 | foo |
43 | I'm still around foo |
92cd015f |
44 | just called foo |
45 | |
46 | You probably could have figured that out from the names "before", |
47 | "after", and "around". |
48 | |
49 | Also, as you can see, the before modifiers come before around |
50 | modifiers, and after modifiers come last. |
51 | |
52 | When there are multiple modifiers of the same type, the before and |
53 | around modifiers run from the last added to the first, and after |
54 | modifiers run from first added to last: |
55 | |
56 | before 2 |
57 | before 1 |
58 | around 2 |
59 | around 1 |
60 | primary |
61 | around 1 |
62 | around 2 |
63 | after 1 |
64 | after 2 |
65 | |
66 | =head1 WHY USE THEM? |
67 | |
909103e1 |
68 | Method modifiers have many uses. They are often used in roles to alter the |
69 | behavior of methods in the classes that consume the role. See |
70 | L<Moose::Manual::Roles> for more information about roles. |
92cd015f |
71 | |
dab94063 |
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. |
92cd015f |
75 | |
76 | =head1 BEFORE, AFTER, AND AROUND |
77 | |
dab94063 |
78 | Method modifiers can be used to add behavior to a method that Moose |
79 | generates for you, such as an attribute accessor: |
92cd015f |
80 | |
81 | has 'size' => ( is => 'rw' ); |
82 | |
83 | before 'size' => sub { |
84 | my $self = shift; |
85 | |
86 | if (@_) { |
87 | Carp::cluck('Someone is setting size'); |
88 | } |
89 | }; |
90 | |
91 | Another use for the before modifier would be to do some sort of |
6549b0d1 |
92 | prechecking on a method call. For example: |
92cd015f |
93 | |
94 | before 'size' => sub { |
95 | my $self = shift; |
96 | |
97 | die 'Cannot set size while the person is growing' |
98 | if @_ && $self->is_growing; |
99 | }; |
100 | |
646e0fb0 |
101 | This lets us implement logical checks that don't make sense as type |
102 | constraints. In particular, they're useful for defining logical rules |
103 | about an object's state changes. |
92cd015f |
104 | |
105 | Similarly, an after modifier could be used for logging an action that |
106 | was taken. |
107 | |
108 | Note that the return values of both before and after modifiers are |
109 | ignored. |
110 | |
909103e1 |
111 | An around modifier is more powerful than either a before or |
646e0fb0 |
112 | after modifier. It can modify the arguments being passed to the |
113 | original method, and you can even decide to simply not call the |
dab94063 |
114 | original method at all. You can also modify the return value with an |
115 | around modifier. |
92cd015f |
116 | |
117 | An around modifier receives the original method as its first argument, |
118 | I<then> the object, and finally any arguments passed to the method. |
119 | |
120 | around 'size' => sub { |
121 | my $orig = shift; |
122 | my $self = shift; |
123 | |
124 | return $self->$orig() |
125 | unless @_; |
126 | |
127 | my $size = shift; |
128 | $size = $size / 2 |
129 | if $self->likes_small_things(); |
130 | |
131 | return $self->$orig($size); |
132 | }; |
133 | |
78946cf8 |
134 | C<before>, C<after>, and C<around> can also modify multiple methods |
135 | at once. The simplest example of this is passing them as a list: |
136 | |
909103e1 |
137 | before [qw(foo bar baz)] => sub { |
78946cf8 |
138 | warn "something is being called!"; |
139 | }; |
140 | |
141 | This will add a C<before> modifier to each of the C<foo>, C<bar>, |
142 | and C<baz> methods in the current class, just as though a separate |
143 | call to C<before> was made for each of them. The list can be passed |
144 | either as a bare list, or as an arrayref. Note that the name of the |
145 | function being modified isn't passed in in any way; this syntax is |
146 | only intended for cases where the function being modified doesn't |
909103e1 |
147 | actually matter. If the function name does matter, use something like this: |
78946cf8 |
148 | |
149 | for my $func (qw(foo bar baz)) { |
150 | before $func => sub { |
151 | warn "$func was called!"; |
152 | }; |
153 | } |
154 | |
78946cf8 |
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 |
909103e1 |
164 | to each one that matches. The same caveats apply as above. Using regular |
78946cf8 |
165 | expressions to determine methods to wrap is quite a bit more powerful |
166 | than the previous alternatives, but it's also quite a bit more |
167 | dangerous. In particular, you should make sure to avoid wrapping |
909103e1 |
168 | methods with a special meaning to Moose or Perl, such as C<meta>, C<new>, |
78946cf8 |
169 | C<BUILD>, C<DESTROY>, C<AUTOLOAD>, etc., as this could cause |
170 | unintended (and hard to debug) problems. |
171 | |
92cd015f |
172 | =head1 INNER AND AUGMENT |
173 | |
174 | Augment and inner are two halves of the same feature. The augment |
175 | modifier provides a sort of inverted subclassing. You provide part of |
176 | the implementation in a superclass, and then document that subclasses |
177 | are expected to provide the rest. |
178 | |
179 | The superclass calls C<inner()>, which then calls the C<augment> |
180 | modifier in the subclass: |
181 | |
182 | package Document; |
183 | |
184 | use Moose; |
185 | |
186 | sub as_xml { |
187 | my $self = shift; |
188 | |
189 | my $xml = "<document>\n"; |
190 | $xml .= inner(); |
191 | $xml .= "</document>\n"; |
192 | |
193 | return $xml; |
194 | } |
195 | |
196 | Using C<inner()> in this method makes it possible for one or more |
197 | subclasses to then augment this method with their own specific |
198 | implementation: |
199 | |
200 | package Report; |
201 | |
202 | use Moose; |
203 | |
204 | extends 'Document'; |
205 | |
206 | augment 'as_xml' => sub { |
207 | my $self = shift; |
208 | |
909103e1 |
209 | my $xml = " <report>\n"; |
92cd015f |
210 | $xml .= inner(); |
909103e1 |
211 | $xml .= " </report>\n"; |
92cd015f |
212 | |
213 | return $xml; |
214 | }; |
215 | |
216 | When we call C<as_xml> on a Report object, we get something like this: |
217 | |
218 | <document> |
909103e1 |
219 | <report> |
220 | </report> |
92cd015f |
221 | </document> |
222 | |
223 | But we also called C<inner()> in C<Report>, so we can continue |
224 | subclassing and adding more content inside the document: |
225 | |
226 | package Report::IncomeAndExpenses; |
227 | |
228 | use Moose; |
229 | |
230 | extends 'Report'; |
231 | |
232 | augment 'as_xml' => sub { |
233 | my $self = shift; |
234 | |
909103e1 |
235 | my $xml = ' <income>' . $self->income . '</income>'; |
92cd015f |
236 | $xml .= "\n"; |
909103e1 |
237 | $xml .= ' <expenses>' . $self->expenses . '</expenses>'; |
92cd015f |
238 | $xml .= "\n"; |
239 | |
240 | $xml .= inner() || q{}; |
241 | |
242 | return $xml; |
243 | }; |
244 | |
245 | Now our report has some content: |
246 | |
247 | <document> |
909103e1 |
248 | <report> |
249 | <income>$10</income> |
250 | <expenses>$8</expenses> |
251 | </report> |
92cd015f |
252 | </document> |
253 | |
254 | What makes this combination of C<augment> and C<inner()> special is |
ce5e6e3c |
255 | that it allows us to have methods which are called from parent (least |
646e0fb0 |
256 | specific) to child (most specific). This inverts the normal |
257 | inheritance pattern. |
92cd015f |
258 | |
909103e1 |
259 | Note that in C<Report::IncomeAndExpenses> we call C<inner()> again. If the |
260 | object is an instance of C<Report::IncomeAndExpenses> then this call is a |
261 | no-op, and just returns false. It's a good idea to always call C<inner()> to |
262 | allow for future subclassing. |
92cd015f |
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 | |
92cd015f |
300 | =cut |