- added Moose::Util::apply_all_roles
Tokuhiro Matsuno [Tue, 2 Dec 2008 04:36:31 +0000 (04:36 +0000)]
- added Moose::Meta::Role->get_method_list
- added Moose::Meta::Class->get_method_list
- copy methods on Moose::Meta::Role->apply

lib/Mouse/Meta/Class.pm
lib/Mouse/Meta/Role.pm
lib/Mouse/Util.pm
t/034-apply_all_roles.t [new file with mode: 0644]

index 661aad0..5cf70e1 100644 (file)
@@ -63,6 +63,20 @@ sub add_method {
     *{ $pkg . '::' . $name } = $code;
 }
 
+# copied from Class::Inspector
+sub get_method_list {
+    my $self = shift;
+    my $name = $self->name;
+
+    no strict 'refs';
+    # Get all the CODE symbol table entries
+    my @functions = grep !/^meta$/,
+      grep { /\A[^\W\d]\w*\z/o }
+      grep { defined &{"${name}::$_"} }
+      keys %{"${name}::"};
+    wantarray ? @functions : \@functions;
+}
+
 sub add_attribute {
     my $self = shift;
     my $attr = shift;
index ebb929f..9037044 100644 (file)
@@ -53,13 +53,41 @@ sub has_attribute { exists $_[0]->{attributes}->{$_[1]}  }
 sub get_attribute_list { keys %{ $_[0]->{attributes} } }
 sub get_attribute { $_[0]->{attributes}->{$_[1]} }
 
+# copied from Class::Inspector
+sub get_method_list {
+    my $self = shift;
+    my $name = $self->name;
+
+    no strict 'refs';
+    # Get all the CODE symbol table entries
+    my @functions = grep !/^meta$/,
+      grep { /\A[^\W\d]\w*\z/o }
+      grep { defined &{"${name}::$_"} }
+      keys %{"${name}::"};
+    wantarray ? @functions : \@functions;
+}
+
 sub apply {
     my $self  = shift;
+    my $selfname = $self->name;
     my $class = shift;
+    my $classname = $class->name;
 
     for my $name (@{$self->{required_methods}}) {
-        unless ($class->name->can($name)) {
-            confess "'@{[ $self->name ]}' requires the method '$name' to be implemented by '@{[ $class->name ]}'";
+        unless ($classname->can($name)) {
+            confess "'$selfname' requires the method '$name' to be implemented by '$classname'";
+        }
+    }
+
+    {
+        no strict 'refs';
+        for my $name ($self->get_method_list) {
+            next if $name eq 'has' || $name eq 'requires' || $name eq 'meta' || $name eq 'with' || $name eq 'around' || $name eq 'before' || $name eq 'after' || $name eq 'blessed' || $name eq 'extends' || $name eq 'confess' || $name eq 'excludes';
+            if ($classname->can($name)) {
+                # XXX what's Moose's behavior?
+                next;
+            }
+            *{"${classname}::${name}"} = *{"${selfname}::${name}"};
         }
     }
 
index a27600b..0c95684 100644 (file)
@@ -223,6 +223,15 @@ BEGIN {
     }
 }
 
+sub apply_all_roles {
+    my $meta = Mouse::Meta::Class->initialize(shift);
+    my $role  = shift;
+    confess "Mouse::Util only supports 'apply_all_roles' on individual roles at a time" if @_;
+
+    Mouse::load_class($role);
+    $role->meta->apply($meta);
+}
+
 1;
 
 __END__
diff --git a/t/034-apply_all_roles.t b/t/034-apply_all_roles.t
new file mode 100644 (file)
index 0000000..557cd5d
--- /dev/null
@@ -0,0 +1,34 @@
+#!/usr/bin/env perl
+use strict;
+use warnings;
+use Test::More tests => 4;
+use Mouse::Util ':test';
+
+{
+    package FooRole;
+    use Mouse::Role;
+    sub foo { 'ok1' }
+}
+
+{
+    package BarRole;
+    use Mouse::Role;
+    sub bar { 'ok2' }
+}
+
+{
+    package Baz;
+    use Mouse;
+    no Mouse;
+}
+
+throws_ok { Mouse::Util::apply_all_roles('Baz', 'BarRole', 'FooRole') } qr{Mouse::Util only supports 'apply_all_roles' on individual roles at a time};
+
+Mouse::Util::apply_all_roles('Baz', 'BarRole');
+Mouse::Util::apply_all_roles('Baz', 'FooRole');
+
+my $baz = Baz->new;
+is $baz->foo, 'ok1';
+is $baz->bar, 'ok2';
+is join(",", sort $baz->meta->get_method_list), 'bar,foo';
+