Merge pull request #3 from brianphillips/master
[gitmo/MooseX-Dependent.git] / README
1 NAME
2     MooseX::Types::Parameterizable - Create your own Parameterizable Types.
3
4 SYNOPSIS
5     The follow is example usage.
6
7         package Test::MooseX::Types::Parameterizable::Synopsis;
8
9         use Moose;
10         use MooseX::Types::Parameterizable qw(Parameterizable);
11         use MooseX::Types::Moose qw(Str Int ArrayRef);
12         use MooseX::Types -declare=>[qw(Varchar)];
13
14     Create a type constraint that is similar to SQL Varchar type.
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
24     Coerce an ArrayRef to a string via concatenation.
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
38         my $object1 = __PACKAGE__->new(
39             varchar_five => '1234',
40             varchar_ten => '123456789',
41         );
42
43     Dies with an invalid constraint for 'varchar_five'
44
45         my $object2 = __PACKAGE__->new(
46             varchar_five => '12345678',  ## too long!
47             varchar_ten => '123456789',
48         );
49
50     varchar_five coerces as expected
51
52         my $object3 = __PACKAGE__->new(
53             varchar_five => [qw/aa bb/],  ## coerces to "aabb"
54             varchar_ten => '123456789',
55         );
56
57     See t/05-pod-examples.t for runnable versions of all POD code
58
59 DESCRIPTION
60     A MooseX::Types library for creating parameterizable types. A
61     parameterizable type constraint for all intents and uses is a subclass
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 you define for a given
65     type constraint.
66
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:
76
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
93         RangedInt([{min=>50, max=>75}])->check(99); ## Not OK, exceeds max
94
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)
107
108         RangedInt([{min=>99, max=>10}])->check(10); ## Not OK, not a valid Range!
109
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:
117
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         }
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
130         RangedInt([min=>10,max=>100])->check(50); ## OK
131         RangedInt([min=>50, max=>75])->check(99); ## Not OK, exceeds max
132         RangedInt([min=>99, max=>10])->check(10); ## Exception, not valid Range
133
134     This is the preferred syntax, as it improve readability and adds to the
135     conciseness of your type constraint declarations.
136
137     Also note that if you 'chain' parameterization results with a method
138     call like:
139
140         TypeConstraint([$ob])->method;
141
142     You need to have the "(...)" around the ArrayRef in the Type Constraint
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.
146
147   Subtyping a Parameterizable type constraints
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
153         subtype RangedInt,
154             as Parameterizable[Int, Range],
155             where {
156                 my ($value, $range) = @_;
157                 return ($value >= $range->{min} &&
158                  $value =< $range->{max});
159             };
160
161     Example subtype with additional constraints:
162
163         subtype PositiveRangedInt,
164             as RangedInt,
165             where {
166                 shift >= 0;              
167             };
168
169     In this case you'd now have a parameterizable type constraint which
170     would work like:
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:
181
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];
197
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
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
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.
212
213     In other words, given the example above, a type constraint of
214     'RangedInt' would have a parent of 'Int', not 'Parameterizable' and for
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.
217
218   Coercions
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.
222
223     MooseX::Types::Parameterizable supports type coercions in all the ways
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
233     declaration. For example:
234
235         subtype Varchar,
236           as Parameterizable[Str, Int],
237           where {
238             my($string, $int) = @_;
239             $int >= length($string) ? 1:0;
240           },
241           message { "'$_' is too long"  };
242
243     This is the "SYNOPSIS" example, which creates a new parameterizable
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.
246
247     Now, this new sub type, "Varchar", is parameterizable since it can take
248     a type parameter. We can apply some coercions to it:
249
250         coerce Varchar,
251           from Object,
252           via { "$_"; },  ## stringify the object
253           from ArrayRef,
254           via { join '',@$_ };  ## convert array to string
255
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:
259
260         has name => (isa=>Varchar, ...); ## Why not just use a Str?
261
262     You are going to do this:
263
264         has name => (isa=>Varchar[40], ...)
265
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.
270
271     You can of course add new coercions to a subtype of a parameterizable
272     type:
273
274         subtype MySpecialVarchar,
275           as Varchar;
276
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.
299
300   Recursion
301         TBD - Needs a use case... Anyone?
302
303 TYPE CONSTRAINTS
304     This type library defines the following constraints.
305
306   Parameterizable[ParentTypeConstraint, ConstrainingValueTypeConstraint]
307     Create a subtype of ParentTypeConstraint with a dependency on a value
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
314 SEE ALSO
315     The following modules or resources may be of interest.
316
317     Moose, Moose::Meta::TypeConstraint, MooseX::Types
318
319 AUTHOR
320     John Napiorkowski, "<jjnapiork@cpan.org>"
321
322 COPYRIGHT & LICENSE
323     This program is free software; you can redistribute it and/or modify it
324     under the same terms as Perl itself.
325