Cherry pick reinitialization fix from master
Dave Rolsky [Sun, 13 Feb 2011 23:05:03 +0000 (17:05 -0600)]
Changes
lib/Moose/Meta/Class.pm
lib/Moose/Meta/Role.pm
lib/Moose/Meta/Role/Application/ToClass.pm
t/050_metaclasses/060_reinitialize.t

diff --git a/Changes b/Changes
index dbe7eb1..644b4e3 100644 (file)
--- a/Changes
+++ b/Changes
@@ -1,6 +1,14 @@
 Also see Moose::Manual::Delta for more details of, and workarounds
 for, noteworthy changes.
 
+{{$NEXT}}
+
+  [BUG FIXES]
+
+  * When reinitializing meta objects for classes and roles, we failed to
+    preserve roles and role applications. This led to weird bugs. Many MooseX
+    modules end up reinitializing your class or role. (Dave Rolsky)
+
 1.21 Wed, Nov 24, 2010
 
   [ENHANCEMENTS]
index 7bf6736..ec9e8a3 100644 (file)
@@ -453,6 +453,24 @@ sub _process_inherited_attribute {
     }
 }
 
+# reinitialization support
+
+sub _restore_metaobjects_from {
+    my $self = shift;
+    my ($old_meta) = @_;
+
+    $self->SUPER::_restore_metaobjects_from($old_meta);
+
+    for my $role ( @{ $old_meta->roles } ) {
+        $self->add_role($role);
+    }
+
+    for my $application ( @{ $old_meta->_get_role_applications } ) {
+        $application->class($self);
+        $self->add_role_application ($application);
+    }
+}
+
 ## Immutability
 
 sub _immutable_options {
index ab14605..a8f2129 100644 (file)
@@ -224,6 +224,10 @@ sub _restore_metaobjects_from {
 
     $self->_restore_metamethods_from($old_meta);
     $self->_restore_metaattributes_from($old_meta);
+
+    for my $role ( @{ $old_meta->get_roles } ) {
+        $self->add_role($role);
+    }
 }
 
 sub add_attribute {
index 069db83..3899233 100644 (file)
@@ -18,7 +18,7 @@ __PACKAGE__->meta->add_attribute('role' => (
 ));
 
 __PACKAGE__->meta->add_attribute('class' => (
-    reader => 'class',
+    accessor => 'class',
 ));
 
 sub apply {
index ca34b7d..04d021f 100644 (file)
@@ -14,12 +14,40 @@ sub check_meta_sanity {
     isa_ok($meta->get_method('foo'), 'Moose::Meta::Method');
     ok($meta->has_attribute('bar'));
     isa_ok($meta->get_attribute('bar'), 'Moose::Meta::Attribute');
+
+    if ( $meta->name eq 'Foo' ) {
+        ok($meta->does_role('Role1'), 'does Role1');
+        ok($meta->does_role('Role2'), 'does Role2');
+
+        is_deeply(
+            [
+                map { [ $_->role->name, $_->class->name ] }
+                    sort { $a->role->name cmp $b->role->name }
+                    $meta->role_applications
+            ],
+            [
+                [ 'Role1|Role2', 'Foo' ],
+            ],
+            'role applications for Role1 and Role2'
+        );
+    }
+}
+
+{
+    package Role1;
+    use Moose::Role;
+}
+
+{
+    package Role2;
+    use Moose::Role;
 }
 
 {
     package Foo;
     use Moose;
     sub foo {}
+    with 'Role1', 'Role2';
     has bar => (is => 'ro');
 }
 
@@ -276,4 +304,18 @@ ok(Quux->meta->has_method('DEMOLISH'));
 isa_ok(Quux->meta->get_method('DEMOLISH'), 'Moose::Meta::Method');
 does_ok(Quux->meta->get_method('DEMOLISH'), 'Foo::Role::Method');
 
+{
+    package Role3;
+    use Moose::Role;
+    with 'Role1', 'Role2';
+}
+
+ok( Role3->meta->does_role('Role1'), 'Role3 does Role1' );
+ok( Role3->meta->does_role('Role2'), 'Role3 does Role2' );
+
+Moose::Meta::Role->reinitialize('Role3');
+
+ok( Role3->meta->does_role('Role1'), 'Role3 does Role1 after reinitialize' );
+ok( Role3->meta->does_role('Role2'), 'Role3 does Role2 after reinitialize' );
+
 done_testing;