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