From: John Napiorkowski Date: Fri, 25 Jun 2010 14:03:17 +0000 (-0400) Subject: better documentation for coercions X-Git-Tag: 0.03~3 X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=910bb5389be9e75022a3bba041dfe75db4ccc4b4;p=gitmo%2FMooseX-Dependent.git better documentation for coercions --- diff --git a/lib/MooseX/Types/Parameterizable.pm b/lib/MooseX/Types/Parameterizable.pm index 6956980..f1db92a 100644 --- a/lib/MooseX/Types/Parameterizable.pm +++ b/lib/MooseX/Types/Parameterizable.pm @@ -212,67 +212,66 @@ could stick it wherever you'd need an Int. =head2 Coercions -Parameterizable 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 parameterizable, Not the parameterized type. So for example if you -create a Parameterizable type like: +A type coerction is a rule that allows you to transform one type from one or +more other types. Please see L for an example +of type coercions if you are not familiar with the subject. - subtype RequiredAgeInYears, - as Int; +L support type coercions in all the ways you +would expect. In addition, it also supports a limited form of type coercion +inheritance. Generally speaking, type constraints don't inherit coercions since +this would rapidly become confusing. However, since your parameterizable type +is intended to become parameterized in order to be useful, we support inheriting +from a 'base' parameterizable type constraint to its 'child' parameterized sub +types. - subtype PersonOverAge, - as Parameterizable[Person, RequiredAgeInYears] +For the purposes of this discussion, a parameterizable type is a subtype created +when you say, "as Parameterizable[..." in your sub type declaration. For example + + subtype Varchar, + as Parameterizable[Str, Int], where { - my ($person, $required_years_old) = @_; - return $person->years_old > $required_years_old; - } + my($string, $int) = @_; + $int >= length($string) ? 1:0; + }, + message { "'$_' is too long" }; -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 parameterizable 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 Parameterizable[Person, PersonSet], - where { - my ($person, $person_set) = @_; - $person_set->find($person); - } - - coerce PersonInSet, - from HashRef, - via { - my ($hashref, $person_set) = @_; - return $person_set->create($hash_ref); - }; +This is the example, which creates a new parameterizable subtype of +Str which takes a single type parameter which must be an Int. This Int is used +to constrain the allowed length of the Str value. + +Now, this new sub type, "Varchar", is parameterizable since it can take a type +parameter. We can apply some coercions to it: + + coerce Varchar, + from Object, + via { "$_"; }, ## stringify the object + from ArrayRef, + via { join '',@$_ }; ## convert array to string + +This parameterizable subtype, "Varchar" itself is something you'd never use +directly to constraint a value. In other words you'd never do something like: + + has name => (isa=>Varchar, ...) + +You are going to do this: + + has name => (isa=>Varchar[40], ...) + +Which is actually useful. However, "Varchar[40]" is a parameterized type, it +is a subtype of the parameterizable "Varchar" and it inherits coercions from +its parent. This may be a bit surprising to L developers, but I believe +this is the actual desired behavior. + +You can of course add extra coercions to a parameterized type: + + subtype Max40CharStr, + as Varchar[40]; + + coerce Max40CharStr, + from ... + +In which case this new parameterized type would inherit coercions from it's parent +parameterizable type (Varchar), as well as the additional coercions you've added. =head2 Recursion