ignore generated recipes
[gitmo/Moose.git] / lib / Moose / Cookbook / Basics / Recipe4.pod
CommitLineData
471c4f09 1
2=pod
3
4=head1 NAME
5
021b8139 6Moose::Cookbook::Basics::Recipe4 - Subtypes, and modeling a simple B<Company> class hierarchy
471c4f09 7
8=head1 SYNOPSIS
36c99105 9
471c4f09 10 package Address;
471c4f09 11 use Moose;
05d9eaf6 12 use Moose::Util::TypeConstraints;
36c99105 13
471c4f09 14 use Locale::US;
15 use Regexp::Common 'zip';
36c99105 16
471c4f09 17 my $STATES = Locale::US->new;
0b3811a6 18 subtype 'USState'
471c4f09 19 => as Str
20 => where {
36c99105 21 ( exists $STATES->{code2state}{ uc($_) }
22 || exists $STATES->{state2code}{ uc($_) } );
23 };
24
0b3811a6 25 subtype 'USZipCode'
471c4f09 26 => as Value
27 => where {
36c99105 28 /^$RE{zip}{US}{-extended => 'allow'}$/;
29 };
30
31 has 'street' => ( is => 'rw', isa => 'Str' );
32 has 'city' => ( is => 'rw', isa => 'Str' );
33 has 'state' => ( is => 'rw', isa => 'USState' );
34 has 'zip_code' => ( is => 'rw', isa => 'USZipCode' );
35
f1917f58 36 package Company;
37 use Moose;
38 use Moose::Util::TypeConstraints;
36c99105 39
40 has 'name' => ( is => 'rw', isa => 'Str', required => 1 );
41 has 'address' => ( is => 'rw', isa => 'Address' );
42 has 'employees' => ( is => 'rw', isa => 'ArrayRef[Employee]' );
43
f1917f58 44 sub BUILD {
36c99105 45 my ( $self, $params ) = @_;
4a6b74bd 46 if ( @{ $self->employees } ) {
47 foreach my $employee ( @{ $self->employees } ) {
f1917f58 48 $employee->company($self);
49 }
50 }
51 }
36c99105 52
f1917f58 53 after 'employees' => sub {
36c99105 54 my ( $self, $employees ) = @_;
4a6b74bd 55 if ($employees) {
36c99105 56 foreach my $employee ( @{$employees} ) {
f1917f58 57 $employee->company($self);
36c99105 58 }
f1917f58 59 }
36c99105 60 };
61
471c4f09 62 package Person;
471c4f09 63 use Moose;
36c99105 64
65 has 'first_name' => ( is => 'rw', isa => 'Str', required => 1 );
66 has 'last_name' => ( is => 'rw', isa => 'Str', required => 1 );
67 has 'middle_initial' => (
68 is => 'rw', isa => 'Str',
69 predicate => 'has_middle_initial'
70 );
71 has 'address' => ( is => 'rw', isa => 'Address' );
72
471c4f09 73 sub full_name {
74 my $self = shift;
36c99105 75 return $self->first_name
76 . (
77 $self->has_middle_initial
78 ? ' ' . $self->middle_initial . '. '
79 : ' '
80 ) . $self->last_name;
471c4f09 81 }
36c99105 82
471c4f09 83 package Employee;
36c99105 84 use Moose;
85
471c4f09 86 extends 'Person';
36c99105 87
4a6b74bd 88 has 'title' => ( is => 'rw', isa => 'Str', required => 1 );
89 has 'employer' => ( is => 'rw', isa => 'Company', weak_ref => 1 );
36c99105 90
471c4f09 91 override 'full_name' => sub {
92 my $self = shift;
36c99105 93 super() . ', ' . $self->title;
471c4f09 94 };
2f04a0fc 95
471c4f09 96=head1 DESCRIPTION
97
4a6b74bd 98This recipe introduces the C<subtype> sugar function from
99L<Moose::Util::TypeConstraints>. The C<subtype> function lets you
100declaratively create type constraints without building an entire
101class.
172e0738 102
4a6b74bd 103In the recipe we also make use of L<Locale::US> and L<Regexp::Common>
104to build constraints, showing how how constraints can make use of
105existing CPAN tools for data validation.
36c99105 106
16fb3624 107Finally, we introduce the C<required> attribute option.
4a6b74bd 108
109The the C<Address> class we define two subtypes. The first uses the
19320607 110L<Locale::US> module to check the validity of a state. It accepts
4a6b74bd 111either a state abbreviation of full name.
112
113A state will be passed in as a string, so we make our C<USState> type
114a subtype of Moose's builtin C<Str> type. This is done using the C<as>
115sugar. The actual constraint is defined using C<where>. This function
116accepts a single subroutine reference. That subroutine will be called
117with the value to be checked in C<$_> (1). It is expected to return a
118true or false value indicating whether the value is valid for the
119type.
172e0738 120
4a6b74bd 121We can now use the C<USState> type just like Moose's builtin types:
172e0738 122
36c99105 123 has 'state' => ( is => 'rw', isa => 'USState' );
172e0738 124
4a6b74bd 125When the C<state> attribute is set, the value is checked against the
126C<USState> constraint. If the value is not valid, an exception will be
127thrown.
172e0738 128
4a6b74bd 129The next C<subtype>, C<USZipCode>, uses
130L<Regexp::Common>. L<Regexp::Common> includes a regex for validating
131US zip codes. We use this constraint for the C<zip_code> attribute.
172e0738 132
0b3811a6 133 subtype 'USZipCode'
172e0738 134 => as Value
135 => where {
36c99105 136 /^$RE{zip}{US}{-extended => 'allow'}$/;
137 };
172e0738 138
4a6b74bd 139Using a subtype instead of requiring a class for each type greatly
140simplifies the code. We don't really need a class for these types, as
141they're just strings, but we do want to ensure that they're valid.
142
143The type constraints we created are reusable. Type constraints are
144stored by name in a global registry. This means that we can refer to
145them in other classes. Because the registry is global, we do recommend
146that you use some sort of pseudo-namespacing in real applications,
147like C<MyApp.Type.USState>.
148
149These two subtypes allow us to define a simple C<Address> class.
172e0738 150
4a6b74bd 151Then we define our C<Company> class, which has an address. As we saw
152in earlier recipes, Moose automatically creates a type constraint for
153each our classes, so we can use that for the C<Company> class's
154C<address> attribute:
172e0738 155
36c99105 156 has 'address' => ( is => 'rw', isa => 'Address' );
172e0738 157
4a6b74bd 158A company also needs a name:
172e0738 159
36c99105 160 has 'name' => ( is => 'rw', isa => 'Str', required => 1 );
172e0738 161
16fb3624 162This introduces a new attribute option, C<required>. If an attribute
163is required, then it must be passed to the class's constructor, or an
164exception will be thrown. It's important to understand that a
165C<required> attribute can still be false or C<undef>, if its type
166constraint allows that.
f1917f58 167
4a6b74bd 168The next attribute, C<employees>, uses a I<parameterized> type
169constraint:
36c99105 170
171 has 'employees' => ( is => 'rw', isa => 'ArrayRef[Employee]' );
07cde929 172
4a6b74bd 173This constraint says that C<employees> must be an array reference
174where each element of the array is an C<Employee> object. It's worth
175noting that an I<empty> array reference also satisfies this
176constraint.
177
178Parameterizable type constraints (or "container types), such as
179C<ArrayRef[`a]>, can be made more specific with a type parameter. In
180fact, we can arbitrarily nest these types, producing something like
181C<HashRef[ArrayRef[Int]]>. However, you can also just use the type by
182itself, so C<ArrayRef> is legal. (2)
183
184If you jump down to the definition of the C<Employee> class, you will
185see that it has an C<employer> attribute.
186
187When we set the C<employees> for a C<Company> we want to make sure
188that each of these employee objects refers back to the right
189C<Company> in its C<employer> attribute.
190
191To do that, we need to hook into object construction. Moose lets us do
192this by writing a C<BUILD> method in our class. When your class
193defined a C<BUILD> method, it will be called immediately after an
194object construction, but before the object is returned to the caller
195(3).
196
197The C<Company> class uses the C<BUILD> method to ensure that each
198employee of a company has the proper C<Company> object in its
199C<employer> attribute:
36c99105 200
ad5ed80c 201 sub BUILD {
36c99105 202 my ( $self, $params ) = @_;
4a6b74bd 203 if ( $self->employees ) {
204 foreach my $employee ( @{ $self->employees } ) {
ad5ed80c 205 $employee->company($self);
206 }
207 }
208 }
209
4a6b74bd 210The C<BUILD> method is executed after type constraints are checked, so
211it is safe to assume that C<< $self->employees >> will return an array
212reference, and that the elements of that array will be C<Employee>
213objects.
214
215We also want to make sure that whenever the C<employees> attribute for
216a C<Company> is changed, we also update the C<employer> for each
217employee.
ad5ed80c 218
4a6b74bd 219To do this we can use an C<after> modifier:
ad5ed80c 220
221 after 'employees' => sub {
36c99105 222 my ( $self, $employees ) = @_;
4a6b74bd 223 if ($employees) {
36c99105 224 foreach my $employee ( @{$employees} ) {
ad5ed80c 225 $employee->company($self);
36c99105 226 }
ad5ed80c 227 }
228 };
229
6549b0d1 230Again, as with the C<BUILD> method, we know that the type constraint
231check has already happened, so we can just check for definedness on the
ad5ed80c 232C<$employees> argument.
233
4a6b74bd 234The B<Person> class does have demonstrate anything new. It has several
235C<required> attributes. It also has a C<predicate> method, which we
236first used in L<recipe 3|Moose::Cookbook::Basics::Recipe3>.
f1917f58 237
4a6b74bd 238The only new feature in the C<Employee> class is the C<override>
239method modifier:
f1917f58 240
241 override 'full_name' => sub {
242 my $self = shift;
36c99105 243 super() . ', ' . $self->title;
f1917f58 244 };
245
4a6b74bd 246This is just a sugary alternative to Perl's built in C<SUPER::>
247feature. However, there is one difference. You cannot pass any
19320607 248arguments to C<super>. Instead, Moose simply passes the same
4a6b74bd 249parameters that were passed to the method.
ad5ed80c 250
4a6b74bd 251A more detailed example of usage can be found in
252F<t/000_recipes/004_recipe.t>.
ad5ed80c 253
254=head1 CONCLUSION
255
4a6b74bd 256This recipe was intentionally longer and more complex. It illustrates
257how Moose classes can be used together with type constraints, as well
258as the density of information that you can get out of a small amount
259of typing when using Moose.
260
261This recipe also introduced the C<subtype> function, the C<required>
262attribute, and the C<override> method modifier.
ad5ed80c 263
4a6b74bd 264We will revisit type constraints in future recipes, and cover type
265coercion as well.
e08c54f5 266
172e0738 267=head1 FOOTNOTES
268
269=over 4
270
271=item (1)
272
6549b0d1 273The value being checked is also passed as the first argument to
4a6b74bd 274the C<where> block, so it can be accessed as C<$_[0]>.
172e0738 275
ad5ed80c 276=item (2)
277
4a6b74bd 278Note that C<ArrayRef[]> will not work. Moose will not parse this as a
279container type, and instead you will have a new type named
280"ArrayRef[]", which doesn't make any sense.
281
282=item (3)
283
284The C<BUILD> method is actually called by C<< Moose::Object->BUILDALL
285>>, which is called by C<< Moose::Object->new >>. The C<BUILDALL>
286method climbs the object inheritance graph and calls any C<BUILD>
287methods it finds in the correct order.
ad5ed80c 288
172e0738 289=back
290
8c3d5c88 291=head1 AUTHORS
471c4f09 292
293Stevan Little E<lt>stevan@iinteractive.comE<gt>
294
8c3d5c88 295Dave Rolsky E<lt>autarch@urth.orgE<gt>
296
471c4f09 297=head1 COPYRIGHT AND LICENSE
298
2840a3b2 299Copyright 2006-2009 by Infinity Interactive, Inc.
471c4f09 300
301L<http://www.iinteractive.com>
302
303This library is free software; you can redistribute it and/or modify
304it under the same terms as Perl itself.
305
e08c54f5 306=cut