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 similar to SQL Varchar type.
17 as Parameterizable[Str,Int],
19 my($string, $int) = @_;
20 $int >= length($string) ? 1:0;
22 message { "'$_' is too long" };
24 Coerce an ArrayRef to a string via concatenation.
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
38 my $object1 = __PACKAGE__->new(
39 varchar_five => '1234',
40 varchar_ten => '123456789',
43 Dies with an invalid constraint for 'varchar_five'
45 my $object2 = __PACKAGE__->new(
46 varchar_five => '12345678', ## too long!
47 varchar_ten => '123456789',
50 varchar_five coerces as expected
52 my $object3 = __PACKAGE__->new(
53 varchar_five => [qw/aa bb/], ## coerces to "aabb"
54 varchar_ten => '123456789',
57 See t/05-pod-examples.t for runnable versions of all POD code
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
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
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:
78 as Dict[max=>Int, min=>Int],
81 return $range->{max} > $range->{min};
85 as Parameterizable[Int, Range],
87 my ($value, $range) = @_;
88 return ($value >= $range->{min} &&
89 $value <= $range->{max});
92 RangedInt([{min=>10,max=>100}])->check(50); ## OK
93 RangedInt([{min=>50, max=>75}])->check(99); ## Not OK, exceeds max
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
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
105 For example the following would throw a hard error (and not just return
108 RangedInt([{min=>99, max=>10}])->check(10); ## Not OK, not a valid Range!
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.
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:
118 my $range = {min=>99, max=>10};
119 if(my $err = Range->validate($range)) {
122 RangedInt($range)->check(99);
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
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
134 This is the preferred syntax, as it improve readability and adds to the
135 conciseness of your type constraint declarations.
137 Also note that if you 'chain' parameterization results with a method
140 TypeConstraint([$ob])->method;
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.
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.
154 as Parameterizable[Int, Range],
156 my ($value, $range) = @_;
157 return ($value >= $range->{min} &&
158 $value =< $range->{max});
161 Example subtype with additional constraints:
163 subtype PositiveRangedInt,
169 In this case you'd now have a parameterizable type constraint which
172 Test::More::ok PositiveRangedInt([{min=>-10, max=>75}])->check(5);
173 Test::More::ok !PositiveRangedInt([{min=>-10, max=>75}])->check(-5);
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:
182 ## Subtype of Int for positive numbers
186 my ($value, $range) = @_;
190 ## subtype Range to re-parameterize Range with subtypes
191 subtype PositiveRange,
192 as Range[max=>PositiveInt, min=>PositiveInt];
194 ## create subtype via reparameterizing
195 subtype PositiveRangedInt,
196 as RangedInt[PositiveRange];
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:
202 Test::More::ok PositiveRangedInt([{min=>10, max=>75}])->check(15); ## OK
203 Test::More::ok !PositiveRangedInt([{min=>-10, max=>75}])->check(-5); ## Dies
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.
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.
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.
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.
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:
236 as Parameterizable[Str, Int],
238 my($string, $int) = @_;
239 $int >= length($string) ? 1:0;
241 message { "'$_' is too long" };
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.
247 Now, this new sub type, "Varchar", is parameterizable since it can take
248 a type parameter. We can apply some coercions to it:
252 via { "$_"; }, ## stringify the object
254 via { join '',@$_ }; ## convert array to string
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
260 has name => (isa=>Varchar, ...); ## Why not just use a Str?
262 You are going to do this:
264 has name => (isa=>Varchar[40], ...)
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.
271 You can of course add new coercions to a subtype of a parameterizable
274 subtype MySpecialVarchar,
277 coerce MySpecialVarchar,
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
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:
292 coerce 40CharStr, ... # BANG!
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.
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.
301 TBD - Needs a use case... Anyone?
304 This type library defines the following constraints.
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
315 The following modules or resources may be of interest.
317 Moose, Moose::Meta::TypeConstraint, MooseX::Types
320 John Napiorkowski, "<jjnapiork@cpan.org>"
323 This program is free software; you can redistribute it and/or modify it
324 under the same terms as Perl itself.