Merge pull request #3 from brianphillips/master
[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
7fcab9b4 14 Create a type constraint that is similar to SQL Varchar type.
afdaaf52 15
16 subtype Varchar,
17 as Parameterizable[Str,Int],
18 where {
19 my($string, $int) = @_;
20 $int >= length($string) ? 1:0;
21 },
22 message { "'$_' is too long" };
23
7fcab9b4 24 Coerce an ArrayRef to a string via concatenation.
25
afdaaf52 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');
7fcab9b4 35
36 Object created since attributes are valid
37
afdaaf52 38 my $object1 = __PACKAGE__->new(
39 varchar_five => '1234',
40 varchar_ten => '123456789',
41 );
42
7fcab9b4 43 Dies with an invalid constraint for 'varchar_five'
44
afdaaf52 45 my $object2 = __PACKAGE__->new(
4a786d1f 46 varchar_five => '12345678', ## too long!
afdaaf52 47 varchar_ten => '123456789',
48 );
49
7fcab9b4 50 varchar_five coerces as expected
51
afdaaf52 52 my $object3 = __PACKAGE__->new(
4a786d1f 53 varchar_five => [qw/aa bb/], ## coerces to "aabb"
afdaaf52 54 varchar_ten => '123456789',
55 );
56
57 See t/05-pod-examples.t for runnable versions of all POD code
c08b66ad 58
59DESCRIPTION
60 A MooseX::Types library for creating parameterizable types. A
61 parameterizable type constraint for all intents and uses is a subclass
4a786d1f 62 of a parent type, but adds additional type parameters which are
63 available to constraint callbacks (such as inside the 'where' clause of
461e0f82 64 a type constraint definition) or in the coercions you define for a given
65 type constraint.
c08b66ad 66
4a786d1f 67 If you have Moose experience, you probably are familiar with the builtin
68 parameterizable type constraints 'ArrayRef' and 'HashRef'. This type
69 constraint lets you generate your own versions of parameterized
70 constraints that work similarly. See Moose::Util::TypeConstraints for
71 more.
72
73 Using this type constraint, you can generate new type constraints that
74 have additional runtime advice, such as being able to specify maximum
75 and minimum values for an Int (integer) type constraint:
c08b66ad 76
6c0e3459 77 subtype Range,
78 as Dict[max=>Int, min=>Int],
79 where {
80 my ($range) = @_;
81 return $range->{max} > $range->{min};
82 };
83
84 subtype RangedInt,
85 as Parameterizable[Int, Range],
86 where {
87 my ($value, $range) = @_;
88 return ($value >= $range->{min} &&
89 $value <= $range->{max});
90 };
91
92 RangedInt([{min=>10,max=>100}])->check(50); ## OK
7fcab9b4 93 RangedInt([{min=>50, max=>75}])->check(99); ## Not OK, exceeds max
c08b66ad 94
461e0f82 95 This is useful since it lets you generate common patterns of type
96 constraints rather than build a custom type constraint for all similar
97 cases.
98
99 The type parameter must be valid against the 'constrainting' type
100 constraint used in the Parameterizable condition. If you pass an invalid
101 value this throws a hard Moose exception. You'll need to capture it in
102 an eval or related exception catching system (see TryCatch or
103 Try::Tiny.)
104
105 For example the following would throw a hard error (and not just return
106 false)
c08b66ad 107
6c0e3459 108 RangedInt([{min=>99, max=>10}])->check(10); ## Not OK, not a valid Range!
c08b66ad 109
461e0f82 110 In the above case the 'min' value is larger than the 'max', which
111 violates the Range constraint. We throw a hard error here since I think
112 incorrect type parameters are most likely to be the result of a typo or
113 other true error conditions.
114
115 If you can't accept a hard exception here, you can either trap it as
116 advised above or you need to test the constraining values first, as in:
c08b66ad 117
6c0e3459 118 my $range = {min=>99, max=>10};
119 if(my $err = Range->validate($range)) {
120 ## Handle #$err
121 } else {
122 RangedInt($range)->check(99);
123 }
c08b66ad 124
125 Please note that for ArrayRef or HashRef parameterizable type
126 constraints, as in the example above, as a convenience we automatically
127 ref the incoming type parameters, so that the above could also be
128 written as:
129
6c0e3459 130 RangedInt([min=>10,max=>100])->check(50); ## OK
7fcab9b4 131 RangedInt([min=>50, max=>75])->check(99); ## Not OK, exceeds max
132 RangedInt([min=>99, max=>10])->check(10); ## Exception, not valid Range
c08b66ad 133
134 This is the preferred syntax, as it improve readability and adds to the
461e0f82 135 conciseness of your type constraint declarations.
c08b66ad 136
7fcab9b4 137 Also note that if you 'chain' parameterization results with a method
138 call like:
c08b66ad 139
6c0e3459 140 TypeConstraint([$ob])->method;
c08b66ad 141
142 You need to have the "(...)" around the ArrayRef in the Type Constraint
7fcab9b4 143 parameters. You can skip the wrapping parenthesis in the most common
144 cases, such as when you use the type constraint in the options section
145 of a Moose attribute declaration, or when defining type libraries.
c08b66ad 146
7fcab9b4 147 Subtyping a Parameterizable type constraints
c08b66ad 148 When subclassing a parameterizable type you must be careful to match
149 either the required type parameter type constraint, or if
150 re-parameterizing, the new type constraints are a subtype of the parent.
151 For example:
152
6c0e3459 153 subtype RangedInt,
154 as Parameterizable[Int, Range],
155 where {
156 my ($value, $range) = @_;
157 return ($value >= $range->{min} &&
158 $value =< $range->{max});
159 };
c08b66ad 160
161 Example subtype with additional constraints:
162
6c0e3459 163 subtype PositiveRangedInt,
164 as RangedInt,
165 where {
166 shift >= 0;
167 };
c08b66ad 168
461e0f82 169 In this case you'd now have a parameterizable type constraint which
170 would work like:
7fcab9b4 171
172 Test::More::ok PositiveRangedInt([{min=>-10, max=>75}])->check(5);
173 Test::More::ok !PositiveRangedInt([{min=>-10, max=>75}])->check(-5);
174
175 Of course the above is somewhat counter-intuitive to the reader, since
176 we have defined our 'RangedInt' in such as way as to let you declare
177 negative ranges. For the moment each type constraint rule is apply
178 without knowledge of any other rule, nor can a rule 'inform' existing
179 rules. This is a limitation of the current system. However, you could
180 instead do the following:
c08b66ad 181
6c0e3459 182 ## Subtype of Int for positive numbers
183 subtype PositiveInt,
184 as Int,
185 where {
186 my ($value, $range) = @_;
187 return $value >= 0;
188 };
189
190 ## subtype Range to re-parameterize Range with subtypes
191 subtype PositiveRange,
192 as Range[max=>PositiveInt, min=>PositiveInt];
193
194 ## create subtype via reparameterizing
195 subtype PositiveRangedInt,
196 as RangedInt[PositiveRange];
c08b66ad 197
7fcab9b4 198 This would constrain values in the same way as the previous type
199 constraint but have the bonus that you'd throw a hard exception if you
200 try to use an incorrect range:
201
202 Test::More::ok PositiveRangedInt([{min=>10, max=>75}])->check(15); ## OK
203 Test::More::ok !PositiveRangedInt([{min=>-10, max=>75}])->check(-5); ## Dies
204
c08b66ad 205 Notice how re-parameterizing the parameterizable type 'RangedInt' works
206 slightly differently from re-parameterizing 'PositiveRange' Although it
207 initially takes two type constraint values to declare a parameterizable
208 type, should you wish to later re-parameterize it, you only use a
7fcab9b4 209 subtype of the extra type parameter (the parameterizable type
210 constraints) since the first type constraint sets the parent type for
211 the parameterizable type.
c08b66ad 212
7fcab9b4 213 In other words, given the example above, a type constraint of
214 'RangedInt' would have a parent of 'Int', not 'Parameterizable' and for
461e0f82 215 all intends and uses you could stick it wherever you'd need an Int. You
216 can't change the parent, even to make it a subclass of Int.
c08b66ad 217
7fcab9b4 218 Coercions
461e0f82 219 A type coercion is a rule that allows you to transform one type from one
220 or more other types. Please see Moose::Cookbook::Basics::Recipe5 for an
221 example of type coercions if you are not familiar with the subject.
7fcab9b4 222
461e0f82 223 MooseX::Types::Parameterizable supports type coercions in all the ways
7fcab9b4 224 you would expect. In addition, it also supports a limited form of type
225 coercion inheritance. Generally speaking, type constraints don't inherit
226 coercions since this would rapidly become confusing. However, since your
227 parameterizable type is intended to become parameterized in order to be
228 useful, we support inheriting from a 'base' parameterizable type
229 constraint to its 'child' parameterized sub types.
230
231 For the purposes of this discussion, a parameterizable type is a subtype
232 created when you say, "as Parameterizable[..." in your sub type
461e0f82 233 declaration. For example:
c08b66ad 234
7fcab9b4 235 subtype Varchar,
236 as Parameterizable[Str, Int],
6c0e3459 237 where {
7fcab9b4 238 my($string, $int) = @_;
239 $int >= length($string) ? 1:0;
240 },
241 message { "'$_' is too long" };
c08b66ad 242
461e0f82 243 This is the "SYNOPSIS" example, which creates a new parameterizable
7fcab9b4 244 subtype of Str which takes a single type parameter which must be an Int.
245 This Int is used to constrain the allowed length of the Str value.
c08b66ad 246
7fcab9b4 247 Now, this new sub type, "Varchar", is parameterizable since it can take
248 a type parameter. We can apply some coercions to it:
c08b66ad 249
7fcab9b4 250 coerce Varchar,
251 from Object,
252 via { "$_"; }, ## stringify the object
253 from ArrayRef,
254 via { join '',@$_ }; ## convert array to string
c08b66ad 255
7fcab9b4 256 This parameterizable subtype, "Varchar" itself is something you'd never
257 use directly to constraint a value. In other words you'd never do
258 something like:
c08b66ad 259
461e0f82 260 has name => (isa=>Varchar, ...); ## Why not just use a Str?
c08b66ad 261
7fcab9b4 262 You are going to do this:
c08b66ad 263
7fcab9b4 264 has name => (isa=>Varchar[40], ...)
c08b66ad 265
7fcab9b4 266 Which is actually useful. However, "Varchar[40]" is a parameterized
267 type, it is a subtype of the parameterizable "Varchar" and it inherits
268 coercions from its parent. This may be a bit surprising to Moose
269 developers, but I believe this is the actual desired behavior.
c08b66ad 270
7fcab9b4 271 You can of course add new coercions to a subtype of a parameterizable
272 type:
c08b66ad 273
7fcab9b4 274 subtype MySpecialVarchar,
275 as Varchar;
c08b66ad 276
7fcab9b4 277 coerce MySpecialVarchar,
278 from ...
279
280 In which case this new parameterizable type would NOT inherit coercions
281 from it's parent parameterizable type (Varchar). This is done in keeping
282 with how generally speaking Moose type constraints avoid complicated
283 coercion inheritance schemes, however I am open to discussion if there
284 are valid use cases.
285
286 NOTE: One thing you can't do is add a coercion to an already
287 parameterized type. Currently the following would throw a hard error:
288
289 subtype 40CharStr,
290 as Varchar[40];
291
292 coerce 40CharStr, ... # BANG!
293
294 This limitation is enforced since generally we expect coercions on the
295 parent. However if good use cases arise we may lift this in the future.
296
297 In general we are trying to take a conservative approach that keeps in
298 line with how most Moose authors expect type constraints to work.
c08b66ad 299
300 Recursion
7fcab9b4 301 TBD - Needs a use case... Anyone?
c08b66ad 302
303TYPE CONSTRAINTS
304 This type library defines the following constraints.
305
461e0f82 306 Parameterizable[ParentTypeConstraint, ConstrainingValueTypeConstraint]
c08b66ad 307 Create a subtype of ParentTypeConstraint with a dependency on a value
461e0f82 308 that can pass the ConstrainingValueTypeConstraint. If
309 ConstrainingValueTypeConstraint is empty we default to the 'Any' type
310 constraint (see Moose::Util::TypeConstraints). This is useful if you are
311 creating some base Parameterizable type constraints that you intend to
312 sub class.
313
314SEE ALSO
315 The following modules or resources may be of interest.
c08b66ad 316
461e0f82 317 Moose, Moose::Meta::TypeConstraint, MooseX::Types
c08b66ad 318
319AUTHOR
320 John Napiorkowski, "<jjnapiork@cpan.org>"
321
322COPYRIGHT & LICENSE
323 This program is free software; you can redistribute it and/or modify it
324 under the same terms as Perl itself.
325