From: Florian Ragwitz Date: Fri, 26 Mar 2010 15:01:55 +0000 (+0100) Subject: Make handles accept role TCs. X-Git-Tag: 1.01~1 X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=c776160203d49277d4501b76ec02ef10d306193b;p=gitmo%2FMoose.git Make handles accept role TCs. --- diff --git a/Changes b/Changes index 165cd13..4f33010 100644 --- a/Changes +++ b/Changes @@ -1,22 +1,31 @@ Also see Moose::Manual::Delta for more details of, and workarounds for, noteworthy changes. -1.01 +1.01 + + [NEW FEATURES] + + * The handles option now also accepts a role type constraint in addition to a + plain role name. (Florian Ragwitz) [OTHER] + * Record the Sartak/doy debt properly in Changes (perigrin) 1.00 Tue, Mar 25, 2010 [BUG FIXES] + * Moose::Meta::Attribute::Native::Trait::Code no longer creates reader methods by default. (Florian Ragwitz) [DOCUMENTATION] + * Improve various parts of the documentation and fix many typos. (Dave Rolsky, Mateu Hunter, Graham Knop, Robin V, Jay Hannah, Jesse Luehrs) [OTHER] + * Paid the $10 debt to doy from 0.80 Sat, Jun 6, 2009 (Sartak) 0.99 Mon, Mar 8, 2010 diff --git a/lib/Moose.pm b/lib/Moose.pm index 484364f..b6d32ae 100644 --- a/lib/Moose.pm +++ b/lib/Moose.pm @@ -492,7 +492,7 @@ B Triggers will only fire when you B to the attribute, either in the constructor, or using the writer. Default and built values will B cause the trigger to be fired. -=item I ARRAY | HASH | REGEXP | ROLE | DUCKTYPE | CODE> +=item I ARRAY | HASH | REGEXP | ROLE | ROLETYPE | DUCKTYPE | CODE> The I option provides Moose classes with automated delegation features. This is a pretty complex and powerful option. It accepts many different option @@ -588,13 +588,14 @@ B An I option is required when using the regexp option format. This is so that we can determine (at compile time) the method list from the class. Without an I this is just not possible. -=item C +=item C or C -With the role option, you specify the name of a role whose "interface" then -becomes the list of methods to handle. The "interface" can be defined as; the -methods of the role and any required methods of the role. It should be noted -that this does B include any method modifiers or generated attribute -methods (which is consistent with role composition). +With the role option, you specify the name of a role or a +L whose "interface" then becomes +the list of methods to handle. The "interface" can be defined as; the methods +of the role and any required methods of the role. It should be noted that this +does B include any method modifiers or generated attribute methods (which +is consistent with role composition). =item C diff --git a/lib/Moose/Meta/Attribute.pm b/lib/Moose/Meta/Attribute.pm index b6abcdb..6da44fd 100644 --- a/lib/Moose/Meta/Attribute.pm +++ b/lib/Moose/Meta/Attribute.pm @@ -659,23 +659,25 @@ sub _canonicalize_handles { elsif (blessed($handles) && $handles->isa('Moose::Meta::TypeConstraint::DuckType')) { return map { $_ => $_ } @{ $handles->methods }; } + elsif (blessed($handles) && $handles->isa('Moose::Meta::TypeConstraint::Role')) { + $handles = $handles->role; + } else { $self->throw_error("Unable to canonicalize the 'handles' option with $handles", data => $handles); } } - else { - Class::MOP::load_class($handles); - my $role_meta = Class::MOP::class_of($handles); - (blessed $role_meta && $role_meta->isa('Moose::Meta::Role')) - || $self->throw_error("Unable to canonicalize the 'handles' option with $handles because its metaclass is not a Moose::Meta::Role", data => $handles); + Class::MOP::load_class($handles); + my $role_meta = Class::MOP::class_of($handles); - return map { $_ => $_ } - grep { $_ ne 'meta' } ( - $role_meta->get_method_list, - map { $_->name } $role_meta->get_required_method_list, - ); - } + (blessed $role_meta && $role_meta->isa('Moose::Meta::Role')) + || $self->throw_error("Unable to canonicalize the 'handles' option with $handles because its metaclass is not a Moose::Meta::Role", data => $handles); + + return map { $_ => $_ } + grep { $_ ne 'meta' } ( + $role_meta->get_method_list, + map { $_->name } $role_meta->get_required_method_list, + ); } sub _find_delegate_metaclass { diff --git a/t/020_attributes/010_attribute_delegation.t b/t/020_attributes/010_attribute_delegation.t index 16ec30e..bcd4cc7 100644 --- a/t/020_attributes/010_attribute_delegation.t +++ b/t/020_attributes/010_attribute_delegation.t @@ -243,6 +243,15 @@ is($car->stop, 'Engine::stop', '... got the right value from ->stop'); handles => 'Foo::Bar', ); + package Foo::OtherThing; + use Moose; + use Moose::Util::TypeConstraints; + + has 'other_thing' => ( + is => 'rw', + isa => 'Foo::Baz', + handles => Moose::Util::TypeConstraints::find_type_constraint('Foo::Bar'), + ); } { @@ -259,6 +268,19 @@ is($car->stop, 'Engine::stop', '... got the right value from ->stop'); is($foo->thing->baz, 'Foo::Baz::BAZ', '... got the right value'); } +{ + my $foo = Foo::OtherThing->new(other_thing => Foo::Baz->new); + isa_ok($foo, 'Foo::OtherThing'); + isa_ok($foo->other_thing, 'Foo::Baz'); + + ok($foo->meta->has_method('foo'), '... we have the method we expect'); + ok($foo->meta->has_method('bar'), '... we have the method we expect'); + ok(!$foo->meta->has_method('baz'), '... we dont have the method we expect'); + + is($foo->foo, 'Foo::Baz::FOO', '... got the right value'); + is($foo->bar, 'Foo::Baz::BAR', '... got the right value'); + is($foo->other_thing->baz, 'Foo::Baz::BAZ', '... got the right value'); +} # ------------------------------------------------------------------- # AUTOLOAD & handles # -------------------------------------------------------------------