Sartak created t/100_bugs/024_anon_method_metaclass.t on May 16th.

The bug is that when an anonymous class's meta object goes out of
scope, the anonymous class is destroyed, even if there are still
instances of the anonymous class in scope (by scope, I really mean if
any non-weak reference still exists).

The root cause of this bug is that
Moose::Meta::Class::_construct_instance overrides
Class::MOP::Class::_construct_instance, and Moose hasn't got the line
that creates a reference to the meta object in the instance of the
anonymous class (nor does it call SUPER).

The fact that Moose::Meta::Class::_construct_instance and
Class::MOP::Class::_construct_instance are so much alike bothers me a
bit; would we want to refactor one or both of these methods to allow
for less code duplication?

I've attached a patch with a possible fix and an update to the tests.
The patch updates Moose::Meta::Class::_construct_instance to include
the code in Class::MOP::Class::_construct_instance. I wouldn't be
opposed to taking a stab at a bigger code change, though, if that's
what we want (to reduce the duplicate code) -- but that would involve
changes to Class::MOP, I imagine.

-- Dan
diff --git a/lib/Moose/Meta/Class.pm b/lib/Moose/Meta/Class.pm
index 2d8a56b..9618821 100644
--- a/lib/Moose/Meta/Class.pm
+++ b/lib/Moose/Meta/Class.pm
@@ -227,6 +227,8 @@ sub new_object {
     return $self;
 }
 
+# FIXME: this looks very similar to Class::MOP::Class::_construct_instance;
+# can we reduce code duplication?
 sub _construct_instance {
     my $class = shift;
     my $params = @_ == 1 ? $_[0] : {...@_};
@@ -239,6 +241,18 @@ sub _construct_instance {
     foreach my $attr ($class->get_all_attributes()) {
         $attr->initialize_instance_slot($meta_instance, $instance, $params);
     }
+    # NOTE:
+    # this will only work for a HASH instance type
+    # NOTE: Class::MOP::Class::_construct_instance dies here if $instance
+    # isn't a hashref. Do we want that behaviour?
+    if ($class->is_anon_class and Scalar::Util::reftype($instance) eq 'HASH') {
+        # NOTE:
+        # At some point we should make this official
+        # as a reserved slot name, but right now I am
+        # going to keep it here.
+        # my $RESERVED_MOP_SLOT = '__MOP__';
+        $instance->{'__MOP__'} = $class;
+    }
     return $instance;
 }
 
diff --git a/t/010_basics/018_methods.t b/t/010_basics/018_methods.t
index 84fb963..b7c337f 100644
--- a/t/010_basics/018_methods.t
+++ b/t/010_basics/018_methods.t
@@ -10,6 +10,7 @@ my $test1 = Moose::Meta::Class->create_anon_class;
 $test1->add_method( 'foo1', sub { } );
 
 my $t1    = $test1->new_object;
+undef $test1; # be sure $t1 is still valid if the meta object goes out of scope
 my $t1_am = $t1->meta->get_method('foo1')->associated_metaclass;
 
 ok( $t1_am, 'associated_metaclass is defined' );
diff --git a/t/100_bugs/024_anon_method_metaclass.t b/t/100_bugs/024_anon_method_metaclass.t
index 81e6813..a316790 100644
--- a/t/100_bugs/024_anon_method_metaclass.t
+++ b/t/100_bugs/024_anon_method_metaclass.t
@@ -39,7 +39,7 @@ for ( 1, 2 ) {
     is( Ball->meta->get_method('bounce'), $method_object,
         'original method object is preserved' );
 
-    local $TODO = "method metaclass seems to be reinitialized" if !$method_meta;
+#    local $TODO = "method metaclass seems to be reinitialized" if !$method_meta;
 
     is( Ball->meta->get_method('bounce')->meta . '', $original_meta,
         "method's metaclass still exists" );

Reply via email to