be more verbose in the required method error (RT#60583)
Jesse Luehrs [Sat, 17 Sep 2011 20:01:09 +0000 (15:01 -0500)]
Changes
lib/Moose/Meta/Role/Application/ToClass.pm
t/roles/imported_required_method.t [new file with mode: 0644]

diff --git a/Changes b/Changes
index d5a6d53..5069373 100644 (file)
--- a/Changes
+++ b/Changes
@@ -39,11 +39,9 @@ for, noteworthy changes.
     this will no longer throw an error. Reported by Mark-Jason Dominus. Fixes
     RT 69988. (Dave Rolsky)
 
-  [BUG FIXES]
-
-  * A subtype of a union type did not return the right results when you called
-    ->is_subtype_of or ->is_a_type_of on it. This has been fixed. RT
-    #70322. (Dave Rolsky)
+  * The error generated by unfulfilled method requirements during role
+    composition now mentions how to work around imported methods not being
+    recognized. Reported by Michael Schwern. Fixes RT 60583. (doy)
 
   [OTHER]
 
index 704310b..822d1e5 100644 (file)
@@ -4,6 +4,7 @@ use strict;
 use warnings;
 use metaclass;
 
+use List::MoreUtils 'firstval';
 use Moose::Util  'english_list';
 use Scalar::Util 'weaken', 'blessed';
 
@@ -116,6 +117,12 @@ sub check_required_methods {
             . "' requires the $noun $list "
             . "to be implemented by '"
             . $class->name . q{'};
+
+        if (my $meth = firstval { $class->name->can($_) } @missing) {
+            $error .= ". If you imported functions intending to use them as "
+                    . "methods, you need to explicitly mark them as such, via "
+                    . $class->name . "->meta->add_method($meth => \\\&$meth)";
+        }
     }
 
     $class->throw_error($error);
diff --git a/t/roles/imported_required_method.t b/t/roles/imported_required_method.t
new file mode 100644 (file)
index 0000000..ce44640
--- /dev/null
@@ -0,0 +1,56 @@
+#!/usr/bin/env perl
+use strict;
+use warnings;
+use Test::More;
+use Test::Fatal;
+use Test::Moose;
+
+BEGIN {
+    package ExportsFoo;
+    use Sub::Exporter -setup => {
+        exports => ['foo'],
+    };
+
+    sub foo { 'FOO' }
+
+    $INC{'ExportsFoo.pm'} = 1;
+}
+
+{
+    package Foo;
+    use Moose::Role;
+    requires 'foo';
+}
+
+{
+    package Bar;
+    use Moose::Role;
+    requires 'bar';
+}
+
+{
+    package Class;
+    use Moose;
+    use ExportsFoo 'foo';
+    ::like(
+        ::exception { with 'Foo' },
+        qr/^\Q'Foo' requires the method 'foo' to be implemented by 'Class'. If you imported functions intending to use them as methods, you need to explicitly mark them as such, via Class->meta->add_method(foo => \&foo)/,
+        "imported 'method' isn't seen"
+    );
+    Class->meta->add_method(foo => \&foo);
+    ::is(
+        ::exception { with 'Foo' },
+        undef,
+        "now it's a method"
+    );
+
+    ::like(
+        ::exception { with 'Bar' },
+        qr/^\Q'Bar' requires the method 'bar' to be implemented by 'Class' at/,
+        "requirement isn't imported, so don't give the extra info in the error"
+    );
+}
+
+does_ok('Class', 'Foo');
+
+done_testing;