foo
[gitmo/Moose.git] / lib / Moose / Util.pm
index 904ecd4..d5af0a6 100644 (file)
@@ -1,23 +1,65 @@
 package Moose::Util;
 
-use Exporter qw/import/;
-use Scalar::Util qw/blessed/;
-
 use strict;
 use warnings;
 
-our $VERSION = '0.01';
+use Sub::Exporter;
+use Scalar::Util ();
+use Class::MOP   ();
+
+our $VERSION   = '0.01';
+our $AUTHORITY = 'cpan:STEVAN';
+
+my @exports = qw[
+    find_meta 
+    does_role
+    search_class_by_role   
+];
+
+Sub::Exporter::setup_exporter({
+    exports => \@exports,
+    groups  => { all => \@exports }
+});
+
+## some utils for the utils ...
+
+sub find_meta { 
+    return unless $_[0];
+    return Class::MOP::get_metaclass_by_name(ref($_[0]) || $_[0]);
+}
+
+## the functions ...
 
-our $AUTHORITY = 'cpan:BERLE';
+sub does_role {
+    my ($class_or_obj, $role) = @_;
 
-our @EXPORT_OK = qw/can_role/;
+    my $meta = find_meta($class_or_obj);
+    
+    return unless defined $meta;
 
-sub can_role {
-  my ($class,$does) = @_;
+    return 1 if $meta->does_role($role);
+    return;
+}
+
+sub search_class_by_role {
+    my ($class_or_obj, $role_name) = @_;
+    
+    my $meta = find_meta($class_or_obj);
+
+    return unless defined $meta;
+
+    foreach my $class ($meta->class_precedence_list) {
+        
+        my $_meta = find_meta($class);        
 
-  return ((!ref $class && eval { $class->isa ('UNIVERSAL') }) || Scalar::Util::blessed ($class))
-    && $class->can ('does')
-    && $class->does ($does);
+        next unless defined $_meta;
+
+        foreach my $role (@{ $_meta->roles || [] }) {
+            return $class if $role->name eq $role_name;
+        }
+    }
+
+    return;
 }
 
 1;
@@ -28,25 +70,57 @@ __END__
 
 =head1 NAME
 
-Moose::Util - Moose utilities
+Moose::Util - Utilities for working with Moose classes
 
 =head1 SYNOPSIS
 
-  use Moose::Util qw/can_role/;
+  use Moose::Util qw/find_meta does_role search_class_by_role/;
 
-  if (can_role ($object,'rolename')) {
-    print "The object can do rolename!\n";
+  my $meta = find_meta($object) || die "No metaclass found";
+
+  if (does_role($object, $role)) {
+    print "The object can do $role!\n";
   }
 
-=head1 FUNCTIONS
+  my $class = search_class_by_role($object, 'FooRole');
+  print "Nearest class with 'FooRole' is $class\n";
+
+=head1 DESCRIPTION
+
+This is a set of utility functions to help working with Moose classes. This 
+is an experimental module, and it's not 100% clear what purpose it will serve. 
+That said, ideas, suggestions and contributions to this collection are most 
+welcome. See the L<TODO> section below for a list of ideas for possible 
+functions to write.
+
+=head1 EXPORTED FUNCTIONS
 
 =over 4
 
-=item can_role
+=item B<find_meta ($class_or_obj)>
+
+This will attempt to locate a metaclass for the given C<$class_or_obj>
+and return it.
+
+=item B<does_role ($class_or_obj, $role_name)>
+
+Returns true if C<$class_or_obj> can do the role C<$role_name>.
+
+=item B<search_class_by_role ($class_or_obj, $role_name)>
+
+Returns first class in precedence list that consumed C<$role_name>.
+
+=back
+
+=head1 TODO
+
+Here is a list of possible functions to write
+
+=over 4
 
-  can_role ($object,$rolename);
+=item discovering original method from modified method
 
-Returns true if $object can do the role $rolename.
+=item search for origin class of a method or attribute
 
 =back
 
@@ -60,6 +134,12 @@ to cpan-RT.
 
 Anders Nor Berle E<lt>debolaz@gmail.comE<gt>
 
+B<with contributions from:>
+
+Robert (phaylon) Sedlacek
+
+Stevan Little
+
 =head1 COPYRIGHT AND LICENSE
 
 Copyright 2007 by Infinity Interactive, Inc.