Add built local::lib
[catagits/Gitalist.git] / local-lib5 / man / man3 / Moose::Cookbook::Basics::Recipe5.3pm
CommitLineData
3fea05b9 1.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.3
2.\"
3.\" Standard preamble:
4.\" ========================================================================
5.de Sh \" Subsection heading
6.br
7.if t .Sp
8.ne 5
9.PP
10\fB\\$1\fR
11.PP
12..
13.de Sp \" Vertical space (when we can't use .PP)
14.if t .sp .5v
15.if n .sp
16..
17.de Vb \" Begin verbatim text
18.ft CW
19.nf
20.ne \\$1
21..
22.de Ve \" End verbatim text
23.ft R
24.fi
25..
26.\" Set up some character translations and predefined strings. \*(-- will
27.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
28.\" double quote, and \*(R" will give a right double quote. | will give a
29.\" real vertical bar. \*(C+ will give a nicer C++. Capital omega is used to
30.\" do unbreakable dashes and therefore won't be available. \*(C` and \*(C'
31.\" expand to `' in nroff, nothing in troff, for use with C<>.
32.tr \(*W-|\(bv\*(Tr
33.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
34.ie n \{\
35. ds -- \(*W-
36. ds PI pi
37. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
38. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
39. ds L" ""
40. ds R" ""
41. ds C` ""
42. ds C' ""
43'br\}
44.el\{\
45. ds -- \|\(em\|
46. ds PI \(*p
47. ds L" ``
48. ds R" ''
49'br\}
50.\"
51.\" If the F register is turned on, we'll generate index entries on stderr for
52.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index
53.\" entries marked with X<> in POD. Of course, you'll have to process the
54.\" output yourself in some meaningful fashion.
55.if \nF \{\
56. de IX
57. tm Index:\\$1\t\\n%\t"\\$2"
58..
59. nr % 0
60. rr F
61.\}
62.\"
63.\" For nroff, turn off justification. Always turn off hyphenation; it makes
64.\" way too many mistakes in technical documents.
65.hy 0
66.if n .na
67.\"
68.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
69.\" Fear. Run. Save yourself. No user-serviceable parts.
70. \" fudge factors for nroff and troff
71.if n \{\
72. ds #H 0
73. ds #V .8m
74. ds #F .3m
75. ds #[ \f1
76. ds #] \fP
77.\}
78.if t \{\
79. ds #H ((1u-(\\\\n(.fu%2u))*.13m)
80. ds #V .6m
81. ds #F 0
82. ds #[ \&
83. ds #] \&
84.\}
85. \" simple accents for nroff and troff
86.if n \{\
87. ds ' \&
88. ds ` \&
89. ds ^ \&
90. ds , \&
91. ds ~ ~
92. ds /
93.\}
94.if t \{\
95. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
96. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
97. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
98. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
99. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
100. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
101.\}
102. \" troff and (daisy-wheel) nroff accents
103.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
104.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
105.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
106.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
107.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
108.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
109.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
110.ds ae a\h'-(\w'a'u*4/10)'e
111.ds Ae A\h'-(\w'A'u*4/10)'E
112. \" corrections for vroff
113.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
114.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
115. \" for low resolution devices (crt and lpr)
116.if \n(.H>23 .if \n(.V>19 \
117\{\
118. ds : e
119. ds 8 ss
120. ds o a
121. ds d- d\h'-1'\(ga
122. ds D- D\h'-1'\(hy
123. ds th \o'bp'
124. ds Th \o'LP'
125. ds ae ae
126. ds Ae AE
127.\}
128.rm #[ #] #H #V #F C
129.\" ========================================================================
130.\"
131.IX Title "Moose::Cookbook::Basics::Recipe5 3"
132.TH Moose::Cookbook::Basics::Recipe5 3 "2009-03-14" "perl v5.8.7" "User Contributed Perl Documentation"
133.SH "NAME"
134Moose::Cookbook::Basics::Recipe5 \- More subtypes, coercion in a \fBRequest\fR class
135.SH "SYNOPSIS"
136.IX Header "SYNOPSIS"
137.Vb 3
138\& package Request;
139\& use Moose;
140\& use Moose::Util::TypeConstraints;
141.Ve
142.PP
143.Vb 3
144\& use HTTP::Headers ();
145\& use Params::Coerce ();
146\& use URI ();
147.Ve
148.PP
149.Vb 1
150\& subtype 'My::Types::HTTP::Headers' => as class_type('HTTP::Headers');
151.Ve
152.PP
153.Vb 5
154\& coerce 'My::Types::HTTP::Headers'
155\& => from 'ArrayRef'
156\& => via { HTTP::Headers\->new( @{$_} ) }
157\& => from 'HashRef'
158\& => via { HTTP::Headers\->new( %{$_} ) };
159.Ve
160.PP
161.Vb 1
162\& subtype 'My::Types::URI' => as class_type('URI');
163.Ve
164.PP
165.Vb 7
166\& coerce 'My::Types::URI'
167\& => from 'Object'
168\& => via { $_\->isa('URI')
169\& ? $_
170\& : Params::Coerce::coerce( 'URI', $_ ); }
171\& => from 'Str'
172\& => via { URI\->new( $_, 'http' ) };
173.Ve
174.PP
175.Vb 3
176\& subtype 'Protocol'
177\& => as 'Str'
178\& => where { /^HTTP\e/[0\-9]\e.[0\-9]$/ };
179.Ve
180.PP
181.Vb 10
182\& has 'base' => ( is => 'rw', isa => 'My::Types::URI', coerce => 1 );
183\& has 'uri' => ( is => 'rw', isa => 'My::Types::URI', coerce => 1 );
184\& has 'method' => ( is => 'rw', isa => 'Str' );
185\& has 'protocol' => ( is => 'rw', isa => 'Protocol' );
186\& has 'headers' => (
187\& is => 'rw',
188\& isa => 'My::Types::HTTP::Headers',
189\& coerce => 1,
190\& default => sub { HTTP::Headers\->new }
191\& );
192.Ve
193.SH "DESCRIPTION"
194.IX Header "DESCRIPTION"
195This recipe introduces type coercions, which are defined with the
196\&\f(CW\*(C`coerce\*(C'\fR sugar function. Coercions are attached to existing type
197constraints, and define a (one\-way) transformation from one type to
198another.
199.PP
200This is very powerful, but it's also magical, so you have to
201explicitly ask for an attribute to be coerced. To do this, you must
202set the \f(CW\*(C`coerce\*(C'\fR attribute option to a true value.
203.PP
204First, we create the subtype to which we will coerce the other types:
205.PP
206.Vb 1
207\& subtype 'My::Types::HTTP::Headers' => as class_type('HTTP::Headers');
208.Ve
209.PP
210We are creating a subtype rather than using \f(CW\*(C`HTTP::Headers\*(C'\fR as a type
211directly. The reason we do this is coercions are global, and a
212coercion defined for \f(CW\*(C`HTTP::Headers\*(C'\fR in our \f(CW\*(C`Request\*(C'\fR class would
213then be defined for \fIall\fR Moose-using classes in the current Perl
214interpreter. It's a best practice to
215avoid this sort of namespace pollution.
216.PP
217The \f(CW\*(C`class_type\*(C'\fR sugar function is simply a shortcut for this:
218.PP
219.Vb 3
220\& subtype 'HTTP::Headers'
221\& => as 'Object'
222\& => where { $_\->isa('HTTP::Headers') };
223.Ve
224.PP
225Internally, Moose creates a type constraint for each Moose-using
226class, but for non-Moose classes, the type must be declared
227explicitly.
228.PP
229We could go ahead and use this new type directly:
230.PP
231.Vb 5
232\& has 'headers' => (
233\& is => 'rw',
234\& isa => 'HTTP::Headers',
235\& default => sub { HTTP::Headers\->new }
236\& );
237.Ve
238.PP
239This creates a simple attribute which defaults to an empty instance of
240HTTP::Headers.
241.PP
242The constructor for HTTP::Headers accepts a list of key-value pairs
243representing the \s-1HTTP\s0 header fields. In Perl, such a list could be
244stored in an \s-1ARRAY\s0 or \s-1HASH\s0 reference. We want our \f(CW\*(C`headers\*(C'\fR attribute
245to accept those data structure instead of an \fBHTTP::Headers\fR
246instance, and just do the right thing. This is exactly what coercion
247is for:
248.PP
249.Vb 5
250\& coerce 'My::Types::HTTP::Headers'
251\& => from 'ArrayRef'
252\& => via { HTTP::Headers\->new( @{$_} ) }
253\& => from 'HashRef'
254\& => via { HTTP::Headers\->new( %{$_} ) };
255.Ve
256.PP
257The first argument to \f(CW\*(C`coerce\*(C'\fR is the type \fIto\fR which we are
258coercing. Then we give it a set of \f(CW\*(C`from\*(C'\fR/\f(CW\*(C`via\*(C'\fR clauses. The \f(CW\*(C`from\*(C'\fR
259function takes some other type name and \f(CW\*(C`via\*(C'\fR takes a subroutine
260reference which actually does the coercion.
261.PP
262However, defining the coercion doesn't do anything until we tell Moose
263we want a particular attribute to be coerced:
264.PP
265.Vb 6
266\& has 'headers' => (
267\& is => 'rw',
268\& isa => 'My::Types::HTTP::Headers',
269\& coerce => 1,
270\& default => sub { HTTP::Headers\->new }
271\& );
272.Ve
273.PP
274Now, if we use an \f(CW\*(C`ArrayRef\*(C'\fR or \f(CW\*(C`HashRef\*(C'\fR to populate \f(CW\*(C`headers\*(C'\fR, it
275will be coerced into a new HTTP::Headers instance. With the
276coercion in place, the following lines of code are all equivalent:
277.PP
278.Vb 3
279\& $foo\->headers( HTTP::Headers\->new( bar => 1, baz => 2 ) );
280\& $foo\->headers( [ 'bar', 1, 'baz', 2 ] );
281\& $foo\->headers( { bar => 1, baz => 2 } );
282.Ve
283.PP
284As you can see, careful use of coercions can produce a very open
285interface for your class, while still retaining the \*(L"safety\*(R" of your
286type constraint checks. (1)
287.PP
288Our next coercion shows how we can leverage existing \s-1CPAN\s0 modules to
289help implement coercions. In this case we use Params::Coerce.
290.PP
291Once again, we need to declare a class type for our non-Moose \s-1URI\s0
292class:
293.PP
294.Vb 1
295\& subtype 'My::Types::URI' => as class_type('URI');
296.Ve
297.PP
298Then we define the coercion:
299.PP
300.Vb 7
301\& coerce 'My::Types::URI'
302\& => from 'Object'
303\& => via { $_\->isa('URI')
304\& ? $_
305\& : Params::Coerce::coerce( 'URI', $_ ); }
306\& => from 'Str'
307\& => via { URI\->new( $_, 'http' ) };
308.Ve
309.PP
310The first coercion takes any object and makes it a \f(CW\*(C`URI\*(C'\fR object. The
311coercion system isn't that smart, and does not check if the object is
312already a \s-1URI\s0, so we check for that ourselves. If it's not a \s-1URI\s0
313already, we let Params::Coerce do its magic, and we just use its
314return value.
315.PP
316If Params::Coerce didn't return a \s-1URI\s0 object (for whatever
317reason), Moose would throw a type constraint error.
318.PP
319The other coercion takes a string and converts to a \s-1URI\s0. In this
320case, we are using the coercion to apply a default behavior, where a
321string is assumed to be an \f(CW\*(C`http\*(C'\fR \s-1URI\s0.
322.PP
323Finally, we need to make sure our attributes enable coercion.
324.PP
325.Vb 2
326\& has 'base' => ( is => 'rw', isa => 'My::Types::URI', coerce => 1 );
327\& has 'uri' => ( is => 'rw', isa => 'My::Types::URI', coerce => 1 );
328.Ve
329.PP
330Re-using the coercion lets us enforce a consistent \s-1API\s0 across multiple
331attributes.
332.SH "CONCLUSION"
333.IX Header "CONCLUSION"
334This recipe showed the use of coercions to create a more flexible and
335DWIM-y \s-1API\s0. Like any powerful magic, we recommend some
336caution. Sometimes it's better to reject a value than just guess at
337how to \s-1DWIM\s0.
338.PP
339We also showed the use of the \f(CW\*(C`class_type\*(C'\fR sugar function as a
340shortcut for defining a new subtype of \f(CW\*(C`Object\*(C'\fR
341.SH "FOOTNOTES"
342.IX Header "FOOTNOTES"
343.IP "(1)" 4
344.IX Item "(1)"
345This particular example could be safer. Really we only want to coerce
346an array with an \fIeven\fR number of elements. We could create a new
347\&\f(CW\*(C`EvenElementArrayRef\*(C'\fR type, and then coerce from that type, as
348opposed to from a plain \f(CW\*(C`ArrayRef\*(C'\fR
349.SH "AUTHORS"
350.IX Header "AUTHORS"
351Stevan Little <stevan@iinteractive.com>
352.PP
353Dave Rolsky <autarch@urth.org>
354.SH "COPYRIGHT AND LICENSE"
355.IX Header "COPYRIGHT AND LICENSE"
356Copyright 2006\-2009 by Infinity Interactive, Inc.
357.PP
358<http://www.iinteractive.com>
359.PP
360This library is free software; you can redistribute it and/or modify
361it under the same terms as Perl itself.