cleanedup coercion docs
[gitmo/MooseX-Dependent.git] / README
CommitLineData
c08b66ad 1NAME
2 MooseX::Types::Parameterizable - Create your own Parameterizable Types.
3
4SYNOPSIS
afdaaf52 5 The follow is example usage.
c08b66ad 6
afdaaf52 7 package Test::MooseX::Types::Parameterizable::Synopsis;
8
9 use Moose;
c08b66ad 10 use MooseX::Types::Parameterizable qw(Parameterizable);
afdaaf52 11 use MooseX::Types::Moose qw(Str Int ArrayRef);
12 use MooseX::Types -declare=>[qw(Varchar)];
13
14 ## Create a type constraint that is a string but parameterizes an integer
15 ## that is used as a maximum length constraint on that string, similar to
4a786d1f 16 ## a SQL Varchar database type.
afdaaf52 17
18 subtype Varchar,
19 as Parameterizable[Str,Int],
20 where {
21 my($string, $int) = @_;
22 $int >= length($string) ? 1:0;
23 },
24 message { "'$_' is too long" };
25
26 coerce Varchar,
27 from ArrayRef,
28 via {
29 my ($arrayref, $int) = @_;
30 join('', @$arrayref);
31 };
32
33 has 'varchar_five' => (isa=>Varchar[5], is=>'ro', coerce=>1);
34 has 'varchar_ten' => (isa=>Varchar[10], is=>'ro');
35
36 ## Object created since attributes are valid
37 my $object1 = __PACKAGE__->new(
38 varchar_five => '1234',
39 varchar_ten => '123456789',
40 );
41
42 ## Dies with an invalid constraint for 'varchar_five'
43 my $object2 = __PACKAGE__->new(
4a786d1f 44 varchar_five => '12345678', ## too long!
afdaaf52 45 varchar_ten => '123456789',
46 );
47
48 ## varchar_five coerces as expected
49 my $object3 = __PACKAGE__->new(
4a786d1f 50 varchar_five => [qw/aa bb/], ## coerces to "aabb"
afdaaf52 51 varchar_ten => '123456789',
52 );
53
54 See t/05-pod-examples.t for runnable versions of all POD code
c08b66ad 55
56DESCRIPTION
57 A MooseX::Types library for creating parameterizable types. A
58 parameterizable type constraint for all intents and uses is a subclass
4a786d1f 59 of a parent type, but adds additional type parameters which are
60 available to constraint callbacks (such as inside the 'where' clause of
61 a type constraint definition) or in the coercions.
c08b66ad 62
4a786d1f 63 If you have Moose experience, you probably are familiar with the builtin
64 parameterizable type constraints 'ArrayRef' and 'HashRef'. This type
65 constraint lets you generate your own versions of parameterized
66 constraints that work similarly. See Moose::Util::TypeConstraints for
67 more.
68
69 Using this type constraint, you can generate new type constraints that
70 have additional runtime advice, such as being able to specify maximum
71 and minimum values for an Int (integer) type constraint:
c08b66ad 72
6c0e3459 73 subtype Range,
74 as Dict[max=>Int, min=>Int],
75 where {
76 my ($range) = @_;
77 return $range->{max} > $range->{min};
78 };
79
80 subtype RangedInt,
81 as Parameterizable[Int, Range],
82 where {
83 my ($value, $range) = @_;
84 return ($value >= $range->{min} &&
85 $value <= $range->{max});
86 };
87
88 RangedInt([{min=>10,max=>100}])->check(50); ## OK
89 RangedInt([{min=>50, max=>75}])->check(99); ## Not OK, 99 exceeds max
c08b66ad 90
4a786d1f 91 The type parameter must be valid against the type constraint given. If
92 you pass an invalid value this throws a hard Moose exception. You'll
93 need to capture it in an eval or related exception catching system (see
94 TryCatch or <Try::Tiny>.) For example the following would throw a hard
95 error (and not just return false)
c08b66ad 96
6c0e3459 97 RangedInt([{min=>99, max=>10}])->check(10); ## Not OK, not a valid Range!
c08b66ad 98
99 If you can't accept a hard exception here, you'll need to test the
100 constraining values first, as in:
101
6c0e3459 102 my $range = {min=>99, max=>10};
103 if(my $err = Range->validate($range)) {
104 ## Handle #$err
105 } else {
106 RangedInt($range)->check(99);
107 }
c08b66ad 108
109 Please note that for ArrayRef or HashRef parameterizable type
110 constraints, as in the example above, as a convenience we automatically
111 ref the incoming type parameters, so that the above could also be
112 written as:
113
6c0e3459 114 RangedInt([min=>10,max=>100])->check(50); ## OK
115 RangedInt([min=>50, max=>75])->check(99); ## Not OK, 99 exceeds max
116 RangedInt([min=>99, max=>10])->check(10); ## Exception, not a valid Range!
c08b66ad 117
118 This is the preferred syntax, as it improve readability and adds to the
119 conciseness of your type constraint declarations. An exception wil be
120 thrown if your type parameters don't match the required reference type.
121
122 Also not that if you 'chain' parameterization results with a method call
123 like:
124
6c0e3459 125 TypeConstraint([$ob])->method;
c08b66ad 126
127 You need to have the "(...)" around the ArrayRef in the Type Constraint
128 parameters. This seems to have something to do with the precendent level
129 of "->". Patches or thoughts welcomed. You only need to do this in the
130 above case which I imagine is not a very common case.
131
132 ==head2 Subtyping a Parameterizable type constraints
133
134 When subclassing a parameterizable type you must be careful to match
135 either the required type parameter type constraint, or if
136 re-parameterizing, the new type constraints are a subtype of the parent.
137 For example:
138
6c0e3459 139 subtype RangedInt,
140 as Parameterizable[Int, Range],
141 where {
142 my ($value, $range) = @_;
143 return ($value >= $range->{min} &&
144 $value =< $range->{max});
145 };
c08b66ad 146
147 Example subtype with additional constraints:
148
6c0e3459 149 subtype PositiveRangedInt,
150 as RangedInt,
151 where {
152 shift >= 0;
153 };
c08b66ad 154
155 Or you could have done the following instead:
156
6c0e3459 157 ## Subtype of Int for positive numbers
158 subtype PositiveInt,
159 as Int,
160 where {
161 my ($value, $range) = @_;
162 return $value >= 0;
163 };
164
165 ## subtype Range to re-parameterize Range with subtypes
166 subtype PositiveRange,
167 as Range[max=>PositiveInt, min=>PositiveInt];
168
169 ## create subtype via reparameterizing
170 subtype PositiveRangedInt,
171 as RangedInt[PositiveRange];
c08b66ad 172
173 Notice how re-parameterizing the parameterizable type 'RangedInt' works
174 slightly differently from re-parameterizing 'PositiveRange' Although it
175 initially takes two type constraint values to declare a parameterizable
176 type, should you wish to later re-parameterize it, you only use a
177 subtype of the second type parameter (the parameterizable type
178 constraint) since the first type constraint sets the parent type for the
179 parameterizable type. In other words, given the example above, a type
180 constraint of 'RangedInt' would have a parent of 'Int', not
181 'Parameterizable' and for all intends and uses you could stick it
182 wherever you'd need an Int.
183
6c0e3459 184 subtype NameAge,
185 as Tuple[Str, Int];
186
187 ## re-parameterized subtypes of NameAge containing a Parameterizable Int
188 subtype NameBetween18and35Age,
189 as NameAge[
190 Str,
191 PositiveRangedInt[min=>18,max=>35],
192 ];
c08b66ad 193
194 One caveat is that you can't stick an unparameterized parameterizable
195 type inside a structure, such as MooseX::Types::Structured since that
196 would require the ability to convert a 'containing' type constraint into
197 a parameterizable type, which is a capacity we current don't have.
198
199 Coercions
200 Parameterizable types have some limited support for coercions. Several
201 things must be kept in mind. The first is that the coercion targets the
202 type constraint which is being made parameterizable, Not the
203 parameterizable type. So for example if you create a Parameterizable
204 type like:
205
6c0e3459 206 subtype RequiredAgeInYears,
207 as Int;
c08b66ad 208
6c0e3459 209 subtype PersonOverAge,
210 as Parameterizable[Person, RequiredAgeInYears]
211 where {
212 my ($person, $required_years_old) = @_;
213 return $person->years_old > $required_years_old;
214 }
c08b66ad 215
216 This would validate the following:
217
6c0e3459 218 my $person = Person->new(age=>35);
219 PersonOverAge([18])->check($person);
c08b66ad 220
221 You can then apply the following coercion
222
6c0e3459 223 coerce PersonOverAge,
224 from Dict[age=>int],
225 via {Person->new(%$_)},
226 from Int,
227 via {Person->new(age=>$_)};
c08b66ad 228
229 This coercion would then apply to all the following:
230
6c0e3459 231 PersonOverAge([18])->check(30); ## via the Int coercion
232 PersonOverAge([18])->check({age=>50}); ## via the Dict coercion
c08b66ad 233
234 However, you are not allowed to place coercions on parameterizable types
235 that have had their constraining value filled, nor subtypes of such. For
236 example:
237
6c0e3459 238 coerce PersonOverAge[18],
239 from DateTime,
240 via {$_->years};
c08b66ad 241
242 That would generate a hard exception. This is a limitation for now until
243 I can devise a smarter way to cache the generated type constraints.
244 However, I doubt it will be a significant limitation, since the general
245 use case is supported.
246
247 Lastly, the constraining value is available in the coercion in much the
248 same way it is available to the constraint.
249
6c0e3459 250 ## Create a type constraint where a Person must be in the set
251 subtype PersonInSet,
252 as Parameterizable[Person, PersonSet],
253 where {
254 my ($person, $person_set) = @_;
255 $person_set->find($person);
256 }
257
258 coerce PersonInSet,
259 from HashRef,
260 via {
261 my ($hashref, $person_set) = @_;
262 return $person_set->create($hash_ref);
263 };
c08b66ad 264
265 Recursion
4a786d1f 266 TBD - Need more tests.
c08b66ad 267
268TYPE CONSTRAINTS
269 This type library defines the following constraints.
270
271 Parameterizable[ParentTypeConstraint, ParameterizableValueTypeConstraint]
272 Create a subtype of ParentTypeConstraint with a dependency on a value
273 that can pass the ParameterizableValueTypeConstraint. If
274 ParameterizableValueTypeConstraint is empty we default to the 'Any' type
275 constraint (see Moose::Util::TypeConstraints).
276
277 This creates a type constraint which must be further parameterized at
278 later time before it can be used to ->check or ->validate a value.
279 Attempting to do so will cause an exception.
280
281AUTHOR
282 John Napiorkowski, "<jjnapiork@cpan.org>"
283
284COPYRIGHT & LICENSE
285 This program is free software; you can redistribute it and/or modify it
286 under the same terms as Perl itself.
287