1Moose::Cookbook::BasicsU:s:eCromCpoanntyr_iSbuuMbtoteoydspeeP:se:(rC3lo)oDkobcouomke:n:tBaatsiiocns::Company_Subtypes(3)
2
3
4

NAME

6       Moose::Cookbook::Basics::Company_Subtypes - Demonstrates the use of
7       subtypes and how to model classes related to companies, people,
8       employees, etc.
9

VERSION

11       version 2.2203
12

SYNOPSIS

14         package Address;
15         use Moose;
16         use Moose::Util::TypeConstraints;
17
18         use Locale::US;
19         use Regexp::Common 'zip';
20
21         my $STATES = Locale::US->new;
22         subtype 'USState'
23             => as Str
24             => where {
25                    (    exists $STATES->{code2state}{ uc($_) }
26                      || exists $STATES->{state2code}{ uc($_) } );
27                };
28
29         subtype 'USZipCode'
30             => as Value
31             => where {
32                    /^$RE{zip}{US}{-extended => 'allow'}$/;
33                };
34
35         has 'street'   => ( is => 'rw', isa => 'Str' );
36         has 'city'     => ( is => 'rw', isa => 'Str' );
37         has 'state'    => ( is => 'rw', isa => 'USState' );
38         has 'zip_code' => ( is => 'rw', isa => 'USZipCode' );
39
40         package Company;
41         use Moose;
42         use Moose::Util::TypeConstraints;
43
44         has 'name' => ( is => 'rw', isa => 'Str', required => 1 );
45         has 'address'   => ( is => 'rw', isa => 'Address' );
46         has 'employees' => (
47             is      => 'rw',
48             isa     => 'ArrayRef[Employee]',
49             default => sub { [] },
50         );
51
52         sub BUILD {
53             my ( $self, $params ) = @_;
54             foreach my $employee ( @{ $self->employees } ) {
55                 $employee->employer($self);
56             }
57         }
58
59         after 'employees' => sub {
60             my ( $self, $employees ) = @_;
61             return unless $employees;
62             foreach my $employee ( @$employees ) {
63                 $employee->employer($self);
64             }
65         };
66
67         package Person;
68         use Moose;
69
70         has 'first_name' => ( is => 'rw', isa => 'Str', required => 1 );
71         has 'last_name'  => ( is => 'rw', isa => 'Str', required => 1 );
72         has 'middle_initial' => (
73             is        => 'rw', isa => 'Str',
74             predicate => 'has_middle_initial'
75         );
76         has 'address' => ( is => 'rw', isa => 'Address' );
77
78         sub full_name {
79             my $self = shift;
80             return $self->first_name
81                 . (
82                 $self->has_middle_initial
83                 ? ' ' . $self->middle_initial . '. '
84                 : ' '
85                 ) . $self->last_name;
86         }
87
88         package Employee;
89         use Moose;
90
91         extends 'Person';
92
93         has 'title'    => ( is => 'rw', isa => 'Str',     required => 1 );
94         has 'employer' => ( is => 'rw', isa => 'Company', weak_ref => 1 );
95
96         override 'full_name' => sub {
97             my $self = shift;
98             super() . ', ' . $self->title;
99         };
100

DESCRIPTION

