2 MooseX::Types::Parameterizable - Create your own Parameterizable Types.
5 The follow is example usage.
7 package Test::MooseX::Types::Parameterizable::Synopsis;
10 use MooseX::Types::Parameterizable qw(Parameterizable);
11 use MooseX::Types::Moose qw(Str Int ArrayRef);
12 use MooseX::Types -declare=>[qw(Varchar)];
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
16 ## an SQL Varchar type.
19 as Parameterizable[Str,Int],
21 my($string, $int) = @_;
22 $int >= length($string) ? 1:0;
24 message { "'$_' is too long" };
29 my ($arrayref, $int) = @_;
33 has 'varchar_five' => (isa=>Varchar[5], is=>'ro', coerce=>1);
34 has 'varchar_ten' => (isa=>Varchar[10], is=>'ro');
36 ## Object created since attributes are valid
37 my $object1 = __PACKAGE__->new(
38 varchar_five => '1234',
39 varchar_ten => '123456789',
42 ## Dies with an invalid constraint for 'varchar_five'
43 my $object2 = __PACKAGE__->new(
44 varchar_five => '12345678',
45 varchar_ten => '123456789',
48 ## varchar_five coerces as expected
49 my $object3 = __PACKAGE__->new(
50 varchar_five => [qw/aa bb/],
51 varchar_ten => '123456789',
54 See t/05-pod-examples.t for runnable versions of all POD code
57 A MooseX::Types library for creating parameterizable types. A
58 parameterizable type constraint for all intents and uses is a subclass
59 of a parent type, but adds a secondary type parameter which is available
60 to constraint callbacks (such as inside the 'where' clause) or in the
63 This allows you to create a type that has additional runtime advice,
64 such as a set of numbers within which another number must be unique, or
65 allowable ranges for a integer, such as in:
68 as Dict[max=>Int, min=>Int],
71 return $range->{max} > $range->{min};
75 as Parameterizable[Int, Range],
77 my ($value, $range) = @_;
78 return ($value >= $range->{min} &&
79 $value <= $range->{max});
82 RangedInt([{min=>10,max=>100}])->check(50); ## OK
83 RangedInt([{min=>50, max=>75}])->check(99); ## Not OK, 99 exceeds max
85 This throws a hard Moose exception. You'll need to capture it in an eval
86 or related exception catching system (see TryCatch or <Try::Tiny>.)
88 RangedInt([{min=>99, max=>10}])->check(10); ## Not OK, not a valid Range!
90 If you can't accept a hard exception here, you'll need to test the
91 constraining values first, as in:
93 my $range = {min=>99, max=>10};
94 if(my $err = Range->validate($range)) {
97 RangedInt($range)->check(99);
100 Please note that for ArrayRef or HashRef parameterizable type
101 constraints, as in the example above, as a convenience we automatically
102 ref the incoming type parameters, so that the above could also be
105 RangedInt([min=>10,max=>100])->check(50); ## OK
106 RangedInt([min=>50, max=>75])->check(99); ## Not OK, 99 exceeds max
107 RangedInt([min=>99, max=>10])->check(10); ## Exception, not a valid Range!
109 This is the preferred syntax, as it improve readability and adds to the
110 conciseness of your type constraint declarations. An exception wil be
111 thrown if your type parameters don't match the required reference type.
113 Also not that if you 'chain' parameterization results with a method call
116 TypeConstraint([$ob])->method;
118 You need to have the "(...)" around the ArrayRef in the Type Constraint
119 parameters. This seems to have something to do with the precendent level
120 of "->". Patches or thoughts welcomed. You only need to do this in the
121 above case which I imagine is not a very common case.
123 ==head2 Subtyping a Parameterizable type constraints
125 When subclassing a parameterizable type you must be careful to match
126 either the required type parameter type constraint, or if
127 re-parameterizing, the new type constraints are a subtype of the parent.
131 as Parameterizable[Int, Range],
133 my ($value, $range) = @_;
134 return ($value >= $range->{min} &&
135 $value =< $range->{max});
138 Example subtype with additional constraints:
140 subtype PositiveRangedInt,
146 Or you could have done the following instead:
148 ## Subtype of Int for positive numbers
152 my ($value, $range) = @_;
156 ## subtype Range to re-parameterize Range with subtypes
157 subtype PositiveRange,
158 as Range[max=>PositiveInt, min=>PositiveInt];
160 ## create subtype via reparameterizing
161 subtype PositiveRangedInt,
162 as RangedInt[PositiveRange];
164 Notice how re-parameterizing the parameterizable type 'RangedInt' works
165 slightly differently from re-parameterizing 'PositiveRange' Although it
166 initially takes two type constraint values to declare a parameterizable
167 type, should you wish to later re-parameterize it, you only use a
168 subtype of the second type parameter (the parameterizable type
169 constraint) since the first type constraint sets the parent type for the
170 parameterizable type. In other words, given the example above, a type
171 constraint of 'RangedInt' would have a parent of 'Int', not
172 'Parameterizable' and for all intends and uses you could stick it
173 wherever you'd need an Int.
178 ## re-parameterized subtypes of NameAge containing a Parameterizable Int
179 subtype NameBetween18and35Age,
182 PositiveRangedInt[min=>18,max=>35],
185 One caveat is that you can't stick an unparameterized parameterizable
186 type inside a structure, such as MooseX::Types::Structured since that
187 would require the ability to convert a 'containing' type constraint into
188 a parameterizable type, which is a capacity we current don't have.
191 Parameterizable types have some limited support for coercions. Several
192 things must be kept in mind. The first is that the coercion targets the
193 type constraint which is being made parameterizable, Not the
194 parameterizable type. So for example if you create a Parameterizable
197 subtype RequiredAgeInYears,
200 subtype PersonOverAge,
201 as Parameterizable[Person, RequiredAgeInYears]
203 my ($person, $required_years_old) = @_;
204 return $person->years_old > $required_years_old;
207 This would validate the following:
209 my $person = Person->new(age=>35);
210 PersonOverAge([18])->check($person);
212 You can then apply the following coercion
214 coerce PersonOverAge,
216 via {Person->new(%$_)},
218 via {Person->new(age=>$_)};
220 This coercion would then apply to all the following:
222 PersonOverAge([18])->check(30); ## via the Int coercion
223 PersonOverAge([18])->check({age=>50}); ## via the Dict coercion
225 However, you are not allowed to place coercions on parameterizable types
226 that have had their constraining value filled, nor subtypes of such. For
229 coerce PersonOverAge[18],
233 That would generate a hard exception. This is a limitation for now until
234 I can devise a smarter way to cache the generated type constraints.
235 However, I doubt it will be a significant limitation, since the general
236 use case is supported.
238 Lastly, the constraining value is available in the coercion in much the
239 same way it is available to the constraint.
241 ## Create a type constraint where a Person must be in the set
243 as Parameterizable[Person, PersonSet],
245 my ($person, $person_set) = @_;
246 $person_set->find($person);
252 my ($hashref, $person_set) = @_;
253 return $person_set->create($hash_ref);
260 This type library defines the following constraints.
262 Parameterizable[ParentTypeConstraint, ParameterizableValueTypeConstraint]
263 Create a subtype of ParentTypeConstraint with a dependency on a value
264 that can pass the ParameterizableValueTypeConstraint. If
265 ParameterizableValueTypeConstraint is empty we default to the 'Any' type
266 constraint (see Moose::Util::TypeConstraints).
268 This creates a type constraint which must be further parameterized at
269 later time before it can be used to ->check or ->validate a value.
270 Attempting to do so will cause an exception.
273 John Napiorkowski, "<jjnapiork@cpan.org>"
276 This program is free software; you can redistribute it and/or modify it
277 under the same terms as Perl itself.