1 package MooseX::Dependent::Types;
5 use Moose::Util::TypeConstraints;
6 use MooseX::Dependent::Meta::TypeConstraint::Parameterizable;
7 use MooseX::Types -declare => [qw(Dependent)];
10 our $AUTHORITY = 'cpan:JJNAPIORK';
14 MooseX::Dependent::Types - L<MooseX::Types> constraints that depend on values.
18 Within your L<MooseX::Types> declared library module:
20 use MooseX::Dependent::Types qw(Dependent);
23 as Dependent[Int, Set],
26 return $set->find($int) ? 0:1;
31 A L<MooseX::Types> library for creating dependent types. A dependent type
32 constraint for all intents and uses is a subclass of a parent type, but adds a
33 secondary type parameter which is available to constraint callbacks (such as
34 inside the 'where' clause) or in the coercions.
36 This allows you to create a type that has additional runtime advice, such as a
37 set of numbers within which another number must be unique, or allowable ranges
38 for a integer, such as in:
41 as Dict[max=>Int, min=>Int],
44 return $range->{max} > $range->{min};
48 as Dependent[Int, Range],
50 my ($value, $range) = @_;
51 return ($value >= $range->{min} &&
52 $value =< $range->{max});
55 RangedInt[{min=>10,max=>100}]->check(50); ## OK
56 RangedInt[{min=>50, max=>75}]->check(99); ## Not OK, 99 exceeds max
57 RangedInt[{min=>99, max=>10}]->check(10); ## Not OK, not a valid Range!
59 Please note that for ArrayRef or HashRef dependent type constraints, as in the
60 example above, as a convenience we automatically ref the incoming type
61 parameters, so that the above could also be written as:
63 RangedInt[min=>10,max=>100]->check(50); ## OK
64 RangedInt[min=>50, max=>75]->check(99); ## Not OK, 99 exceeds max
65 RangedInt[min=>99, max=>10]->check(10); ## Not OK, not a valid Range!
67 This is the preferred syntax, as it improve readability and adds to the
68 conciseness of your type constraint declarations. An exception wil be thrown if
69 your type parameters don't match the required reference type.
71 ==head2 Subtyping a Dependent type constraints
73 When subclassing a dependent type you must be careful to match either the
74 required type parameter type constraint, or if re-parameterizing, the new
75 type constraints are a subtype of the parent. For example:
78 as Dependent[Int, Range],
80 my ($value, $range) = @_;
81 return ($value >= $range->{min} &&
82 $value =< $range->{max});
85 Example subtype with additional constraints:
87 subtype PositiveRangedInt,
93 Or you could have done the following instead (example of re-paramterizing)
95 ## Subtype of Int for positive numbers
102 ## subtype Range to re-parameterize Range with subtypes
103 subtype PositveRange,
104 as Range[max=>PositiveInt, min=>PositiveInt];
106 ## create subtype via reparameterizing
107 subtype PositiveRangedInt,
108 as RangedInt[PositveRange];
110 Notice how re-parameterizing the dependent type 'RangedInt' works slightly
111 differently from re-parameterizing 'PositiveRange'? Although it initially takes
112 two type constraint values to declare a dependent type, should you wish to
113 later re-parameterize it, you only use a subtype of the second type parameter
114 (the dependent type constraint) since the first type constraint sets the parent
115 type for the dependent type. In other words, given the example above, a type
116 constraint of 'RangedInt' would have a parent of 'Int', not 'Dependent' and for
117 all intends and uses you could stick it wherever you'd need an Int.
122 ## re-parameterized subtypes of NameAge containing a Dependent Int
123 subtype NameBetween18and35Age,
126 PositiveRangedInt[min=>18,max=>35],
129 One caveat is that you can't stick an unparameterized dependent type inside a
130 structure, such as L<MooseX::Types::Structured> since that would require the
131 ability to convert a 'containing' type constraint into a dependent type, which
132 is a capacity we current don't have.
136 You can place coercions on dependent types, however you need to pay attention to
137 what you are actually coercion, the unparameterized or parameterized constraint.
139 TBD: Need discussion and example of coercions working for both the
140 constrainted and dependent type constraint.
142 subtype OlderThanAge,
143 as Dependent[Int, Dict[older_than=>Int]],
145 my ($value, $dict) = @_;
146 return $value > $dict->{older_than} ? 1:0;
149 Which should work like:
151 OlderThanAge[{older_than=>25}]->check(39); ## is OK
152 OlderThanAge[older_than=>1]->check(9); ## OK, using reference type inference
154 And you can create coercions like:
157 from Tuple[Int, Int],
160 return [$int, {older_than=>$int}];
165 Newer versions of L<MooseX::Types> support recursive type constraints. That is
166 you can include a type constraint as a contained type constraint of itself.
167 Recursion is support in both the dependent and constraining type constraint. For
168 example, if we assume an Object hierarchy like Food -> [Grass, Meat]
170 TODO: DOES THIS EXAMPLE MAKE SENSE?
173 as Dependent[Food, Food],
175 my ($value, $allowed_food_type) = @_;
176 return $value->isa($allowed_food_type);
179 my $grass = Food::Grass->new;
180 my $meat = Food::Meat->new;
181 my $vegetarian = Food[$grass];
183 $vegetarian->check($grass); ## Grass is the allowed food of a vegetarian
184 $vegetarian->check($meat); ## BANG, vegetarian can't eat meat!
186 =head1 TYPE CONSTRAINTS
188 This type library defines the following constraints.
190 =head2 Dependent[ParentTypeConstraint, DependentValueTypeConstraint]
192 Create a subtype of ParentTypeConstraint with a dependency on a value that can
193 pass the DependentValueTypeConstraint. If DependentValueTypeConstraint is empty
194 we default to the 'Any' type constraint (see L<Moose::Util::TypeConstraints>).
196 This creates a type constraint which must be further parameterized at later time
197 before it can be used to ->check or ->validate a value. Attempting to do so
198 will cause an exception.
202 Moose::Util::TypeConstraints::get_type_constraint_registry->add_type_constraint(
203 MooseX::Dependent::Meta::TypeConstraint::Parameterizable->new(
204 name => 'MooseX::Dependent::Types::Dependent',
205 parent => find_type_constraint('ArrayRef'),
206 constraint_generator=> sub {
207 my ($dependent_val, $callback, $constraining_val) = @_;
208 return $callback->($dependent_val, $constraining_val);
215 John Napiorkowski, C<< <jjnapiork@cpan.org> >>
217 =head1 COPYRIGHT & LICENSE
219 This program is free software; you can redistribute it and/or modify
220 it under the same terms as Perl itself.