fix up a few spelling and pod issues
[gitmo/Moose.git] / lib / Moose / Meta / TypeConstraint.pm
index f85cffb..303b8fb 100644 (file)
@@ -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;
@@ -43,6 +44,18 @@ __PACKAGE__->meta->add_attribute('hand_optimized_type_constraint' => (
     predicate => 'has_hand_optimized_type_constraint',
 ));
 
+__PACKAGE__->meta->add_attribute('inlined' => (
+    init_arg  => 'inlined',
+    accessor  => '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;
@@ -122,6 +135,41 @@ sub validate {
     }
 }
 
+sub can_be_inlined {
+    my $self = shift;
+
+    if ( $self->has_parent && $self->constraint == $null_constraint ) {
+        return $self->parent->can_be_inlined;
+    }
+
+    return $self->_has_inlined_type_constraint;
+}
+
+sub _inline_check {
+    my $self = shift;
+
+    unless ( $self->can_be_inlined ) {
+        require Moose;
+        Moose->throw_error( 'Cannot inline a type constraint check for ' . $self->name );
+    }
+
+    if ( $self->has_parent && $self->constraint == $null_constraint ) {
+        return $self->parent->_inline_check(@_);
+    }
+
+    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 {
     my ($self, $value) = @_;
 
@@ -140,7 +188,12 @@ sub get_message {
     }
     else {
         # have to load it late like this, since it uses Moose itself
-        if (try { Class::MOP::load_class('Devel::PartialDump'); 1 }) {
+        my $can_partialdump = try {
+            # versions prior to 0.14 had a potential infinite loop bug
+            Class::MOP::load_class('Devel::PartialDump', { -version => 0.14 });
+            1;
+        };
+        if ($can_partialdump) {
             $value = Devel::PartialDump->new->dump($value);
         }
         else {
@@ -213,6 +266,13 @@ sub _actually_compile_type_constraint {
     return $self->_compile_hand_optimized_type_constraint
         if $self->has_hand_optimized_type_constraint;
 
+    if ( $self->can_be_inlined ) {
+        return eval_closure(
+            source      => 'sub { ' . $self->_inline_check('$_[0]') . ' }',
+            environment => $self->inline_environment,
+        );
+    }
+
     my $check = $self->constraint;
     unless ( defined $check ) {
         require Moose;
@@ -234,7 +294,6 @@ sub _compile_hand_optimized_type_constraint {
 
     unless ( ref $type_constraint ) {
         require Moose;
-        Carp::confess ("Hand optimized type constraint for " . $self->name . " is not a code reference");
         Moose->throw_error("Hand optimized type constraint is not a code reference");
     }
 
@@ -376,8 +435,24 @@ the constraint fails. This is optional.
 A L<Moose::Meta::TypeCoercion> 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<references> to the variables.
+
 =item * optimized
 
+B<This option is deprecated.>
+
 This is a variant of the C<constraint> parameter that is somehow
 optimized. Typically, this means incorporating both the type's
 constraint and all of its parents' constraints into a single
@@ -475,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<This method is deprecated.>
+
 Returns the type's hand optimized constraint, as provided to the
 constructor via the C<optimized> option.
 
 =item B<< $constraint->has_hand_optimized_type_constraint >>
 
+B<This method is deprecated.>
+
 Returns true if the type has an optimized constraint.
 
 =item B<< $constraint->create_child_type(%options) >>