more docs and clarifications
[gitmo/MooseX-Dependent.git] / lib / MooseX / Dependent / Types.pm
index 57000a2..b23e750 100644 (file)
@@ -13,14 +13,41 @@ MooseX::Dependent::Types - L<MooseX::Types> constraints that depend on values.
 Within your L<MooseX::Types> declared library module:
 
     use MooseX::Dependent::Types qw(Dependent);
+       
+       subtype Set,
+               as class_type("Set::Scalar");
 
-    subtype UniqueID,
+    subtype UniqueInt,
         as Dependent[Int, Set],
         where {
             my ($int, $set) = @_;
-            return $set->find($int) ? 0:1;
+            return !$set->has($int);
         };
                
+       subtype PositiveSet,
+               as Set,
+               where {
+                       my ($set) = @_;
+                       return !grep {$_ <0 } $set->members;
+               };
+               
+    subtype PositiveUniqueInt,
+        as UniqueInt[PositiveSet];
+       
+       my $set = Set::Scalar->new(1,2,3);
+
+       UniqueInt([$set])->check(100);  ## Okay, 100 isn't in (1,2,3)
+       UniqueInt([$set])->check(-99);  ## Okay, -99 isn't in (1,2,3)
+       UniqueInt([$set])->check(2);  ## Not OK, 2 is in (1,2,3)
+       
+       PositiveUniqueInt([$set])->check(100);  ## Okay, 100 isn't in (1,2,3)
+       PositiveUniqueInt([$set])->check(-99);  ## Not OK, -99 not Positive Int
+       PositiveUniqueInt([$set])->check(2);  ## Not OK, 2 is in (1,2,3)
+       
+       my $negative_set = Set::Scalar->new(-1,-2,-3);
+       
+       UniqueInt([$negative_set])->check(100);  ## Throws exception
+               
 =head1 DESCRIPTION
 
 A L<MooseX::Types> library for creating dependent types.  A dependent type
@@ -108,7 +135,7 @@ Example subtype with additional constraints:
                        shift >= 0;                     
                };
                
-Or you could have done the following instead (example of re-paramterizing)
+Or you could have done the following instead:
 
        ## Subtype of Int for positive numbers
        subtype PositiveInt,
@@ -152,55 +179,71 @@ is a capacity we current don't have.
        
 =head2 Coercions
 
-You can place coercions on dependent types, however you need to pay attention to
-what you are actually coercion, the unparameterized or parameterized constraint.
+Dependent types have some limited support for coercions.  Several things must
+be kept in mind.  The first is that the coercion targets the type constraint
+which is being made dependent, Not the dependent type.  So for example if you
+create a Dependent type like:
 
-    TBD: Need discussion and example of coercions working for both the
-    constrainted and dependent type constraint.
-       
-       subtype OlderThanAge,
-               as Dependent[Int, Dict[older_than=>Int]],
-               where {
-                       my ($value, $dict) = @_;
-                       return $value > $dict->{older_than} ? 1:0;
-               };
-
-Which should work like:
+       subtype RequiredAgeInYears,
+         as Int;
 
-       OlderThanAge([{older_than=>25}])->check(39); ## is OK
-       OlderThanAge([older_than=>1])->check(9); ## OK, using reference type inference
+       subtype PersonOverAge,
+         as Dependent[Person, RequiredAgeInYears]
+         where {
+               my ($person, $required_years_old) = @_;
+               return $person->years_old > $required_years_old;
+         }
 
-And you can create coercions like:
+This would validate the following:
+       
+       my $person = Person->new(age=>35);
+       PersonOverAge([18])->check($person);
+       
+You can then apply the following coercion
+
+       coerce PersonOverAge,
+         from Dict[age=>int],
+         via {Person->new(%$_)},
+         from Int,
+         via {Person->new(age=>$_)};
+         
+This coercion would then apply to all the following:
+
+       PersonOverAge([18])->check(30); ## via the Int coercion
+       PersonOverAge([18])->check({age=>50}); ## via the Dict coercion
+
+However, you are not allowed to place coercions on dependent types that have
+had their constraining value filled, nor subtypes of such.  For example:
+
+       coerce PersonOverAge[18],
+         from DateTime,
+         via {$_->years};
+         
+That would generate a hard exception.  This is a limitation for now until I can
+devise a smarter way to cache the generated type constraints.  However, I doubt
+it will be a significant limitation, since the general use case is supported.
+
+Lastly, the constraining value is available in the coercion in much the same way
+it is available to the constraint.
+
+       ## Create a type constraint where a Person must be in the set
+       subtype PersonInSet,
+               as Dependent[Person, PersonSet],
+               where {
+                       my ($person, $person_set) = @_;
+                       $person_set->find($person);
+               }
 
-       coerce OlderThanAge,
-               from Tuple[Int, Int],
+       coerce PersonInSet,
+               from HashRef,
                via {
-                       my ($int, $int);
-                       return [$int, {older_than=>$int}];
+                       my ($hashref, $person_set) = @_;
+                       return $person_set->create($hash_ref);
                };
 
 =head2 Recursion
 
-Newer versions of L<MooseX::Types> support recursive type constraints.  That is
-you can include a type constraint as a contained type constraint of itself.
-Recursion is support in both the dependent and constraining type constraint. For
-example, if we assume an Object hierarchy like Food -> [Grass, Meat]
-       
-       TODO: DOES THIS EXAMPLE MAKE SENSE?
-       
-    subtype Food,
-               as Dependent[Food, Food],
-               where {
-                       my ($value, $allowed_food_type) = @_;
-                       return $value->isa($allowed_food_type);
-               };
-       
-       my $grass = Food::Grass->new;
-       my $meat = Food::Meat->new;
-       my $vegetarian = Food[$grass];
-       
-       $vegetarian->check($grass); ## Grass is the allowed food of a vegetarian
-       $vegetarian->check($meat); ## BANG, vegetarian can't eat meat!
+       TBD
 
 =head1 TYPE CONSTRAINTS