102       This recipe introduces the "subtype" sugar function from
103       Moose::Util::TypeConstraints. The "subtype" function lets you
104       declaratively create type constraints without building an entire class.
105
106       In the recipe we also make use of Locale::US and Regexp::Common to
107       build constraints, showing how constraints can make use of existing
108       CPAN tools for data validation.
109
110       Finally, we introduce the "required" attribute option.
111
112       In the "Address" class we define two subtypes. The first uses the
113       Locale::US module to check the validity of a state. It accepts either a
114       state abbreviation or full name.
115
116       A state will be passed in as a string, so we make our "USState" type a
117       subtype of Moose's builtin "Str" type. This is done using the "as"
118       sugar. The actual constraint is defined using "where". This function
119       accepts a single subroutine reference. That subroutine will be called
120       with the value to be checked in $_ (1). It is expected to return a true
121       or false value indicating whether the value is valid for the type.
122
123       We can now use the "USState" type just like Moose's builtin types:
124
125         has 'state'    => ( is => 'rw', isa => 'USState' );
126
127       When the "state" attribute is set, the value is checked against the
128       "USState" constraint. If the value is not valid, an exception will be
129       thrown.
130
131       The next "subtype", "USZipCode", uses Regexp::Common. Regexp::Common
132       includes a regex for validating US zip codes. We use this constraint
133       for the "zip_code" attribute.
134
135         subtype 'USZipCode'
136             => as Value
137             => where {
138                    /^$RE{zip}{US}{-extended => 'allow'}$/;
139                };
140
141       Using a subtype instead of requiring a class for each type greatly
142       simplifies the code. We don't really need a class for these types, as
143       they're just strings, but we do want to ensure that they're valid.
144
145       The type constraints we created are reusable. Type constraints are
146       stored by name in a global registry, which means that we can refer to
147       them in other classes. Because the registry is global, we do recommend
148       that you use some sort of namespacing in real applications, like
149       "MyApp::Type::USState" (just as you would do with class names).
150
151       These two subtypes allow us to define a simple "Address" class.
152
153       Then we define our "Company" class, which has an address. As we saw in
154       earlier recipes, Moose automatically creates a type constraint for each
155       our classes, so we can use that for the "Company" class's "address"
156       attribute:
157
158         has 'address'   => ( is => 'rw', isa => 'Address' );
159
160       A company also needs a name:
161
162         has 'name' => ( is => 'rw', isa => 'Str', required => 1 );
163
164       This introduces a new attribute option, "required". If an attribute is
165       required, then it must be passed to the class's constructor, or an
166       exception will be thrown. It's important to understand that a
167       "required" attribute can still be false or "undef", if its type
168       constraint allows that.
169
170       The next attribute, "employees", uses a parameterized type constraint:
171
172         has 'employees' => (
173             is      => 'rw',
174             isa     => 'ArrayRef[Employee]'
175             default => sub { [] },
176         );
177
178       This constraint says that "employees" must be an array reference where
179       each element of the array is an "Employee" object. It's worth noting
180       that an empty array reference also satisfies this constraint, such as
181       the value given as the default here.
182
183       Parameterizable type constraints (or "container types"), such as
184       "ArrayRef[`a]", can be made more specific with a type parameter. In
185       fact, we can arbitrarily nest these types, producing something like
186       "HashRef[ArrayRef[Int]]". However, you can also just use the type by
187       itself, so "ArrayRef" is legal. (2)
188
189       If you jump down to the definition of the "Employee" class, you will
190       see that it has an "employer" attribute.
191
192       When we set the "employees" for a "Company" we want to make sure that
193       each of these employee objects refers back to the right "Company" in
194       its "employer" attribute.
195
196       To do that, we need to hook into object construction. Moose lets us do
197       this by writing a "BUILD" method in our class. When your class defines
198       a "BUILD" method, it will be called by the constructor immediately
199       after object construction, but before the object is returned to the
200       caller. Note that all "BUILD" methods in your class hierarchy will be
201       called automatically; there is no need to (and you should not) call the
202       superclass "BUILD" method.
203
204       The "Company" class uses the "BUILD" method to ensure that each
205       employee of a company has the proper "Company" object in its "employer"
206       attribute:
207
208         sub BUILD {
209             my ( $self, $params ) = @_;
210             foreach my $employee ( @{ $self->employees } ) {
211                 $employee->employer($self);
212             }
213         }
214
215       The "BUILD" method is executed after type constraints are checked, so
216       it is safe to assume that if "$self->employees" has a value, it will be
217       an array reference, and that the elements of that array reference will
218       be "Employee" objects.
219
220       We also want to make sure that whenever the "employees" attribute for a
221       "Company" is changed, we also update the "employer" for each employee.
222
223       To do this we can use an "after" modifier:
224
225         after 'employees' => sub {
226             my ( $self, $employees ) = @_;
227             return unless $employees;
228             foreach my $employee ( @$employees ) {
229                 $employee->employer($self);
230             }
231         };
232
233       Again, as with the "BUILD" method, we know that the type constraint
234       check has already happened, so we know that if $employees is defined it
235       will contain an array reference of "Employee" objects.
236
237       Note that "employees" is a read/write accessor, so we must return early
238       if it's called as a reader.
239
240       The Person class does not really demonstrate anything new. It has
241       several "required" attributes. It also has a "predicate" method, which
242       we first used in Moose::Cookbook::Basics::BinaryTree_AttributeFeatures.
243
244       The only new feature in the "Employee" class is the "override" method
245       modifier:
246
247         override 'full_name' => sub {
248             my $self = shift;
249             super() . ', ' . $self->title;
250         };
251
252       This is just a sugary alternative to Perl's built in "SUPER::" feature.
253       However, there is one difference. You cannot pass any arguments to
254       "super". Instead, Moose simply passes the same parameters that were
255       passed to the method.
256
257       A more detailed example of usage can be found in
258       t/recipes/basics_company_subtypes.t.
259

CONCLUSION

261       This recipe was intentionally longer and more complex. It illustrates
262       how Moose classes can be used together with type constraints, as well
263       as the density of information that you can get out of a small amount of
264       typing when using Moose.
265
266       This recipe also introduced the "subtype" function, the "required"
267       attribute, and the "override" method modifier.
268
269       We will revisit type constraints in future recipes, and cover type
270       coercion as well.
271

FOOTNOTES

273       (1) The value being checked is also passed as the first argument to the
274           "where" block, so it can be accessed as $_[0].
275
276       (2) Note that "ArrayRef[]" will not work. Moose will not parse this as
277           a container type, and instead you will have a new type named
278           "ArrayRef[]", which doesn't make any sense.
279

AUTHORS

281       •   Stevan Little <stevan@cpan.org>
282
283       •   Dave Rolsky <autarch@urth.org>
284
285       •   Jesse Luehrs <doy@cpan.org>
286
287       •   Shawn M Moore <sartak@cpan.org>
288
289       •   יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org>
290
291       •   Karen Etheridge <ether@cpan.org>
292
293       •   Florian Ragwitz <rafl@debian.org>
294
295       •   Hans Dieter Pearcey <hdp@cpan.org>
296
297       •   Chris Prather <chris@prather.org>
298
299       •   Matt S Trout <mstrout@cpan.org>
300
302       This software is copyright (c) 2006 by Infinity Interactive, Inc.
303
304       This is free software; you can redistribute it and/or modify it under
305       the same terms as the Perl 5 programming language system itself.
306
307
308
309perl v5.36.0                      2M0o2o3s-e0:2:-C0o6okbook::Basics::Company_Subtypes(3)
Impressum