6 Moose::Cookbook::Basics::Recipe4 - Subtypes, and modeling a simple B<Company> class hierarchy
12 use Moose::Util::TypeConstraints;
15 use Regexp::Common 'zip';
17 my $STATES = Locale::US->new;
21 ( exists $STATES->{code2state}{ uc($_) }
22 || exists $STATES->{state2code}{ uc($_) } );
28 /^$RE{zip}{US}{-extended => 'allow'}$/;
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' );
38 use Moose::Util::TypeConstraints;
40 has 'name' => ( is => 'rw', isa => 'Str', required => 1 );
41 has 'address' => ( is => 'rw', isa => 'Address' );
42 has 'employees' => ( is => 'rw', isa => 'ArrayRef[Employee]' );
45 my ( $self, $params ) = @_;
46 if ( @{ $self->employees } ) {
47 foreach my $employee ( @{ $self->employees } ) {
48 $employee->company($self);
53 after 'employees' => sub {
54 my ( $self, $employees ) = @_;
56 foreach my $employee ( @{$employees} ) {
57 $employee->company($self);
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'
71 has 'address' => ( is => 'rw', isa => 'Address' );
75 return $self->first_name
77 $self->has_middle_initial
78 ? ' ' . $self->middle_initial . '. '
88 has 'title' => ( is => 'rw', isa => 'Str', required => 1 );
89 has 'employer' => ( is => 'rw', isa => 'Company', weak_ref => 1 );
91 override 'full_name' => sub {
93 super() . ', ' . $self->title;
98 This recipe introduces the C<subtype> sugar function from
99 L<Moose::Util::TypeConstraints>. The C<subtype> function lets you
100 declaratively create type constraints without building an entire
103 In the recipe we also make use of L<Locale::US> and L<Regexp::Common>
104 to build constraints, showing how how constraints can make use of
105 existing CPAN tools for data validation.
107 Finally, we introduce the C<required> attribute parameter.
109 The the C<Address> class we define two subtypes. The first uses the
110 L<Locale::US> module to check the validity of a state. It accepts
111 either a state abbreviation of full name.
113 A state will be passed in as a string, so we make our C<USState> type
114 a subtype of Moose's builtin C<Str> type. This is done using the C<as>
115 sugar. The actual constraint is defined using C<where>. This function
116 accepts a single subroutine reference. That subroutine will be called
117 with the value to be checked in C<$_> (1). It is expected to return a
118 true or false value indicating whether the value is valid for the
121 We can now use the C<USState> type just like Moose's builtin types:
123 has 'state' => ( is => 'rw', isa => 'USState' );
125 When the C<state> attribute is set, the value is checked against the
126 C<USState> constraint. If the value is not valid, an exception will be
129 The next C<subtype>, C<USZipCode>, uses
130 L<Regexp::Common>. L<Regexp::Common> includes a regex for validating
131 US zip codes. We use this constraint for the C<zip_code> attribute.
136 /^$RE{zip}{US}{-extended => 'allow'}$/;
139 Using a subtype instead of requiring a class for each type greatly
140 simplifies the code. We don't really need a class for these types, as
141 they're just strings, but we do want to ensure that they're valid.
143 The type constraints we created are reusable. Type constraints are
144 stored by name in a global registry. This means that we can refer to
145 them in other classes. Because the registry is global, we do recommend
146 that you use some sort of pseudo-namespacing in real applications,
147 like C<MyApp.Type.USState>.
149 These two subtypes allow us to define a simple C<Address> class.
151 Then we define our C<Company> class, which has an address. As we saw
152 in earlier recipes, Moose automatically creates a type constraint for
153 each our classes, so we can use that for the C<Company> class's
154 C<address> attribute:
156 has 'address' => ( is => 'rw', isa => 'Address' );
158 A company also needs a name:
160 has 'name' => ( is => 'rw', isa => 'Str', required => 1 );
162 This introduces a new attribute parameter, C<required>. If an
163 attribute is required, then it must be passed to the class's
164 constructor, or an exception will be thrown. It's important to
165 understand that a C<required> attribute can still be false or
166 C<undef>, if its type constraint allows that.
168 The next attribute, C<employees>, uses a I<parameterized> type
171 has 'employees' => ( is => 'rw', isa => 'ArrayRef[Employee]' );
173 This constraint says that C<employees> must be an array reference
174 where each element of the array is an C<Employee> object. It's worth
175 noting that an I<empty> array reference also satisfies this
178 Parameterizable type constraints (or "container types), such as
179 C<ArrayRef[`a]>, can be made more specific with a type parameter. In
180 fact, we can arbitrarily nest these types, producing something like
181 C<HashRef[ArrayRef[Int]]>. However, you can also just use the type by
182 itself, so C<ArrayRef> is legal. (2)
184 If you jump down to the definition of the C<Employee> class, you will
185 see that it has an C<employer> attribute.
187 When we set the C<employees> for a C<Company> we want to make sure
188 that each of these employee objects refers back to the right
189 C<Company> in its C<employer> attribute.
191 To do that, we need to hook into object construction. Moose lets us do
192 this by writing a C<BUILD> method in our class. When your class
193 defined a C<BUILD> method, it will be called immediately after an
194 object construction, but before the object is returned to the caller
197 The C<Company> class uses the C<BUILD> method to ensure that each
198 employee of a company has the proper C<Company> object in its
199 C<employer> attribute:
202 my ( $self, $params ) = @_;
203 if ( $self->employees ) {
204 foreach my $employee ( @{ $self->employees } ) {
205 $employee->company($self);
210 The C<BUILD> method is executed after type constraints are checked, so
211 it is safe to assume that C<< $self->employees >> will return an array
212 reference, and that the elements of that array will be C<Employee>
215 We also want to make sure that whenever the C<employees> attribute for
216 a C<Company> is changed, we also update the C<employer> for each
219 To do this we can use an C<after> modifier:
221 after 'employees' => sub {
222 my ( $self, $employees ) = @_;
224 foreach my $employee ( @{$employees} ) {
225 $employee->company($self);
230 Again, as with the C<BUILD> method, we know that the type constraint
231 check has already happened, so we can just check for definedness on the
232 C<$employees> argument.
234 The B<Person> class does have demonstrate anything new. It has several
235 C<required> attributes. It also has a C<predicate> method, which we
236 first used in L<recipe 3|Moose::Cookbook::Basics::Recipe3>.
238 The only new feature in the C<Employee> class is the C<override>
241 override 'full_name' => sub {
243 super() . ', ' . $self->title;
246 This is just a sugary alternative to Perl's built in C<SUPER::>
247 feature. However, there is one difference. You cannot pass any
248 arguments to C<super>. Instead, Moose simply passes the same
249 parameters that were passed to the method.
251 A more detailed example of usage can be found in
252 F<t/000_recipes/004_recipe.t>.
256 This recipe was intentionally longer and more complex. It illustrates
257 how Moose classes can be used together with type constraints, as well
258 as the density of information that you can get out of a small amount
259 of typing when using Moose.
261 This recipe also introduced the C<subtype> function, the C<required>
262 attribute, and the C<override> method modifier.
264 We will revisit type constraints in future recipes, and cover type
273 The value being checked is also passed as the first argument to
274 the C<where> block, so it can be accessed as C<$_[0]>.
278 Note that C<ArrayRef[]> will not work. Moose will not parse this as a
279 container type, and instead you will have a new type named
280 "ArrayRef[]", which doesn't make any sense.
284 The C<BUILD> method is actually called by C<< Moose::Object->BUILDALL
285 >>, which is called by C<< Moose::Object->new >>. The C<BUILDALL>
286 method climbs the object inheritance graph and calls any C<BUILD>
287 methods it finds in the correct order.
293 Stevan Little E<lt>stevan@iinteractive.comE<gt>
295 Dave Rolsky E<lt>autarch@urth.orgE<gt>
297 =head1 COPYRIGHT AND LICENSE
299 Copyright 2006-2009 by Infinity Interactive, Inc.
301 L<http://www.iinteractive.com>
303 This library is free software; you can redistribute it and/or modify
304 it under the same terms as Perl itself.