better docs, more tests, update readme
[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.
65
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:
75
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
92         RangedInt([{min=>50, max=>75}])->check(99); ## Not OK, exceeds max
93
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)
99
100         RangedInt([{min=>99, max=>10}])->check(10); ## Not OK, not a valid Range!
101
102     If you can't accept a hard exception here, you'll need to test the
103     constraining values first, as in:
104
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         }
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
117         RangedInt([min=>10,max=>100])->check(50); ## OK
118         RangedInt([min=>50, max=>75])->check(99); ## Not OK, exceeds max
119         RangedInt([min=>99, max=>10])->check(10); ## Exception, not valid Range
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
125     Also note that if you 'chain' parameterization results with a method
126     call like:
127
128         TypeConstraint([$ob])->method;
129
130     You need to have the "(...)" around the ArrayRef in the Type Constraint
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.
134
135   Subtyping a Parameterizable type constraints
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
141         subtype RangedInt,
142             as Parameterizable[Int, Range],
143             where {
144                 my ($value, $range) = @_;
145                 return ($value >= $range->{min} &&
146                  $value =< $range->{max});
147             };
148
149     Example subtype with additional constraints:
150
151         subtype PositiveRangedInt,
152             as RangedInt,
153             where {
154                 shift >= 0;              
155             };
156
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:
169
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];
185
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
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
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.
200
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.
204
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
221
222         subtype Varchar,
223           as Parameterizable[Str, Int],
224           where {
225             my($string, $int) = @_;
226             $int >= length($string) ? 1:0;
227           },
228           message { "'$_' is too long"  };
229
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.
233
234     Now, this new sub type, "Varchar", is parameterizable since it can take
235     a type parameter. We can apply some coercions to it:
236
237         coerce Varchar,
238           from Object,
239           via { "$_"; },  ## stringify the object
240           from ArrayRef,
241           via { join '',@$_ };  ## convert array to string
242
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:
246
247         has name => (isa=>Varchar, ...)
248
249     You are going to do this:
250
251         has name => (isa=>Varchar[40], ...)
252
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.
257
258     You can of course add new coercions to a subtype of a parameterizable
259     type:
260
261         subtype MySpecialVarchar,
262           as Varchar;
263
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.
286
287   Recursion
288         TBD - Needs a use case... Anyone?
289
290 TYPE 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
303 AUTHOR
304     John Napiorkowski, "<jjnapiork@cpan.org>"
305
306 COPYRIGHT & LICENSE
307     This program is free software; you can redistribute it and/or modify it
308     under the same terms as Perl itself.
309