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 | |
132 | =head1 INNER AND AUGMENT |
133 | |
134 | Augment and inner are two halves of the same feature. The augment |
135 | modifier provides a sort of inverted subclassing. You provide part of |
136 | the implementation in a superclass, and then document that subclasses |
137 | are expected to provide the rest. |
138 | |
139 | The superclass calls C<inner()>, which then calls the C<augment> |
140 | modifier in the subclass: |
141 | |
142 | package Document; |
143 | |
144 | use Moose; |
145 | |
146 | sub as_xml { |
147 | my $self = shift; |
148 | |
149 | my $xml = "<document>\n"; |
150 | $xml .= inner(); |
151 | $xml .= "</document>\n"; |
152 | |
153 | return $xml; |
154 | } |
155 | |
156 | Using C<inner()> in this method makes it possible for one or more |
157 | subclasses to then augment this method with their own specific |
158 | implementation: |
159 | |
160 | package Report; |
161 | |
162 | use Moose; |
163 | |
164 | extends 'Document'; |
165 | |
166 | augment 'as_xml' => sub { |
167 | my $self = shift; |
168 | |
169 | my $xml = "<report>\n"; |
170 | $xml .= inner(); |
171 | $xml .= "</report>\n"; |
172 | |
173 | return $xml; |
174 | }; |
175 | |
176 | When we call C<as_xml> on a Report object, we get something like this: |
177 | |
178 | <document> |
179 | <report> |
180 | </report> |
181 | </document> |
182 | |
183 | But we also called C<inner()> in C<Report>, so we can continue |
184 | subclassing and adding more content inside the document: |
185 | |
186 | package Report::IncomeAndExpenses; |
187 | |
188 | use Moose; |
189 | |
190 | extends 'Report'; |
191 | |
192 | augment 'as_xml' => sub { |
193 | my $self = shift; |
194 | |
195 | my $xml = '<income>' . $self->income . '</income>'; |
196 | $xml .= "\n"; |
ec4161a5 |
197 | $xml .= '<expenses>' . $self->expenses . '</expenses>'; |
92cd015f |
198 | $xml .= "\n"; |
199 | |
200 | $xml .= inner() || q{}; |
201 | |
202 | return $xml; |
203 | }; |
204 | |
205 | Now our report has some content: |
206 | |
207 | <document> |
208 | <report> |
209 | <income>$10</income> |
210 | <expenses>$8</expenses> |
211 | </report> |
212 | </document> |
213 | |
214 | What makes this combination of C<augment> and C<inner()> special is |
ce5e6e3c |
215 | that it allows us to have methods which are called from parent (least |
646e0fb0 |
216 | specific) to child (most specific). This inverts the normal |
217 | inheritance pattern. |
92cd015f |
218 | |
219 | Note that in C<Report::IncomeAndExpenses> we call C<inner()> again. If |
220 | the object is an instance of C<Report::IncomeAndExpenses> then this |
221 | call is a no-op, and just returns false. |
222 | |
223 | =head1 OVERRIDE AND SUPER |
224 | |
225 | Finally, Moose provides some simple sugar for Perl's built-in method |
226 | overriding scheme. If you want to override a method from a parent |
227 | class, you can do this with C<override>: |
228 | |
229 | package Employee; |
230 | |
231 | use Moose; |
232 | |
233 | extends 'Person'; |
234 | |
235 | has 'job_title' => ( is => 'rw' ); |
236 | |
237 | override 'display_name' => sub { |
238 | my $self = shift; |
239 | |
240 | return super() . q{, } . $self->title(); |
241 | }; |
242 | |
243 | The call to C<super()> is almost the same as calling C<< |
244 | $self->SUPER::display_name >>. The difference is that the arguments |
245 | passed to the superclass's method will always be the same as the ones |
246 | passed to the method modifier, and cannot be changed. |
247 | |
248 | All arguments passed to C<super()> are ignored, as are any changes |
249 | made to C<@_> before C<super()> is called. |
250 | |
251 | =head1 SEMI-COLONS |
252 | |
253 | Because all of these method modifiers are implemented as Perl |
254 | functions, you must always end the modifier declaration with a |
255 | semi-colon: |
256 | |
257 | after 'foo' => sub { }; |
258 | |
259 | =head1 AUTHOR |
260 | |
261 | Dave Rolsky E<lt>autarch@urth.orgE<gt> |
262 | |
263 | =head1 COPYRIGHT AND LICENSE |
264 | |
646e0fb0 |
265 | Copyright 2008-2009 by Infinity Interactive, Inc. |
92cd015f |
266 | |
267 | L<http://www.iinteractive.com> |
268 | |
269 | This library is free software; you can redistribute it and/or modify |
270 | it under the same terms as Perl itself. |
271 | |
272 | =cut |