From: Jesse Luehrs Date: Sun, 26 Sep 2010 19:37:48 +0000 (-0500) Subject: let reinitialization fix metaobjs via role reconciliation X-Git-Tag: 1.15~60 X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=c1f0275a49cdf2641a17081297b05db57f78d08c;p=gitmo%2FMoose.git let reinitialization fix metaobjs via role reconciliation --- diff --git a/lib/Moose/Meta/Class.pm b/lib/Moose/Meta/Class.pm index b37b8c9..28bdbb6 100644 --- a/lib/Moose/Meta/Class.pm +++ b/lib/Moose/Meta/Class.pm @@ -606,6 +606,22 @@ sub _replace_self { Class::MOP::weaken_metaclass( $self->name ) if $self->is_anon_class; } +sub _get_compatible_single_metaclass_by_role_reconciliation { + my $self = shift; + my ($single_meta_name) = @_; + + my $current_single_meta_name = $self->_get_associated_single_metaclass($single_meta_name); + + return $self->_reconcile_roles_for_metaclass($single_meta_name, $current_single_meta_name)->name; +} + +sub _get_compatible_single_metaclass { + my $self = shift; + + return $self->SUPER::_get_compatible_single_metaclass(@_) + || $self->_get_compatible_single_metaclass_by_role_reconciliation(@_); +} + sub _process_attribute { my ( $self, $name, @args ) = @_; diff --git a/t/050_metaclasses/060_reinitialize.t b/t/050_metaclasses/060_reinitialize.t new file mode 100644 index 0000000..33de304 --- /dev/null +++ b/t/050_metaclasses/060_reinitialize.t @@ -0,0 +1,193 @@ +#!/usr/bin/env perl +use strict; +use warnings; +use Test::More; +use Test::Moose; +use Test::Exception; + +sub check_meta_sanity { + my ($meta, $class) = @_; + local $Test::Builder::Level = $Test::Builder::Level + 1; + isa_ok($meta, 'Moose::Meta::Class'); + is($meta->name, $class); + ok($meta->has_method('foo')); + isa_ok($meta->get_method('foo'), 'Moose::Meta::Method'); + ok($meta->has_attribute('bar')); + isa_ok($meta->get_attribute('bar'), 'Moose::Meta::Attribute'); +} + +{ + package Foo; + use Moose; + sub foo {} + has bar => (is => 'ro'); +} + +check_meta_sanity(Foo->meta, 'Foo'); + +Moose::Meta::Class->reinitialize('Foo'); +check_meta_sanity(Foo->meta, 'Foo'); + +{ + package Foo::Role::Method; + use Moose::Role; + + has foo => (is => 'rw'); +} + +{ + package Foo::Role::Attribute; + use Moose::Role; + has oof => (is => 'rw'); +} + +Moose::Util::MetaRole::apply_metaroles( + for => 'Foo', + class_metaroles => { + method => ['Foo::Role::Method'], + attribute => ['Foo::Role::Attribute'], + }, +); +check_meta_sanity(Foo->meta, 'Foo'); +does_ok(Foo->meta->get_method('foo'), 'Foo::Role::Method'); +does_ok(Foo->meta->get_attribute('bar'), 'Foo::Role::Attribute'); + +Moose::Meta::Class->reinitialize('Foo'); +check_meta_sanity(Foo->meta, 'Foo'); +does_ok(Foo->meta->get_method('foo'), 'Foo::Role::Method'); +does_ok(Foo->meta->get_attribute('bar'), 'Foo::Role::Attribute'); + +Foo->meta->get_method('foo')->foo('TEST'); +Foo->meta->get_attribute('bar')->oof('TSET'); +is(Foo->meta->get_method('foo')->foo, 'TEST'); +is(Foo->meta->get_attribute('bar')->oof, 'TSET'); +Moose::Meta::Class->reinitialize('Foo'); +check_meta_sanity(Foo->meta, 'Foo'); +is(Foo->meta->get_method('foo')->foo, 'TEST'); +is(Foo->meta->get_attribute('bar')->oof, 'TSET'); + +{ + package Bar::Role::Method; + use Moose::Role; +} + +{ + package Bar::Role::Attribute; + use Moose::Role; +} + +{ + package Bar; + use Moose; + Moose::Util::MetaRole::apply_metaroles( + for => 'Bar', + class_metaroles => { + method => ['Bar::Role::Method'], + attribute => ['Bar::Role::Attribute'], + }, + ); + sub foo {} + has bar => (is => 'ro'); +} + +check_meta_sanity(Bar->meta, 'Bar'); +does_ok(Bar->meta->get_method('foo'), 'Bar::Role::Method'); +does_ok(Bar->meta->get_attribute('bar'), 'Bar::Role::Attribute'); + +Moose::Meta::Class->reinitialize('Bar'); +check_meta_sanity(Bar->meta, 'Bar'); +does_ok(Bar->meta->get_method('foo'), 'Bar::Role::Method'); +does_ok(Bar->meta->get_attribute('bar'), 'Bar::Role::Attribute'); +ok(!Moose::Util::does_role(Bar->meta->get_method('foo'), 'Foo::Role::Method')); +ok(!Moose::Util::does_role(Bar->meta->get_attribute('bar'), 'Foo::Role::Attribute')); + +Moose::Util::MetaRole::apply_metaroles( + for => 'Bar', + class_metaroles => { + method => ['Foo::Role::Method'], + attribute => ['Foo::Role::Attribute'], + }, +); +check_meta_sanity(Bar->meta, 'Bar'); +does_ok(Bar->meta->get_method('foo'), 'Bar::Role::Method'); +does_ok(Bar->meta->get_attribute('bar'), 'Bar::Role::Attribute'); +does_ok(Bar->meta->get_method('foo'), 'Foo::Role::Method'); +does_ok(Bar->meta->get_attribute('bar'), 'Foo::Role::Attribute'); + +{ + package Bar::Meta::Method; + use Moose; + BEGIN { extends 'Moose::Meta::Method' }; +} + +{ + package Bar::Meta::Attribute; + use Moose; + BEGIN { extends 'Moose::Meta::Attribute' }; +} + +Moose::Meta::Class->reinitialize( + 'Bar', + method_metaclass => 'Bar::Meta::Method', + attribute_metaclass => 'Bar::Meta::Attribute', +); +check_meta_sanity(Bar->meta, 'Bar'); +isa_ok(Bar->meta->get_method('foo'), 'Bar::Meta::Method'); +does_ok(Bar->meta->get_method('foo'), 'Bar::Role::Method'); +does_ok(Bar->meta->get_method('foo'), 'Foo::Role::Method'); +isa_ok(Bar->meta->get_attribute('bar'), 'Bar::Meta::Attribute'); +does_ok(Bar->meta->get_attribute('bar'), 'Bar::Role::Attribute'); +does_ok(Bar->meta->get_attribute('bar'), 'Foo::Role::Attribute'); + +{ + package Baz::Meta::Class; + use Moose; + BEGIN { extends 'Moose::Meta::Class' }; + + sub initialize { + my $self = shift; + return $self->SUPER::initialize( + @_, + method_metaclass => 'Bar::Meta::Method', + attribute_metaclass => 'Bar::Meta::Attribute' + ); + } +} + +{ + package Baz; + use Moose -metaclass => 'Baz::Meta::Class'; + sub foo {} + has bar => (is => 'ro'); +} + +check_meta_sanity(Baz->meta, 'Baz'); +isa_ok(Baz->meta->get_method('foo'), 'Bar::Meta::Method'); +isa_ok(Baz->meta->get_attribute('bar'), 'Bar::Meta::Attribute'); +Moose::Meta::Class->reinitialize('Baz'); +check_meta_sanity(Baz->meta, 'Baz'); +isa_ok(Baz->meta->get_method('foo'), 'Bar::Meta::Method'); +isa_ok(Baz->meta->get_attribute('bar'), 'Bar::Meta::Attribute'); + +Moose::Util::MetaRole::apply_metaroles( + for => 'Baz', + class_metaroles => { + method => ['Foo::Role::Method'], + attribute => ['Foo::Role::Attribute'], + }, +); +check_meta_sanity(Baz->meta, 'Baz'); +isa_ok(Baz->meta->get_method('foo'), 'Bar::Meta::Method'); +isa_ok(Baz->meta->get_attribute('bar'), 'Bar::Meta::Attribute'); +does_ok(Baz->meta->get_method('foo'), 'Foo::Role::Method'); +does_ok(Baz->meta->get_attribute('bar'), 'Foo::Role::Attribute'); + +throws_ok { + Moose::Meta::Class->reinitialize( + 'Baz', + method_metaclass => 'Foo::Meta::Method', + attribute_metaclass => 'Foo::Meta::Attribute', + ); +} qr/compatible/; + +done_testing;