Commit | Line | Data |
471c4f09 |
1 | |
2 | =pod |
3 | |
4 | =head1 NAME |
5 | |
cdcae970 |
6 | Moose::Cookbook::Recipe1 - The (always classic) cartesian point example. |
471c4f09 |
7 | |
8 | =head1 SYNOPSIS |
9 | |
10 | package Point; |
11 | use strict; |
12 | use warnings; |
13 | use Moose; |
14 | |
15 | has 'x' => (isa => 'Int', is => 'ro'); |
16 | has 'y' => (isa => 'Int', is => 'rw'); |
17 | |
18 | sub clear { |
19 | my $self = shift; |
20 | $self->{x} = 0; |
21 | $self->y(0); |
22 | } |
23 | |
24 | package Point3D; |
25 | use strict; |
26 | use warnings; |
27 | use Moose; |
28 | |
29 | extends 'Point'; |
30 | |
31 | has 'z' => (isa => 'Int'); |
32 | |
33 | after 'clear' => sub { |
34 | my $self = shift; |
35 | $self->{z} = 0; |
36 | }; |
37 | |
38 | =head1 DESCRIPTION |
39 | |
cdcae970 |
40 | This is the classic Point example. This one in particular I took |
41 | from the Perl 6 Apocalypse 12 document, but it is similar to the |
42 | example found in the classic K&R C book as well, and many other |
43 | places. And now, onto the code: |
44 | |
45 | As with all Perl 5 classes, a Moose class is defined in a package. |
46 | Of course we always use C<strict> and C<warnings> (don't forget |
47 | that a kitten will die if you don't) and then we C<use Moose>. |
48 | |
49 | By loading Moose, we are enabeling the Moose "environment" to be |
50 | loaded within our package. This means that we export some functions |
51 | which serve as Moose "keywords". This is nothing fancier than that, |
52 | just plain old exported functions. |
53 | |
54 | Another important thing happens at this stage as well. Moose will |
55 | automatically set your package's superclass to be L<Moose::Object>. |
56 | The reason we do this, is so that we can be sure that you will |
57 | inherit from L<Moose::Object> and get the benefits that provides |
58 | (see the L<Moose::Object> for those details). However, you don't |
59 | actually I<have> to inherit from L<Moose::Object> if you don't |
60 | want to, all other features of Moose are still accessible to you. |
61 | |
62 | Now, onto the keywords. The first one we see here is C<has>, which |
63 | defines an instance attribute in your class. |
64 | |
65 | has 'x' => (isa => 'Int', is => 'ro'); |
66 | |
67 | This will create an attribute named C<x>, it will expect that the |
68 | value stored in the attribute to pass the type constraint C<Int> (1), |
69 | and the accessor generated for this attribute will be read-only |
70 | (abbreviated as C<ro>). |
71 | |
72 | The next C<has> line is very similar, with only one difference. |
73 | |
74 | has 'y' => (isa => 'Int', is => 'rw'); |
75 | |
76 | For the C<y> attribute a read/write accessor will be generated |
77 | (abbreviated as C<rw>). |
78 | |
79 | At this point the attributes have been defined, and it is time to |
80 | define our methods. In Moose, as with regular Perl 5 OO, a method |
81 | is just a subroutine defined within the package. So here we create |
82 | the C<clear> method. |
83 | |
84 | sub clear { |
85 | my $self = shift; |
86 | $self->{x} = 0; |
87 | $self->y(0); |
88 | } |
89 | |
90 | It is pretty standard, the only thing to note is that we are directly |
91 | accessing the C<x> slot in the instance L<(2)>. This is because the |
92 | value was created with a read-only accessor. This also shows that Moose |
93 | objects are not anything out of the ordinary, but just regular old |
94 | blessed HASH references. This means they are very compatible with |
95 | other Perl 5 (non-Moose) classes as well. |
96 | |
97 | The next part of the code to review is the B<Point> subclass, |
98 | B<Point3D>. The first item you might notice is that we do not use |
99 | the standard C<use base> declaration here. Instead we use the Moose |
100 | keyword C<extends> like so: |
101 | |
102 | extends 'Point'; |
103 | |
104 | This keyword will function very much like C<use base> does in that |
105 | it will make an attempt to load your class if it has not already been |
106 | loaded. However, it differs on one important point. The C<extends> |
107 | keyword will overwrite any previous values in your package's C<@ISA>, |
108 | where C<use base> will C<push> values onto the package's C<@ISA>. It |
109 | is my opinion that the behavior of C<extends> is more intuitive in |
110 | that it is more explicit about defining the superclass relationship. |
111 | |
112 | A small digression here, both Moose and C<extends> support multiple |
113 | inheritence. You simply pass all the superclasses to C<extends>, |
114 | like so: |
115 | |
116 | extends 'Foo', 'Bar', 'Baz'; |
117 | |
118 | Now, back to our B<Point3D> class. The next thing we do is to create |
119 | a new attribute for B<Point3D> called C<z>. |
120 | |
121 | has 'z' => (isa => 'Int'); |
122 | |
123 | As with B<Point>'s C<x> and C<y> attributes, this attribute has a |
124 | type constraint of C<Int>, but it differs in that it does B<not> |
125 | ask for any autogenerated accessors. The result being (aside from |
126 | breaking object encapsulation), that C<x> is a private attribute. |
127 | |
128 | Next comes another Moose feature which we call method "modifiers" |
129 | (or method "advice" for the AOP inclined). The modifier used here |
130 | is the C<after> modifier, and looks like this: |
131 | |
132 | after 'clear' => sub { |
133 | my $self = shift; |
134 | $self->{z} = 0; |
135 | }; |
136 | |
137 | This modifier tells Moose to install a C<clear> method for |
138 | B<Point3D> that will first run the C<clear> method for the |
139 | superclass (in this case C<Point::clear>), and then run this |
140 | method I<after> it (passing in the same arguments as the original |
141 | method). |
142 | |
143 | Now, of course using the C<after> modifier is not the only way to |
144 | accomplish this. I mean, after all, this B<is> Perl right? You |
145 | would get the same results with this code: |
146 | |
147 | sub clear { |
148 | my $self = shift; |
149 | $self->SUPER::clear(); |
150 | $self->{z} = 0; |
151 | } |
152 | |
153 | You could also use another Moose method modifier, C<override> here, |
154 | and get the same results again. Here is how that would look. |
155 | |
156 | override 'clear' => sub { |
157 | my $self = shift; |
158 | super(); |
159 | $self->{z} = 0; |
160 | }; |
161 | |
162 | The C<override> modifier allows you to use the C<super> keyword |
163 | within it to dispatch to the superclass's method in a very Ruby-ish |
164 | style. |
165 | |
166 | Now of course, what use is a class if you cant instantiate objects |
167 | with it. Now since B<Point> inherits from L<Moose::Object>, it will |
168 | inherit the default L<Moose::Object> constructor called C<new>. Here |
169 | are two examples of how that is used: |
170 | |
171 | my $point = Point->new(x => 1, y => 2); |
172 | my $point3d = Point3D->new(x => 1, y => 2, z => 3); |
173 | |
174 | As you can see, C<new> accepts named argument pairs for any of the |
175 | attributes. It does not I<require> that you pass in the all the |
176 | attributes, and it will politely ignore any named arguments it does |
177 | not recognize. |
178 | |
703d9522 |
179 | From here on, you can use C<$point> and C<$point3d> just as you would |
180 | any other Perl 5 object. For a more detailed example of what can be |
181 | done, you can refer to the F<t/001_basic.t> test file. |
cdcae970 |
182 | |
183 | =head1 CONCLUSION |
184 | |
185 | I hope this recipe has given you some explaination of how to use |
186 | Moose to build you Perl 5 classes. The next recipe will build upon |
187 | the basics shown here with more complex attributes and methods. |
188 | Please read on :) |
189 | |
190 | =head1 FOOTNOTES |
191 | |
192 | =over 4 |
193 | |
194 | =item (1) |
195 | |
196 | Several default type constraints are provided by Moose, of which |
197 | C<Int> is one. For more information on the built-in type constraints |
198 | and the type constraint system in general, see the |
199 | L<Moose::Util::TypeConstraints> documentation. |
200 | |
201 | =item (2) |
202 | |
203 | Future plans for Moose include allowing for alternate instance |
204 | structures such as blessed ARRAY refs and such. If you want you Moose |
205 | classes to be interchangable, it is advised that you avoid direct |
206 | instance access, like that which is shown above. |
207 | |
208 | =back |
209 | |
210 | =head1 SEE ALSO |
211 | |
212 | =over 4 |
213 | |
214 | =item Method Modifiers |
215 | |
216 | The concept of method modifiers is directly ripped off from CLOS. A |
217 | great explaination of them can be found by following this link. |
218 | |
219 | L<http://www.gigamonkeys.com/book/object-reorientation-generic-functions.html> |
220 | |
221 | =back |
222 | |
471c4f09 |
223 | =head1 AUTHOR |
224 | |
225 | Stevan Little E<lt>stevan@iinteractive.comE<gt> |
226 | |
227 | =head1 COPYRIGHT AND LICENSE |
228 | |
229 | Copyright 2006 by Infinity Interactive, Inc. |
230 | |
231 | L<http://www.iinteractive.com> |
232 | |
233 | This library is free software; you can redistribute it and/or modify |
234 | it under the same terms as Perl itself. |
235 | |
236 | =cut |