implementations for DOES and around does => sub {...}
Toby Inkster [Fri, 19 Oct 2012 13:52:44 +0000 (14:52 +0100)]
Changes
lib/Role/Tiny.pm

diff --git a/Changes b/Changes
index 713988d..9dd6188 100644 (file)
--- a/Changes
+++ b/Changes
@@ -1,5 +1,7 @@
   - load class in addition to roles when using create_class_from_roles
   - fix module name in Makefile.PL (RT#78591)
+  - when classes consume roles, override their DOES method (RT#79747)
+  - method modifiers can be used for 'does' and 'DOES'
 
 1.001005 - 2012-07-18
   - localize UNIVERSAL::can change to avoid confusing TB2
index 609f4a6..07ea94a 100644 (file)
@@ -86,11 +86,6 @@ sub apply_single_role_to_package {
 
   $me->_install_modifiers($to, $info->{modifiers});
 
-  # only add does() method to classes and only if they don't have one
-  if (not $INFO{$to} and not $to->can('does')) {
-    *{_getglob "${to}::does"} = \&does_role;
-  }
-
   # copy our role list into the target's
   @{$APPLIED_TO{$to}||={}}{keys %{$APPLIED_TO{$role}}} = ();
 }
@@ -157,8 +152,6 @@ sub create_class_with_roles {
     do { my %h; @h{map @{$_->{requires}||[]}, @info} = (); keys %h }
   );
 
-  *{_getglob "${new_name}::does"} = \&does_role unless $new_name->can('does');
-
   @{$APPLIED_TO{$new_name}||={}}{
     map keys %{$APPLIED_TO{$_}}, @roles
   } = ();
@@ -298,6 +291,8 @@ sub _install_methods {
     no warnings 'once';
     *{_getglob "${to}::${i}"} = $methods->{$i};
   }
+  
+  $me->_install_does($to);
 }
 
 sub _install_modifiers {
@@ -316,6 +311,27 @@ sub _install_single_modifier {
   Class::Method::Modifiers::install_modifier(@args);
 }
 
+my $FALLBACK = sub { 0 };
+sub _install_does {
+  my ($me, $to) = @_;
+  
+  # only add does() method to classes
+  return if $INFO{$to};
+  
+  # add does() only if they don't have one
+  *{_getglob "${to}::does"} = \&does_role unless $to->can('does');
+  
+  return if ($to->can('DOES') and $to->can('DOES') != UNIVERSAL->can('DOES'));
+  
+  my $existing = $to->can('DOES') || $to->can('isa') || $FALLBACK;
+  my $new_sub = sub {
+    my ($proto, $role) = @_;
+    Role::Tiny::does_role($proto, $role) or $proto->$existing($role);
+  };
+  no warnings 'redefine';
+  *{_getglob "${to}::DOES"} = $new_sub;
+}
+
 sub does_role {
   my ($proto, $role) = @_;
   if ($] >= 5.010) {
@@ -474,7 +490,11 @@ composed into unless that class already has an ->does method, so
     ...
   }
 
-will work for classes but to test a role, one must use ::does_role directly
+will work for classes but to test a role, one must use ::does_role directly.
+
+Additionally, Role::Tiny will override the standard Perl C<DOES> method
+for your class. However, if C<any> class in your class' inheritance
+heirarchy provides C<DOES>, then Role::Tiny will not override it.
 
 =head1 METHODS
 
@@ -540,6 +560,8 @@ Mithaldu - Christian Walde (cpan:MITHALDU) <walde.christian@googlemail.com>
 
 ilmari - Dagfinn Ilmari MannsÃ¥ker (cpan:ILMARI) <ilmari@ilmari.org>
 
+tobyink - Toby Inkster (cpan:TOBYINK) <tobyink@cpan.org>
+
 =head1 COPYRIGHT
 
 Copyright (c) 2010-2012 the Role::Tiny L</AUTHOR> and L</CONTRIBUTORS>