From: Fuji, Goro Date: Mon, 27 Sep 2010 12:44:36 +0000 (+0900) Subject: Fix the delegation rule X-Git-Tag: 0.76~6 X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=cd81020880fad959c9f5d378345755f33846d5b6;p=gitmo%2FMouse.git Fix the delegation rule --- diff --git a/Moose-t-failing/020_attributes/011_more_attr_delegation.t b/Moose-t-failing/020_attributes/011_more_attr_delegation.t deleted file mode 100644 index c588848..0000000 --- a/Moose-t-failing/020_attributes/011_more_attr_delegation.t +++ /dev/null @@ -1,267 +0,0 @@ -#!/usr/bin/perl -# This is automatically generated by author/import-moose-test.pl. -# DO NOT EDIT THIS FILE. ANY CHANGES WILL BE LOST!!! -use t::lib::MooseCompat; - -use strict; -use warnings; - -use Test::More; -$TODO = q{Mouse is not yet completed}; -use Test::Exception; - -=pod - -This tests the more complex -delegation cases and that they -do not fail at compile time. - -=cut - -{ - - package ChildASuper; - use Mouse; - - sub child_a_super_method { "as" } - - package ChildA; - use Mouse; - - extends "ChildASuper"; - - sub child_a_method_1 { "a1" } - sub child_a_method_2 { Scalar::Util::blessed($_[0]) . " a2" } - - package ChildASub; - use Mouse; - - extends "ChildA"; - - sub child_a_method_3 { "a3" } - - package ChildB; - use Mouse; - - sub child_b_method_1 { "b1" } - sub child_b_method_2 { "b2" } - sub child_b_method_3 { "b3" } - - package ChildC; - use Mouse; - - sub child_c_method_1 { "c1" } - sub child_c_method_2 { "c2" } - sub child_c_method_3_la { "c3" } - sub child_c_method_4_la { "c4" } - - package ChildD; - use Mouse; - - sub child_d_method_1 { "d1" } - sub child_d_method_2 { "d2" } - - package ChildE; - # no Mouse - - sub new { bless {}, shift } - sub child_e_method_1 { "e1" } - sub child_e_method_2 { "e2" } - - package ChildF; - # no Mouse - - sub new { bless {}, shift } - sub child_f_method_1 { "f1" } - sub child_f_method_2 { "f2" } - - package ChildG; - use Mouse; - - sub child_g_method_1 { "g1" } - - package ChildH; - use Mouse; - - sub child_h_method_1 { "h1" } - sub parent_method_1 { "child_parent_1" } - - package ChildI; - use Mouse; - - sub child_i_method_1 { "i1" } - sub parent_method_1 { "child_parent_1" } - - package Parent; - use Mouse; - - sub parent_method_1 { "parent_1" } - ::can_ok('Parent', 'parent_method_1'); - - ::dies_ok { - has child_a => ( - is => "ro", - default => sub { ChildA->new }, - handles => qr/.*/, - ); - } "all_methods requires explicit isa"; - - ::lives_ok { - has child_a => ( - isa => "ChildA", - is => "ro", - default => sub { ChildA->new }, - handles => qr/.*/, - ); - } "allow all_methods with explicit isa"; - - ::lives_ok { - has child_b => ( - is => 'ro', - default => sub { ChildB->new }, - handles => [qw/child_b_method_1/], - ); - } "don't need to declare isa if method list is predefined"; - - ::lives_ok { - has child_c => ( - isa => "ChildC", - is => "ro", - default => sub { ChildC->new }, - handles => qr/_la$/, - ); - } "can declare regex collector"; - - ::dies_ok { - has child_d => ( - is => "ro", - default => sub { ChildD->new }, - handles => sub { - my ( $class, $delegate_class ) = @_; - } - ); - } "can't create attr with generative handles parameter and no isa"; - - ::lives_ok { - has child_d => ( - isa => "ChildD", - is => "ro", - default => sub { ChildD->new }, - handles => sub { - my ( $class, $delegate_class ) = @_; - return; - } - ); - } "can't create attr with generative handles parameter and no isa"; - - ::lives_ok { - has child_e => ( - isa => "ChildE", - is => "ro", - default => sub { ChildE->new }, - handles => ["child_e_method_2"], - ); - } "can delegate to non moose class using explicit method list"; - - my $delegate_class; - ::lives_ok { - has child_f => ( - isa => "ChildF", - is => "ro", - default => sub { ChildF->new }, - handles => sub { - $delegate_class = $_[1]->name; - return; - }, - ); - } "subrefs on non moose class give no meta"; - - ::is( $delegate_class, "ChildF", "plain classes are handed down to subs" ); - - ::lives_ok { - has child_g => ( - isa => "ChildG", - default => sub { ChildG->new }, - handles => ["child_g_method_1"], - ); - } "can delegate to object even without explicit reader"; - - ::can_ok('Parent', 'parent_method_1'); - ::dies_ok { - has child_h => ( - isa => "ChildH", - is => "ro", - default => sub { ChildH->new }, - handles => sub { map { $_, $_ } $_[1]->get_all_method_names }, - ); - } "Can't override exisiting class method in delegate"; - ::can_ok('Parent', 'parent_method_1'); - - ::lives_ok { - has child_i => ( - isa => "ChildI", - is => "ro", - default => sub { ChildI->new }, - handles => sub { - map { $_, $_ } grep { !/^parent_method_1|meta$/ } - $_[1]->get_all_method_names; - }, - ); - } "Test handles code ref for skipping predefined methods"; - - - sub parent_method { "p" } -} - -# sanity - -isa_ok( my $p = Parent->new, "Parent" ); -isa_ok( $p->child_a, "ChildA" ); -isa_ok( $p->child_b, "ChildB" ); -isa_ok( $p->child_c, "ChildC" ); -isa_ok( $p->child_d, "ChildD" ); -isa_ok( $p->child_e, "ChildE" ); -isa_ok( $p->child_f, "ChildF" ); -isa_ok( $p->child_i, "ChildI" ); - -ok(!$p->can('child_g'), '... no child_g accessor defined'); -ok(!$p->can('child_h'), '... no child_h accessor defined'); - - -is( $p->parent_method, "p", "parent method" ); -is( $p->child_a->child_a_super_method, "as", "child supermethod" ); -is( $p->child_a->child_a_method_1, "a1", "child method" ); - -can_ok( $p, "child_a_super_method" ); -can_ok( $p, "child_a_method_1" ); -can_ok( $p, "child_a_method_2" ); -ok( !$p->can( "child_a_method_3" ), "but not subclass of delegate class" ); - -is( $p->child_a_method_1, $p->child_a->child_a_method_1, "delegate behaves the same" ); -is( $p->child_a_method_2, "ChildA a2", "delegates are their own invocants" ); - - -can_ok( $p, "child_b_method_1" ); -ok( !$p->can("child_b_method_2"), "but not ChildB's unspecified siblings" ); - - -ok( !$p->can($_), "none of ChildD's methods ($_)" ) - for grep { /^child/ } map { $_->name } ChildD->meta->get_all_methods(); - -can_ok( $p, "child_c_method_3_la" ); -can_ok( $p, "child_c_method_4_la" ); - -is( $p->child_c_method_3_la, "c3", "ChildC method delegated OK" ); - -can_ok( $p, "child_e_method_2" ); -ok( !$p->can("child_e_method_1"), "but not child_e_method_1"); - -is( $p->child_e_method_2, "e2", "delegate to non moose class (child_e_method_2)" ); - -can_ok( $p, "child_g_method_1" ); -is( $p->child_g_method_1, "g1", "delegate to moose class without reader (child_g_method_1)" ); - -can_ok( $p, "child_i_method_1" ); -is( $p->parent_method_1, "parent_1", "delegate doesn't override existing method" ); - -done_testing; diff --git a/lib/Mouse/Meta/Attribute.pm b/lib/Mouse/Meta/Attribute.pm index 736c814..bb5c05f 100644 --- a/lib/Mouse/Meta/Attribute.pm +++ b/lib/Mouse/Meta/Attribute.pm @@ -263,8 +263,9 @@ sub install_accessors{ # install delegation if(exists $attribute->{handles}){ my %handles = $attribute->_canonicalize_handles(); - while(my($handle, $method_to_call) = each %handles){ + next if Mouse::Object->can($handle); + if($metaclass->has_method($handle)) { $attribute->throw_error("You cannot overwrite a locally defined method ($handle) with a delegation"); } @@ -298,7 +299,7 @@ sub _canonicalize_handles { elsif ($handle_type eq 'Regexp') { my $meta = $self->_find_delegate_metaclass(); return map { $_ => $_ } - grep { !Mouse::Object->can($_) && $_ =~ $handles } + grep { /$handles/ } Mouse::Util::is_a_metarole($meta) ? $meta->get_method_list : $meta->get_all_method_names; diff --git a/t/020_attributes/011_more_attr_delegation.t b/t/020_attributes/011_more_attr_delegation.t index 75d6fa1..5d958c2 100644 --- a/t/020_attributes/011_more_attr_delegation.t +++ b/t/020_attributes/011_more_attr_delegation.t @@ -1,9 +1,12 @@ #!/usr/bin/perl +# This is automatically generated by author/import-moose-test.pl. +# DO NOT EDIT THIS FILE. ANY CHANGES WILL BE LOST!!! +use t::lib::MooseCompat; use strict; use warnings; -use Test::More tests => 39; +use Test::More; use Test::Exception; =pod @@ -76,9 +79,24 @@ do not fail at compile time. sub child_g_method_1 { "g1" } + package ChildH; + use Mouse; + + sub child_h_method_1 { "h1" } + sub parent_method_1 { "child_parent_1" } + + package ChildI; + use Mouse; + + sub child_i_method_1 { "i1" } + sub parent_method_1 { "child_parent_1" } + package Parent; use Mouse; + sub parent_method_1 { "parent_1" } + ::can_ok('Parent', 'parent_method_1'); + ::dies_ok { has child_a => ( is => "ro", @@ -167,11 +185,34 @@ do not fail at compile time. ); } "can delegate to object even without explicit reader"; + ::can_ok('Parent', 'parent_method_1'); + ::dies_ok { + has child_h => ( + isa => "ChildH", + is => "ro", + default => sub { ChildH->new }, + handles => sub { map { $_, $_ } $_[1]->get_all_method_names }, + ); + } "Can't override exisiting class method in delegate"; + ::can_ok('Parent', 'parent_method_1'); + + ::lives_ok { + has child_i => ( + isa => "ChildI", + is => "ro", + default => sub { ChildI->new }, + handles => sub { + map { $_, $_ } grep { !/^parent_method_1|meta$/ } + $_[1]->get_all_method_names; + }, + ); + } "Test handles code ref for skipping predefined methods"; + + sub parent_method { "p" } } # sanity - isa_ok( my $p = Parent->new, "Parent" ); isa_ok( $p->child_a, "ChildA" ); isa_ok( $p->child_b, "ChildB" ); @@ -179,9 +220,12 @@ isa_ok( $p->child_c, "ChildC" ); isa_ok( $p->child_d, "ChildD" ); isa_ok( $p->child_e, "ChildE" ); isa_ok( $p->child_f, "ChildF" ); +isa_ok( $p->child_i, "ChildI" ); ok(!$p->can('child_g'), '... no child_g accessor defined'); - +{ local $TODO = 'Mouse does not install delegations atomically'; +ok(!$p->can('child_h'), '... no child_h accessor defined'); +} is( $p->parent_method, "p", "parent method" ); is( $p->child_a->child_a_super_method, "as", "child supermethod" ); @@ -215,3 +259,8 @@ is( $p->child_e_method_2, "e2", "delegate to non moose class (child_e_method_2)" can_ok( $p, "child_g_method_1" ); is( $p->child_g_method_1, "g1", "delegate to moose class without reader (child_g_method_1)" ); + +can_ok( $p, "child_i_method_1" ); +is( $p->parent_method_1, "parent_1", "delegate doesn't override existing method" ); + +done_testing;