From: Tokuhiro Matsuno Date: Sat, 7 Mar 2009 01:32:11 +0000 (+0000) Subject: oops. we want to use 'metaclass' in role, too :( X-Git-Tag: 0.19~8 X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?p=gitmo%2FMouse.git;a=commitdiff_plain;h=05b9dc92e107117921170e662967d5d2101db21b oops. we want to use 'metaclass' in role, too :( --- diff --git a/lib/Mouse/Meta/Role.pm b/lib/Mouse/Meta/Role.pm index 95bdca8..e82690d 100644 --- a/lib/Mouse/Meta/Role.pm +++ b/lib/Mouse/Meta/Role.pm @@ -2,6 +2,7 @@ package Mouse::Meta::Role; use strict; use warnings; use Carp 'confess'; +use Mouse::Util; do { my %METACLASS_CACHE; @@ -107,7 +108,19 @@ sub apply { for my $name ($self->get_attribute_list) { next if $class->has_attribute($name); my $spec = $self->get_attribute($name); - Mouse::Meta::Attribute->create($class, $name, %$spec); + + my $metaclass = 'Mouse::Meta::Attribute'; + if ( my $metaclass_name = $spec->{metaclass} ) { + my $new_class = Mouse::Util::resolve_metaclass_alias( + 'Attribute', + $metaclass_name + ); + if ( $metaclass ne $new_class ) { + $metaclass = $new_class; + } + } + + $metaclass->create($class, $name, %$spec); } } else { # apply role to role @@ -188,7 +201,19 @@ sub combine_apply { for my $name ($self->get_attribute_list) { next if $class->has_attribute($name); my $spec = $self->get_attribute($name); - Mouse::Meta::Attribute->create($class, $name, %$spec); + + my $metaclass = 'Mouse::Meta::Attribute'; + if ( my $metaclass_name = $spec->{metaclass} ) { + my $new_class = Mouse::Util::resolve_metaclass_alias( + 'Attribute', + $metaclass_name + ); + if ( $metaclass ne $new_class ) { + $metaclass = $new_class; + } + } + + $metaclass->create($class, $name, %$spec); } } } else { diff --git a/t/047-attribute-metaclass-role.t b/t/047-attribute-metaclass-role.t new file mode 100644 index 0000000..db28fc6 --- /dev/null +++ b/t/047-attribute-metaclass-role.t @@ -0,0 +1,92 @@ +#!/usr/bin/env perl +use strict; +use warnings; +use Test::More tests => 7; +use lib 't/lib'; + +do { + package MouseX::AttributeHelpers::Number; + use Mouse; + extends 'Mouse::Meta::Attribute'; + + around 'create' => sub { + my ($next, @args) = @_; + my $attr = $next->(@args); + my %provides = %{$attr->{provides}}; + my $method_constructors = { + add => sub { + my ($attr, $name) = @_; + return sub { + $_[0]->$name( $_[0]->$name() + $_[1]) + }; + }, + }; + while (my ($name, $aliased) = each %provides) { + $attr->associated_class->add_method( + $aliased => $method_constructors->{$name}->($attr, $attr->name) + ); + } + return $attr; + }; + + package # hide me from search.cpan.org + Mouse::Meta::Attribute::Custom::Number; + sub register_implementation { 'MouseX::AttributeHelpers::Number' } + + 1; + + package Foo; + use Mouse::Role; + + has 'i' => ( + metaclass => 'Number', + is => 'rw', + isa => 'Int', + provides => { + 'add' => 'add_number' + }, + ); + sub f_m {} + + package Bar; + use Mouse::Role; + + has 'j' => ( + metaclass => 'Number', + is => 'rw', + isa => 'Int', + provides => { + 'add' => 'add_number_j' + }, + ); + sub b_m {} + + package Klass1; + use Mouse; + with 'Foo'; + + package Klass2; + use Mouse; + with 'Foo', 'Bar'; + +}; + +{ + # normal + can_ok 'Klass1', 'add_number'; + my $k = Klass1->new(i=>3); + $k->add_number(4); + is $k->i, 7; +} + +{ + # combine + can_ok 'Klass2', 'f_m'; + can_ok 'Klass2', 'b_m'; + can_ok 'Klass2', 'add_number'; + can_ok 'Klass2', 'add_number_j'; + my $k = Klass2->new(i=>3); + $k->add_number(4); + is $k->i, 7; +} +