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 TBD: Need discussion and example of coercions working for both the
137 constrainted and dependent type constraint.
139 subtype OlderThanAge,
140 as Dependent[Int, Dict[older_than=>Int]],
142 my ($value, $dict) = @_;
143 return $value > $dict->{older_than} ? 1:0;
146 Which should work like:
148 OlderThanAge[{older_than=>25}]->check(39); ## is OK
151 from Tuple[Int, Int],
154 return [$int, {older_than=>$int}];
159 Newer versions of L<MooseX::Types> support recursive type constraints. That is
160 you can include a type constraint as a contained type constraint of itself.
161 Recursion is support in both the dependent and constraining type constraint. For
162 example, if we assume an Object hierarchy like Food -> [Grass, Meat]
164 TODO: DOES THIS EXAMPLE MAKE SENSE?
167 as Dependent[Food, Food],
169 my ($value, $allowed_food_type) = @_;
170 return $value->isa($allowed_food_type);
173 my $grass = Food::Grass->new;
174 my $meat = Food::Meat->new;
175 my $vegetarian = Food[$grass];
177 $vegetarian->check($grass); ## Grass is the allowed food of a vegetarian
178 $vegetarian->check($meat); ## BANG, vegetarian can't eat meat!
180 =head1 TYPE CONSTRAINTS
182 This type library defines the following constraints.
184 =head2 Dependent[ParentTypeConstraint, DependentValueTypeConstraint]
186 Create a subtype of ParentTypeConstraint with a dependency on a value that can
187 pass the DependentValueTypeConstraint. If DependentValueTypeConstraint is empty
188 we default to the 'Any' type constraint (see L<Moose::Util::TypeConstraints>).
190 This creates a type constraint which must be further parameterized at later time
191 before it can be used to ->check or ->validate a value. Attempting to do so
192 will cause an exception.
196 Moose::Util::TypeConstraints::get_type_constraint_registry->add_type_constraint(
197 MooseX::Dependent::Meta::TypeConstraint::Parameterizable->new(
198 name => 'MooseX::Dependent::Types::Dependent',
199 parent => find_type_constraint('ArrayRef'),
200 constraint_generator=> sub {
201 my ($dependent_val, $callback, $constraining_val) = @_;
202 return $callback->($dependent_val, $constraining_val);
209 John Napiorkowski, C<< <jjnapiork@cpan.org> >>
211 =head1 COPYRIGHT & LICENSE
213 This program is free software; you can redistribute it and/or modify
214 it under the same terms as Perl itself.