X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FMooseX%2FTypes.pm;h=4a39855c3d7d1e5215acc06adfcf630d2e2a2999;hb=e50bf0d982a7e75adb8106c092080d06cee427c3;hp=e8c20acdaeb50f5b6caa50c944a5354f9ebcf995;hpb=0e92a78eb793e7761cc58a662eb6ed1c7a8f2aa7;p=gitmo%2FMooseX-Types.git diff --git a/lib/MooseX/Types.pm b/lib/MooseX/Types.pm index e8c20ac..4a39855 100644 --- a/lib/MooseX/Types.pm +++ b/lib/MooseX/Types.pm @@ -7,9 +7,6 @@ MooseX::Types - Organise your Moose types in libraries =cut -#use warnings; -#use strict; - use Moose::Util::TypeConstraints; use MooseX::Types::TypeDecorator; use MooseX::Types::Base (); @@ -19,8 +16,8 @@ use Carp::Clan qw( ^MooseX::Types ); use namespace::clean -except => [qw( meta )]; -our $VERSION = 0.05; - +use 5.008; +our $VERSION = 0.10; my $UndefMsg = q{Action for type '%s' not yet defined in library '%s'}; =head1 SYNOPSIS @@ -31,12 +28,16 @@ my $UndefMsg = q{Action for type '%s' not yet defined in library '%s'}; # predeclare our own types use MooseX::Types - -declare => [qw( PositiveInt NegativeInt )]; + -declare => [qw( + PositiveInt NegativeInt + ArrayRefOfPositiveInt ArrayRefOfAtLeastThreeNegativeInts + LotsOfInnerConstraints StrOrArrayRef + )]; # import builtin types use MooseX::Types::Moose 'Int'; - # type definition + # type definition. subtype PositiveInt, as Int, where { $_ > 0 }, @@ -52,6 +53,23 @@ my $UndefMsg = q{Action for type '%s' not yet defined in library '%s'}; from Int, via { 1 }; + # with parameterized constraints. + + subtype ArrayRefOfPositiveInt, + as ArrayRef[PositiveInt]; + + subtype ArrayRefOfAtLeastThreeNegativeInts, + as ArrayRef[NegativeInt], + where { scalar(@$_) > 2 }; + + subtype LotsOfInnerConstraints, + as ArrayRef[ArrayRef[HashRef[Int]]]; + + # with TypeConstraint Unions + + subtype StrOrArrayRef, + as Str|ArrayRef; + 1; =head2 Usage @@ -242,7 +260,38 @@ The fully qualified name of this type as L knows it. A message that will be thrown when type functionality is used but the type does not yet exist. -=back +=head1 RECURSIVE SUBTYPES + +As of version 0.08, L has experimental support for Recursive +subtypes. This will allow: + + subtype Tree() => as HashRef[Str|Tree]; + +Which validates things like: + + {key=>'value'}; + {key=>{subkey1=>'value', subkey2=>'value'}} + +And so on. This feature is new and there may be lurking bugs so don't be afraid +to hunt me down with patches and test cases if you have trouble. + +=head1 NOTES REGARDING TYPE UNIONS + +L uses L to do some overloading +which generally allows you to easily create union types: + + subtype StrOrArrayRef, + as Str|ArrayRef; + +As with parameterized constrains, this overloading extends to modules using the +types you define in a type library. + + use Moose; + use MooseX::Types::Moose qw(HashRef Int); + + has 'attr' => (isa=>HashRef|Int); + +And everything should just work as you'd think. =head1 METHODS @@ -302,9 +351,16 @@ yet defined. sub type_export_generator { my ($class, $type, $name) = @_; + + ## Return an anonymous subroutine that will generate the proxied type + ## constraint for you. + return sub { my $type_constraint; if(defined(my $params = shift @_)) { + ## We currently only allow a TC to accept a single, ArrayRef + ## parameter, as in HashRef[Int], where [Int] is what's inside the + ## ArrayRef passed. if(ref $params eq 'ARRAY') { $type_constraint = $class->create_arged_type_constraint($name, @$params); } else { @@ -313,24 +369,35 @@ sub type_export_generator { } else { $type_constraint = $class->create_base_type_constraint($name); } + $type_constraint = defined($type_constraint) ? $type_constraint : MooseX::Types::UndefinedType->new($name); - return $class->create_type_decorator($type_constraint); + my $type_decorator = $class->create_type_decorator($type_constraint); + + ## If there are additional args, that means it's probably stuff that + ## needs to be returned to the subtype. Not an ideal solution here but + ## doesn't seem to cause trouble. + + if(@_) { + return ($type_decorator, @_); + } else { + return $type_decorator; + } }; } =head2 create_arged_type_constraint ($name, @args) -Given a String $name with @args find the matching typeconstraint. +Given a String $name with @args find the matching typeconstraint and parameterize +it with @args. =cut sub create_arged_type_constraint { - my ($class, $name, @args) = @_; - ### This whole section is a real TODO :) Ugly hack to get the base tests working. - my $fullname = $name."[$args[0]]"; - return Moose::Util::TypeConstraints::create_parameterized_type_constraint($fullname); + my ($class, $name, @args) = @_; + my $type_constraint = Moose::Util::TypeConstraints::find_or_create_type_constraint("$name"); + return $type_constraint->parameterize(@args); } =head2 create_base_type_constraint ($name) @@ -353,7 +420,7 @@ instance. sub create_type_decorator { my ($class, $type_constraint) = @_; - return MooseX::Types::TypeDecorator->new(type_constraint=>$type_constraint); + return MooseX::Types::TypeDecorator->new($type_constraint); } =head2 coercion_export_generator @@ -398,11 +465,72 @@ sub check_export_generator { =head1 CAVEATS +The following are lists of gotcha's and their workarounds for developers coming +from the standard string based type constraint names + +=head2 Uniqueness + A library makes the types quasi-unique by prefixing their names with (by default) the library package name. If you're only using the type handler functions provided by MooseX::Types, you shouldn't ever have to use a type's actual full name. +=head2 Argument separation ('=>' versus ',') + +The Perlop manpage has this to say about the '=>' operator: "The => operator is +a synonym for the comma, but forces any word (consisting entirely of word +characters) to its left to be interpreted as a string (as of 5.001). This +includes words that might otherwise be considered a constant or function call." + +Due to this stringification, the following will NOT work as you might think: + + subtype StrOrArrayRef => as Str|ArrayRef; + +The 'StrOrArrayRef' will have it's stringification activated this causes the +subtype to not be created. Since the bareword type constraints are not strings +you really should not try to treat them that way. You will have to use the ',' +operator instead. The author's of this package realize that all the L +documention and examples nearly uniformly use the '=>' version of the comma +operator and this could be an issue if you are converting code. + +Patches welcome for discussion. + +=head2 Compatibility with Sub::Exporter + +If you want to use L with a Type Library, you need to make sure +you export all the type constraints declared AS WELL AS any additional export +targets. For example if you do: + + package TypeAndSubExporter; { + + use MooseX::Types::Moose qw(Str); + use MooseX::Types -declare => [qw(MyStr)]; + use Sub::Exporter -setup => { exports => [ qw(something) ] }; + + subtype MyStr, + as Str; + + sub something { + return 1; + } + + } 1; + + package Foo; { + use TypeAndSubExporter qw(MyStr); + } 1; + +You'll get a '"MyStr" is not exported by the TypeAndSubExporter module' error. +Upi can workaround by: + + - use Sub::Exporter -setup => { exports => [ qw(something) ] }; + + use Sub::Exporter -setup => { exports => [ qw(something MyStr) ] }; + +This is a workaround and I am exploring how to make these modules work better +together. I realize this workaround will lead a lot of duplication in your +export declarations and will be onerous for large type libraries. Patches and +detailed test cases welcome. See the tests directory for a start on this. + =head1 SEE ALSO L, @@ -415,6 +543,8 @@ L Robert 'phaylon' Sedlacek Crs@474.atE>, with many thanks to the C<#moose> cabal on C. +Additional features by John Napiorkowski (jnapiorkowski) . + =head1 LICENSE This program is free software; you can redistribute it and/or modify