X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FMoose%2FUtil%2FTypeConstraints.pm;h=d9840858e1f1cefe6e0c83dc11f1a069180b31c2;hb=8c4acc601eded1380a6496b9265a331afee580d6;hp=655894d109061e294667d745fdfcd13dd5ce2774;hpb=8ecb1fa00856ddb07f4e006c79fe4c48e08902c0;p=gitmo%2FMoose.git diff --git a/lib/Moose/Util/TypeConstraints.pm b/lib/Moose/Util/TypeConstraints.pm index 655894d..d984085 100644 --- a/lib/Moose/Util/TypeConstraints.pm +++ b/lib/Moose/Util/TypeConstraints.pm @@ -1,6 +1,4 @@ -use lib '/Users/stevan/Projects/Moose/Moose/Class-MOP/branches/Class-MOP-tranformations/lib'; - package Moose::Util::TypeConstraints; use strict; @@ -11,7 +9,28 @@ use Scalar::Util 'blessed'; use B 'svref_2object'; use Sub::Exporter; -our $VERSION = '0.09'; +our $VERSION = '0.12'; +our $AUTHORITY = 'cpan:STEVAN'; + +# Prototyped subs must be predeclared because we have a circular dependency +# with Moose::Meta::Attribute et. al. so in case of us being use'd first the +# predeclaration ensures the prototypes are in scope when consumers are +# compiled + +sub find_type_constraint ($); +sub _create_type_constraint ($$$;$$); +sub _install_type_coercions ($$); +sub create_type_constraint_union (@); +sub type ($$;$$); +sub subtype ($$;$$$); +sub coerce ($@); +sub as ($); +sub from ($); +sub where (&); +sub via (&); +sub message (&); +sub optimize_as (&); +sub enum ($;@); use Moose::Meta::TypeConstraint; use Moose::Meta::TypeCoercion; @@ -68,14 +87,18 @@ sub unimport { my ($message, $optimized); for (@_) { - $message = $_->{message} if exists $_->{message}; + $message = $_->{message} if exists $_->{message}; $optimized = $_->{optimized} if exists $_->{optimized}; } + + my $pkg_defined_in = scalar(caller(0)); - my $pkg_defined_in = scalar(caller(1)); ($TYPES{$name}->[0] eq $pkg_defined_in) - || confess "The type constraint '$name' has already been created " - if defined $name && exists $TYPES{$name}; + || confess ("The type constraint '$name' has already been created in " + . $TYPES{$name}->[0] . " and cannot be created again in " + . $pkg_defined_in) + if defined $name && exists $TYPES{$name}; + $parent = find_type_constraint($parent) if defined $parent; my $constraint = Moose::Meta::TypeConstraint->new( name => $name || '__ANON__', @@ -109,20 +132,24 @@ sub unimport { ); } - sub export_type_contstraints_as_functions { + sub export_type_constraints_as_functions { my $pkg = caller(); no strict 'refs'; foreach my $constraint (keys %TYPES) { *{"${pkg}::${constraint}"} = find_type_constraint($constraint)->_compiled_type_constraint; } - } + } + + *Moose::Util::TypeConstraints::export_type_contstraints_as_functions = \&export_type_constraints_as_functions; + + sub list_all_type_constraints { keys %TYPES } } # type constructors -sub type ($$) { - my ($name, $check) = @_; - _create_type_constraint($name, undef, $check); +sub type ($$;$$) { + splice(@_, 1, 0, undef); + goto &_create_type_constraint; } sub subtype ($$;$$$) { @@ -219,6 +246,11 @@ subtype 'Role' => where { $_->can('does') } => optimize_as { blessed($_[0]) && $_[0]->can('does') }; +{ + my @BUILTINS = list_all_type_constraints(); + sub list_all_builtin_type_constraints { @BUILTINS } +} + 1; __END__ @@ -252,9 +284,8 @@ Moose::Util::TypeConstraints - Type constraint system for Moose =head1 DESCRIPTION -This module provides Moose with the ability to create type contraints -to be are used in both attribute definitions and for method argument -validation. +This module provides Moose with the ability to create custom type +contraints to be used in attribute definition. =head2 Important Caveat @@ -287,7 +318,7 @@ this, as well as future proof your subtypes from classes which have yet to have been created yet, is to simply do this: use DateTime; - subtype 'DateTime' => as Object => where { $_->isa('DateTime') }; + subtype 'DateTime' => as 'Object' => where { $_->isa('DateTime') }; =head2 Default Type Constraints @@ -318,6 +349,40 @@ Suggestions for improvement are welcome. B The C type constraint does not work correctly in every occasion, please use it sparringly. + +=head2 Use with Other Constraint Modules + +This module should play fairly nicely with other constraint +modules with only some slight tweaking. The C clause +in types is expected to be a C reference which checks +it's first argument and returns a bool. Since most constraint +modules work in a similar way, it should be simple to adapt +them to work with Moose. + +For instance, this is how you could use it with +L to declare a completely new type. + + type 'HashOfArrayOfObjects' + => IsHashRef( + -keys => HasLength, + -values => IsArrayRef( IsObject )); + +For more examples see the F test file. + +Here is an example of using L and it's non-test +related C function. + + type 'ArrayOfHashOfBarsAndRandomNumbers' + => where { + eq_deeply($_, + array_each(subhashof({ + bar => isa('Bar'), + random_number => ignore() + }))) + }; + +For a complete example see the F +test file. =head1 FUNCTIONS @@ -335,12 +400,28 @@ meta-object. What you do with it from there is up to you :) Given a list of C<@type_constraint_names>, this will return a B instance. -=item B +=item B This will export all the current type constraints as functions into the caller's namespace. Right now, this is mostly used for testing, but it might prove useful to others. +=item B + +Alias for the above function. + +=item B + +This will return a list of type constraint names, you can then +fetch them using C if you +want to. + +=item B + +This will return a list of builtin type constraints, meaning, +those which are defined in this module. See the section +labeled L for a complete list. + =back =head2 Type Constraint Constructors @@ -349,7 +430,7 @@ The following functions are used to create type constraints. They will then register the type constraints in a global store where Moose can get to them if it needs to. -See the L for an example of how to use these. +See the L for an example of how to use these. =over 4 @@ -391,17 +472,25 @@ This is just sugar for the type constraint construction syntax. =item B +This can be used to define a "hand optimized" version of your +type constraint which can be used to avoid traversing a subtype +constraint heirarchy. + +B You should only use this if you know what you are doing, +all the built in types use this, so your subtypes (assuming they +are shallow) will not likely need to use this. + =back =head2 Type Coercion Constructors -Type constraints can also contain type coercions as well. In most -cases Moose will run 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. +Type constraints can also contain type coercions as well. If you +ask your accessor too coerce, the Moose will run 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 @@ -440,7 +529,7 @@ Stevan Little Estevan@iinteractive.comE =head1 COPYRIGHT AND LICENSE -Copyright 2006 by Infinity Interactive, Inc. +Copyright 2006, 2007 by Infinity Interactive, Inc. L