X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FMoose%2FUtil%2FTypeConstraints.pm;h=f6787a42fa7ff841263b4c3e3d9ab3d63781cdcb;hb=b6cca0d5690feec99436fe952315d5d4feeb9473;hp=2b16047c01accea60ce09e0670c1382f3c3d5267;hpb=8de5717850eb1f406e5f71d2ccfac33c72cc490b;p=gitmo%2FMoose.git diff --git a/lib/Moose/Util/TypeConstraints.pm b/lib/Moose/Util/TypeConstraints.pm index 2b16047..f6787a4 100644 --- a/lib/Moose/Util/TypeConstraints.pm +++ b/lib/Moose/Util/TypeConstraints.pm @@ -6,7 +6,7 @@ use List::MoreUtils qw( all any ); use Scalar::Util qw( blessed reftype ); use Moose::Exporter; -our $VERSION = '0.92'; +our $VERSION = '1.14'; $VERSION = eval $VERSION; our $AUTHORITY = 'cpan:STEVAN'; @@ -25,6 +25,7 @@ sub optimize_as (&); ## -------------------------------------------------------- +use Moose::Deprecated; use Moose::Meta::TypeConstraint; use Moose::Meta::TypeConstraint::Union; use Moose::Meta::TypeConstraint::Parameterized; @@ -49,7 +50,6 @@ Moose::Exporter->setup_import_methods( register_type_constraint match_on_type ) ], - _export_to_main => 1, ); ## -------------------------------------------------------- @@ -276,6 +276,12 @@ sub type { # back-compat version, called without sugar if ( !any { ( reftype($_) || '' ) eq 'HASH' } @_ ) { + Moose::Deprecated::deprecated( + feature => 'type without sugar', + message => + 'Calling type() with a simple list of parameters is deprecated' + ); + return _create_type_constraint( $_[0], undef, $_[1] ); } @@ -295,6 +301,12 @@ sub subtype { # # subtype 'Parent', sub { where }; if ( scalar @_ == 2 && ( reftype( $_[1] ) || '' ) eq 'CODE' ) { + Moose::Deprecated::deprecated( + feature => 'subtype without sugar', + message => + 'Calling subtype() with a simple list of parameters is deprecated' + ); + return _create_type_constraint( undef, @_ ); } @@ -302,11 +314,23 @@ sub subtype { # subtype 'Parent', sub { where }, sub { message }, sub { optimized }; if ( scalar @_ >= 3 && all { ( reftype($_) || '' ) eq 'CODE' } @_[ 1 .. $#_ ] ) { + Moose::Deprecated::deprecated( + feature => 'subtype without sugar', + message => + 'Calling subtype() with a simple list of parameters is deprecated' + ); + return _create_type_constraint( undef, @_ ); } # subtype 'Name', 'Parent', ... if ( scalar @_ >= 2 && all { !ref } @_[ 0, 1 ] ) { + Moose::Deprecated::deprecated( + feature => 'subtype without sugar', + message => + 'Calling subtype() with a simple list of parameters is deprecated' + ); + return _create_type_constraint(@_); } @@ -366,6 +390,9 @@ sub duck_type { @methods = @$type_name; $type_name = undef; } + if ( @methods == 1 && ref $methods[0] eq 'ARRAY' ) { + @methods = @{ $methods[0] }; + } register_type_constraint( create_duck_type_constraint( @@ -408,14 +435,16 @@ sub enum { # if only an array-ref is passed then # you get an anon-enum # - SL - if ( ref $type_name eq 'ARRAY' && !@values ) { + if ( ref $type_name eq 'ARRAY' ) { + @values == 0 + || __PACKAGE__->_throw_error("enum called with an array reference and additional arguments. Did you mean to parenthesize the enum call's parameters?"); + @values = @$type_name; $type_name = undef; } - ( scalar @values >= 2 ) - || __PACKAGE__->_throw_error( - "You must have at least two values to enumerate through"); - my %valid = map { $_ => 1 } @values; + if ( @values == 1 && ref $values[0] eq 'ARRAY' ) { + @values = @{ $values[0] }; + } register_type_constraint( create_enum_type_constraint( @@ -567,20 +596,54 @@ sub _install_type_coercions ($$) { use re "eval"; my $valid_chars = qr{[\w:\.]}; - my $type_atom = qr{ $valid_chars+ }; - - my $any; - - my $type = qr{ $valid_chars+ (?: \[ \s* (??{$any}) \s* \] )? }x; - my $type_capture_parts - = qr{ ($valid_chars+) (?: \[ \s* ((??{$any})) \s* \] )? }x; - my $type_with_parameter - = qr{ $valid_chars+ \[ \s* (??{$any}) \s* \] }x; - - my $op_union = qr{ \s* \| \s* }x; - my $union = qr{ $type (?: $op_union $type )+ }x; + my $type_atom = qr{ (?>$valid_chars+) }x; + my $ws = qr{ (?>\s*) }x; + my $op_union = qr{ $ws \| $ws }x; + + my ($type, $type_capture_parts, $type_with_parameter, $union, $any); + if (Class::MOP::IS_RUNNING_ON_5_10) { + my $type_pattern + = q{ (?&type_atom) (?: \[ (?&ws) (?&any) (?&ws) \] )? }; + my $type_capture_parts_pattern + = q{ ((?&type_atom)) (?: \[ (?&ws) ((?&any)) (?&ws) \] )? }; + my $type_with_parameter_pattern + = q{ (?&type_atom) \[ (?&ws) (?&any) (?&ws) \] }; + my $union_pattern + = q{ (?&type) (?> (?: (?&op_union) (?&type) )+ ) }; + my $any_pattern + = q{ (?&type) | (?&union) }; + + my $defines = qr{(?(DEFINE) + (? $valid_chars) + (? $type_atom) + (? $ws) + (? $op_union) + (? $type_pattern) + (? $type_capture_parts_pattern) + (? $type_with_parameter_pattern) + (? $union_pattern) + (? $any_pattern) + )}x; + + $type = qr{ $type_pattern $defines }x; + $type_capture_parts = qr{ $type_capture_parts_pattern $defines }x; + $type_with_parameter = qr{ $type_with_parameter_pattern $defines }x; + $union = qr{ $union_pattern $defines }x; + $any = qr{ $any_pattern $defines }x; + } + else { + $type + = qr{ $type_atom (?: \[ $ws (??{$any}) $ws \] )? }x; + $type_capture_parts + = qr{ ($type_atom) (?: \[ $ws ((??{$any})) $ws \] )? }x; + $type_with_parameter + = qr{ $type_atom \[ $ws (??{$any}) $ws \] }x; + $union + = qr{ $type (?> (?: $op_union $type )+ ) }x; + $any + = qr{ $type | $union }x; + } - $any = qr{ $type | $union }x; sub _parse_parameterized_type_constraint { { no warnings 'void'; $any; } # force capture of interpolated lexical @@ -656,7 +719,7 @@ subtype 'Value' => as 'Defined' => where { !ref($_) } => subtype 'Ref' => as 'Defined' => where { ref($_) } => optimize_as \&Moose::Util::TypeConstraints::OptimizedConstraints::Ref; -subtype 'Str' => as 'Value' => where {1} => +subtype 'Str' => as 'Value' => where { ref(\$_) eq 'SCALAR' } => optimize_as \&Moose::Util::TypeConstraints::OptimizedConstraints::Str; subtype 'Num' => as 'Str' => @@ -666,9 +729,6 @@ subtype 'Num' => as 'Str' => subtype 'Int' => as 'Num' => where { "$_" =~ /^-?[0-9]+$/ } => optimize_as \&Moose::Util::TypeConstraints::OptimizedConstraints::Int; -subtype 'ScalarRef' => as 'Ref' => where { ref($_) eq 'SCALAR' } => - optimize_as - \&Moose::Util::TypeConstraints::OptimizedConstraints::ScalarRef; subtype 'CodeRef' => as 'Ref' => where { ref($_) eq 'CODE' } => optimize_as \&Moose::Util::TypeConstraints::OptimizedConstraints::CodeRef; subtype 'RegexpRef' => as 'Ref' => where { ref($_) eq 'Regexp' } => @@ -711,6 +771,24 @@ subtype 'RoleName' => as 'ClassName' => where { $REGISTRY->add_type_constraint( Moose::Meta::TypeConstraint::Parameterizable->new( + name => 'ScalarRef', + package_defined_in => __PACKAGE__, + parent => find_type_constraint('Ref'), + constraint => sub { ref($_) eq 'SCALAR' || ref($_) eq 'REF' }, + optimized => + \&Moose::Util::TypeConstraints::OptimizedConstraints::ScalarRef, + constraint_generator => sub { + my $type_parameter = shift; + my $check = $type_parameter->_compiled_type_constraint; + return sub { + return $check->(${ $_ }); + }; + } + ) +); + +$REGISTRY->add_type_constraint( + Moose::Meta::TypeConstraint::Parameterizable->new( name => 'ArrayRef', package_defined_in => __PACKAGE__, parent => find_type_constraint('Ref'), @@ -769,7 +847,7 @@ $REGISTRY->add_type_constraint( ); my @PARAMETERIZABLE_TYPES - = map { $REGISTRY->get_type_constraint($_) } qw[ArrayRef HashRef Maybe]; + = map { $REGISTRY->get_type_constraint($_) } qw[ScalarRef ArrayRef HashRef Maybe]; sub get_all_parameterizable_types {@PARAMETERIZABLE_TYPES} @@ -882,13 +960,13 @@ that hierarchy represented visually. Undef Defined Value - Num - Int Str + Num + Int ClassName RoleName Ref - ScalarRef + ScalarRef[`a] ArrayRef[`a] HashRef[`a] CodeRef @@ -902,6 +980,7 @@ parameterized, this means you can say: ArrayRef[Int] # an array of integers HashRef[CodeRef] # a hash of str to CODE ref mappings + ScalarRef[Int] # a reference to an integer Maybe[Str] # value may be a string, may be undefined If Moose finds a name in brackets that it does not recognize as an @@ -979,7 +1058,7 @@ The following functions are used to create type constraints. They will also register the type constraints your create in a global registry that is used to look types up by name. -See the L for an example of how to use these. +See the L for an example of how to use these. =over 4 @@ -1026,10 +1105,10 @@ metaclass L. Creates a type constraint for either C or something of the given type. -=item B +=item B This will create a subtype of Object and test to make sure the value -C do the methods in C<@methods>. +C do the methods in C<\@methods>. This is intended as an easy way to accept non-Moose objects that provide a certain interface. If you're using Moose classes, we @@ -1037,30 +1116,30 @@ recommend that you use a C-only Role instead. =item B -If passed an ARRAY reference instead of the C<$name>, C<@methods> -pair, this will create an unnamed duck type. This can be used in an -attribute definition like so: +If passed an ARRAY reference as the only parameter instead of the +C<$name>, C<\@methods> pair, this will create an unnamed duck type. +This can be used in an attribute definition like so: has 'cache' => ( is => 'ro', isa => duck_type( [qw( get_set )] ), ); -=item B +=item B This will create a basic subtype for a given set of strings. The resulting constraint will be a subtype of C and -will match any of the items in C<@values>. It is case sensitive. -See the L for a simple example. +will match any of the items in C<\@values>. It is case sensitive. +See the L for a simple example. B This is not a true proper enum type, it is simply a convenient constraint builder. =item B -If passed an ARRAY reference instead of the C<$name>, C<@values> pair, -this will create an unnamed enum. This can then be used in an attribute -definition like so: +If passed an ARRAY reference as the only parameter instead of the +C<$name>, C<\@values> pair, this will create an unnamed enum. This +can then be used in an attribute definition like so: has 'sort_order' => ( is => 'ro', @@ -1121,59 +1200,69 @@ The valid hashref keys are C, C, and C. =item B<< match_on_type $value => ( $type => \&action, ... ?\&default ) >> -This is a utility function for doing simple type based dispatching -similar to match/case in O'Caml and case/of in Haskell. It does not -claim to be as featureful as either of those and does not support any -kind of automatic destructuring bind. However it is suitable for a fair -amount of your dispatching needs, for instance, here is a simple -Perl pretty printer dispatching over the core Moose types. +This is a utility function for doing simple type based dispatching similar to +match/case in OCaml and case/of in Haskell. It is not as featureful as those +languages, nor does not it support any kind of automatic destructuring +bind. Here is a simple Perl pretty printer dispatching over the core Moose +types. sub ppprint { my $x = shift; - match_on_type $x => - HashRef => sub { + match_on_type $x => ( + HashRef => sub { my $hash = shift; - '{ ' . (join ", " => map { - $_ . ' => ' . ppprint( $hash->{ $_ } ) - } sort keys %$hash ) . ' }' }, - ArrayRef => sub { + '{ ' + . ( + join ", " => map { $_ . ' => ' . ppprint( $hash->{$_} ) } + sort keys %$hash + ) . ' }'; + }, + ArrayRef => sub { my $array = shift; - '[ '.(join ", " => map { ppprint( $_ ) } @$array ).' ]' }, - CodeRef => sub { 'sub { ... }' }, - RegexpRef => sub { 'qr/' . $_ . '/' }, - GlobRef => sub { '*' . B::svref_2object($_)->NAME }, + '[ ' . ( join ", " => map { ppprint($_) } @$array ) . ' ]'; + }, + CodeRef => sub {'sub { ... }'}, + RegexpRef => sub { 'qr/' . $_ . '/' }, + GlobRef => sub { '*' . B::svref_2object($_)->NAME }, Object => sub { $_->can('to_string') ? $_->to_string : $_ }, - ScalarRef => sub { '\\' . ppprint( ${$_} ) }, - Num => sub { $_ }, - Str => sub { '"'. $_ . '"' }, - Undef => sub { 'undef' }, - => sub { die "I don't know what $_ is" }; + ScalarRef => sub { '\\' . ppprint( ${$_} ) }, + Num => sub {$_}, + Str => sub { '"' . $_ . '"' }, + Undef => sub {'undef'}, + => sub { die "I don't know what $_ is" } + ); } Or a simple JSON serializer: sub to_json { my $x = shift; - match_on_type $x => - HashRef => sub { + match_on_type $x => ( + HashRef => sub { my $hash = shift; - '{ ' . (join ", " => map { - '"' . $_ . '" : ' . to_json( $hash->{ $_ } ) - } sort keys %$hash ) . ' }' }, - ArrayRef => sub { + '{ ' + . ( + join ", " => + map { '"' . $_ . '" : ' . to_json( $hash->{$_} ) } + sort keys %$hash + ) . ' }'; + }, + ArrayRef => sub { my $array = shift; - '[ ' . (join ", " => map { to_json( $_ ) } @$array ) . ' ]' }, - Num => sub { $_ }, - Str => sub { '"'. $_ . '"' }, - Undef => sub { 'null' }, - => sub { die "$_ is not acceptable json type" }; + '[ ' . ( join ", " => map { to_json($_) } @$array ) . ' ]'; + }, + Num => sub {$_}, + Str => sub { '"' . $_ . '"' }, + Undef => sub {'null'}, + => sub { die "$_ is not acceptable json type" } + ); } -Based on a mapping of C<$type> to C<\&action>, where C<$type> can be -either a string type or a L object, and -C<\&action> is a CODE ref, this function will dispatch on the first -match for C<$value>. It is possible to have a catch-all at the end -in the form of a C<\&default> CODE ref. +The matcher is done by mapping a C<$type> to an C<\&action>. The C<$type> can +be either a string type or a L object, and +C<\&action> is a subroutine reference. This function will dispatch on the +first match for C<$value>. It is possible to have a catch-all by providing an +additional subroutine reference as the final argument to C. =back @@ -1186,7 +1275,7 @@ the type-coercion code first, followed by the type constraint check. This feature should be used carefully as it is very powerful and could easily take off a limb if you are not careful. -See the L for an example of how to use these. +See the L for an example of how to use these. =over 4 @@ -1340,9 +1429,7 @@ Adds C<$type> to the list of parameterizable types =head1 BUGS -All complex software has bugs lurking in it, and this module is no -exception. If you find a bug please either email me, or add the bug -to cpan-RT. +See L for details on reporting bugs. =head1 AUTHOR @@ -1350,7 +1437,7 @@ Stevan Little Estevan@iinteractive.comE =head1 COPYRIGHT AND LICENSE -Copyright 2006-2009 by Infinity Interactive, Inc. +Copyright 2006-2010 by Infinity Interactive, Inc. L