Make sure we always local-ize $@ and $SIG{__DIE__} for code evals.
Dave Rolsky [Sun, 21 Jun 2009 16:14:09 +0000 (11:14 -0500)]
This required some changes to the CMOP::Method::Inlined API which
propogated out to anything that calls ->_eval_closure.

lib/Class/MOP/Class.pm
lib/Class/MOP/Method/Accessor.pm
lib/Class/MOP/Method/Constructor.pm
lib/Class/MOP/Method/Generated.pm
t/310_inline_structor.t
t/311_inline_and_dollar_at.t [new file with mode: 0644]

index ecfe5b2..d9f903b 100644 (file)
@@ -623,7 +623,7 @@ sub add_method {
 
     my ( $current_package, $current_name ) = Class::MOP::get_code_info($body);
 
-    if ( $current_name eq '__ANON__' ) {
+    if ( !defined $current_name || $current_name eq '__ANON__' ) {
         my $full_method_name = ($self->name . '::' . $method_name);
         subname($full_method_name => $body);
     }
index 1f71913..40b5ec7 100644 (file)
@@ -159,7 +159,7 @@ sub _generate_accessor_method_inline {
     my $attr_name     = $attr->name;
     my $meta_instance = $attr->associated_class->instance_metaclass;
 
-    my $code = $self->_eval_closure(
+    my ( $code, $e ) = $self->_eval_closure(
         {},
         'sub {'
         . $meta_instance->inline_set_slot_value('$_[0]', $attr_name, '$_[1]')
@@ -167,7 +167,7 @@ sub _generate_accessor_method_inline {
         . $meta_instance->inline_get_slot_value('$_[0]', $attr_name)
         . '}'
     );
-    confess "Could not generate inline accessor because : $@" if $@;
+    confess "Could not generate inline accessor because : $e" if $e;
 
     return $code;
 }
@@ -184,14 +184,14 @@ sub _generate_reader_method_inline {
     my $attr_name     = $attr->name;
     my $meta_instance = $attr->associated_class->instance_metaclass;
 
-     my $code = $self->_eval_closure(
+     my ( $code, $e ) = $self->_eval_closure(
          {},
         'sub {'
         . 'confess "Cannot assign a value to a read-only accessor" if @_ > 1;'
         . $meta_instance->inline_get_slot_value('$_[0]', $attr_name)
         . '}'
     );
-    confess "Could not generate inline reader because : $@" if $@;
+    confess "Could not generate inline reader because : $e" if $e;
 
     return $code;
 }
@@ -208,13 +208,13 @@ sub _generate_writer_method_inline {
     my $attr_name     = $attr->name;
     my $meta_instance = $attr->associated_class->instance_metaclass;
 
-    my $code = $self->_eval_closure(
+    my ( $code, $e ) = $self->_eval_closure(
         {},
         'sub {'
         . $meta_instance->inline_set_slot_value('$_[0]', $attr_name, '$_[1]')
         . '}'
     );
-    confess "Could not generate inline writer because : $@" if $@;
+    confess "Could not generate inline writer because : $e" if $e;
 
     return $code;
 }
@@ -231,13 +231,13 @@ sub _generate_predicate_method_inline {
     my $attr_name     = $attr->name;
     my $meta_instance = $attr->associated_class->instance_metaclass;
 
-    my $code = $self->_eval_closure(
+    my ( $code, $e ) = $self->_eval_closure(
         {},
        'sub {'
        . $meta_instance->inline_is_slot_initialized('$_[0]', $attr_name)
        . '}'
     );
-    confess "Could not generate inline predicate because : $@" if $@;
+    confess "Could not generate inline predicate because : $e" if $e;
 
     return $code;
 }
@@ -254,13 +254,13 @@ sub _generate_clearer_method_inline {
     my $attr_name     = $attr->name;
     my $meta_instance = $attr->associated_class->instance_metaclass;
 
-    my $code = $self->_eval_closure(
+    my ( $code, $e ) = $self->_eval_closure(
         {},
         'sub {'
         . $meta_instance->inline_deinitialize_slot('$_[0]', $attr_name)
         . '}'
     );
-    confess "Could not generate inline clearer because : $@" if $@;
+    confess "Could not generate inline clearer because : $e" if $e;
 
     return $code;
 }
index 14a3c80..c30e0f4 100644 (file)
@@ -136,11 +136,11 @@ sub _generate_constructor_method_inline {
     $source .= ";\n" . '}';
     warn $source if $self->options->{debug};
 
-    my $code = $self->_eval_closure(
+    my ( $code, $e ) = $self->_eval_closure(
         $close_over,
         $source
     );
-    confess "Could not eval the constructor :\n\n$source\n\nbecause :\n\n$@" if $@;
+    confess "Could not eval the constructor :\n\n$source\n\nbecause :\n\n$e" if $e;
 
     return $code;
 }
index 5af96b8..ea0ea2c 100644 (file)
@@ -29,22 +29,29 @@ sub _initialize_body {
 sub _eval_closure {
     # my ($self, $captures, $sub_body) = @_;
     my $__captures = $_[1];
-    eval join(
-        "\n",
-        (
+
+    my $code;
+
+    my $e = do {
+        local $@;
+        local $SIG{__DIE__};
+        $code = eval join
+            "\n", (
             map {
                 /^([\@\%\$])/
                     or die "capture key should start with \@, \% or \$: $_";
-                q[my ]
-                . $_ . q[ = ]
-                . $1
-                . q[{$__captures->{']
-                . $_
-                . q['}};];
-            } keys %$__captures
-        ),
-        $_[2]
-    );
+                q[my ] 
+                    . $_ . q[ = ] 
+                    . $1
+                    . q[{$__captures->{']
+                    . $_ . q['}};];
+                } keys %$__captures
+            ),
+            $_[2];
+        $@;
+    };
+
+    return ( $code, $e );
 }
 
 sub _add_line_directive {
index bbdcce8..efceb2f 100644 (file)
@@ -202,13 +202,15 @@ use Class::MOP;
     sub _inline_destructor {
         my $self = shift;
 
-        my $code = $self->_eval_closure( {}, 'sub { }' );
+        my ( $code, $e ) = $self->_eval_closure( {}, 'sub { }' );
+        die $e if $e;
 
         $self->{body} = $code;
     }
 
     sub is_needed { 1 }
     sub associated_metaclass { $_[0]->{metaclass} }
+    sub body { $_[0]->{body} }
     sub _expected_method_class { 'Base::Class' }
 }
 
diff --git a/t/311_inline_and_dollar_at.t b/t/311_inline_and_dollar_at.t
new file mode 100644 (file)
index 0000000..c1fc286
--- /dev/null
@@ -0,0 +1,21 @@
+use strict;
+use warnings;
+
+use Test::More;
+
+plan tests => 1;
+
+use Class::MOP;
+
+
+{
+    package Foo;
+
+    my $meta = Class::MOP::Class->initialize(__PACKAGE__);
+
+    $@ = 'dollar at';
+
+    $meta->make_immutable;
+
+    ::is( $@, 'dollar at', '$@ is untouched after immutablization' );
+}