X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FMoose%2FMeta%2FTypeConstraint.pm;h=303b8fb4af5c4668d2beffbf686049955b33529d;hb=297899d15cdf00745649d439545a1e7daeac28b8;hp=1ce53c0b9b2ff8f2422eb691c51bf0b5e6be31a0;hpb=92efe680e120e70b2b6e4aba277bd70ca64f05e5;p=gitmo%2FMoose.git diff --git a/lib/Moose/Meta/TypeConstraint.pm b/lib/Moose/Meta/TypeConstraint.pm index 1ce53c0..303b8fb 100644 --- a/lib/Moose/Meta/TypeConstraint.pm +++ b/lib/Moose/Meta/TypeConstraint.pm @@ -10,6 +10,7 @@ use overload '0+' => sub { refaddr(shift) }, # id an object bool => sub { 1 }, fallback => 1; +use Eval::Closure; use Scalar::Util qw(blessed refaddr); use Sub::Name qw(subname); use Try::Tiny; @@ -49,6 +50,12 @@ __PACKAGE__->meta->add_attribute('inlined' => ( predicate => '_has_inlined_type_constraint', )); +__PACKAGE__->meta->add_attribute('inline_environment' => ( + init_arg => 'inline_environment', + accessor => '_inline_environment', + default => sub { {} }, +)); + sub parents { my $self; $self->parent; @@ -128,11 +135,11 @@ sub validate { } } -sub has_inlined_type_constraint { +sub can_be_inlined { my $self = shift; if ( $self->has_parent && $self->constraint == $null_constraint ) { - return $self->parent->has_inlined_type_constraint; + return $self->parent->can_be_inlined; } return $self->_has_inlined_type_constraint; @@ -141,7 +148,7 @@ sub has_inlined_type_constraint { sub _inline_check { my $self = shift; - unless ( $self->has_inlined_type_constraint ) { + unless ( $self->can_be_inlined ) { require Moose; Moose->throw_error( 'Cannot inline a type constraint check for ' . $self->name ); } @@ -150,7 +157,17 @@ sub _inline_check { return $self->parent->_inline_check(@_); } - return $self->inlined->( $self, @_ ); + return '( do { ' . $self->inlined->( $self, @_ ) . ' } )'; +} + +sub inline_environment { + my $self = shift; + + if ( $self->has_parent && $self->constraint == $null_constraint ) { + return $self->parent->inline_environment; + } + + return $self->_inline_environment; } sub assert_valid { @@ -249,12 +266,11 @@ sub _actually_compile_type_constraint { return $self->_compile_hand_optimized_type_constraint if $self->has_hand_optimized_type_constraint; - if ( $self->has_inlined_type_constraint ) { - local $@; - my $sub = eval 'sub { ' . $self->_inline_check('$_[0]') . '}'; - die $@ if $@; - - return $sub; + if ( $self->can_be_inlined ) { + return eval_closure( + source => 'sub { ' . $self->_inline_check('$_[0]') . ' }', + environment => $self->inline_environment, + ); } my $check = $self->constraint; @@ -419,8 +435,24 @@ the constraint fails. This is optional. A L object representing the coercions to the type. This is optional. +=item * inlined + +A subroutine which returns a string suitable for inlining this type +constraint. It will be called as a method on the type constraint object, and +will receive a single additional parameter, a variable name to be tested +(usually C<"$_"> or C<"$_[0]">. + +This is optional. + +=item * inline_environment + +A hash reference of variables to close over. The keys are variables names, and +the values are I to the variables. + =item * optimized +B + This is a variant of the C parameter that is somehow optimized. Typically, this means incorporating both the type's constraint and all of its parents' constraints into a single @@ -518,13 +550,23 @@ exists. Returns true if the type has a coercion. +=item B<< $constraint->can_be_inlined >> + +Returns true if this type constraint can be inlined. A type constraint which +subtypes an inlinable constraint and does not add an additional constraint +"inherits" its parent type's inlining. + =item B<< $constraint->hand_optimized_type_constraint >> +B + Returns the type's hand optimized constraint, as provided to the constructor via the C option. =item B<< $constraint->has_hand_optimized_type_constraint >> +B + Returns true if the type has an optimized constraint. =item B<< $constraint->create_child_type(%options) >>