bump version and update Changes for release
[gitmo/Moose.git] / lib / Moose / Util.pm
index b8c5f0f..a617093 100644 (file)
@@ -5,10 +5,10 @@ use warnings;
 
 use Sub::Exporter;
 use Scalar::Util 'blessed';
-use Carp         'confess';
-use Class::MOP   ();
+use Class::MOP   0.60;
 
-our $VERSION   = '0.05';
+our $VERSION   = '0.72';
+$VERSION = eval $VERSION;
 our $AUTHORITY = 'cpan:STEVAN';
 
 my @exports = qw[
@@ -20,6 +20,8 @@ my @exports = qw[
     get_all_attribute_values
     resolve_metatrait_alias
     resolve_metaclass_alias
+    add_method_modifier
+    english_list
 ];
 
 Sub::Exporter::setup_exporter({
@@ -70,33 +72,38 @@ sub search_class_by_role {
 
 sub apply_all_roles {
     my $applicant = shift;
-    
-    confess "Must specify at least one role to apply to $applicant" unless @_;
-    
-    my $roles = Data::OptList::mkopt([ @_ ]);
-    
-    #use Data::Dumper;
-    #warn Dumper $roles;
-    
-    my $meta = (blessed $applicant ? $applicant : find_meta($applicant));
-    
+
+    unless (@_) {
+        require Moose;
+        Moose->throw_error("Must specify at least one role to apply to $applicant");
+    }
+
+    my $roles = Data::OptList::mkopt( [@_] );
+
+    my $meta = ( blessed $applicant ? $applicant : find_meta($applicant) );
+
     foreach my $role_spec (@$roles) {
-        Class::MOP::load_class($role_spec->[0]);
+        Class::MOP::load_class( $role_spec->[0] );
     }
-    
-    ($_->[0]->can('meta') && $_->[0]->meta->isa('Moose::Meta::Role'))
-        || confess "You can only consume roles, " . $_->[0] . " is not a Moose role"
-            foreach @$roles;
 
-    if (scalar @$roles == 1) {
-        my ($role, $params) = @{$roles->[0]};
-        $role->meta->apply($meta, (defined $params ? %$params : ()));
+    foreach my $role (@$roles) {
+        unless ( $role->[0]->can('meta')
+            && $role->[0]->meta->isa('Moose::Meta::Role') ) {
+
+            require Moose;
+            Moose->throw_error( "You can only consume roles, "
+                    . $role->[0]
+                    . " is not a Moose role" );
+        }
+    }
+
+    if ( scalar @$roles == 1 ) {
+        my ( $role, $params ) = @{ $roles->[0] };
+        $role->meta->apply( $meta, ( defined $params ? %$params : () ) );
     }
     else {
-        Moose::Meta::Role->combine(
-            @$roles
-        )->apply($meta);
-    }    
+        Moose::Meta::Role->combine( @$roles )->apply($meta);
+    }
 }
 
 # instance deconstruction ...
@@ -121,28 +128,69 @@ sub get_all_init_args {
 }
 
 sub resolve_metatrait_alias {
-    resolve_metaclass_alias( @_, trait => 1 );
+    return resolve_metaclass_alias( @_, trait => 1 );
 }
 
-sub resolve_metaclass_alias {
-    my ( $type, $metaclass_name, %options ) = @_;
+{
+    my %cache;
 
-    if ( my $resolved = eval {
-        my $possible_full_name = 'Moose::Meta::' . $type . '::Custom::' . ( $options{trait} ? "Trait::" : "" ) . $metaclass_name;
+    sub resolve_metaclass_alias {
+        my ( $type, $metaclass_name, %options ) = @_;
 
-        Class::MOP::load_class($possible_full_name);
+        my $cache_key = $type . q{ } . ( $options{trait} ? '-Trait' : '' );
+        return $cache{$cache_key}{$metaclass_name}
+            if $cache{$cache_key}{$metaclass_name};
 
-        $possible_full_name->can('register_implementation')
-            ? $possible_full_name->register_implementation
-            : $possible_full_name;
-    } ) {
-        return $resolved;
-    } else {
-        Class::MOP::load_class($metaclass_name);
-        return $metaclass_name;
+        my $possible_full_name
+            = 'Moose::Meta::' 
+            . $type
+            . '::Custom::'
+            . ( $options{trait} ? "Trait::" : "" )
+            . $metaclass_name;
+
+        my $loaded_class = Class::MOP::load_first_existing_class(
+            $possible_full_name,
+            $metaclass_name
+        );
+
+        return $cache{$cache_key}{$metaclass_name}
+            = $loaded_class->can('register_implementation')
+            ? $loaded_class->register_implementation
+            : $loaded_class;
+    }
+}
+
+sub add_method_modifier {
+    my ( $class_or_obj, $modifier_name, $args ) = @_;
+    my $meta                = find_meta($class_or_obj);
+    my $code                = pop @{$args};
+    my $add_modifier_method = 'add_' . $modifier_name . '_method_modifier';
+    if ( my $method_modifier_type = ref( @{$args}[0] ) ) {
+        if ( $method_modifier_type eq 'Regexp' ) {
+            my @all_methods = $meta->get_all_methods;
+            my @matched_methods
+                = grep { $_->name =~ @{$args}[0] } @all_methods;
+            $meta->$add_modifier_method( $_->name, $code )
+                for @matched_methods;
+        }
+    }
+    else {
+        $meta->$add_modifier_method( $_, $code ) for @{$args};
     }
 }
 
+sub english_list {
+    my @items = sort @_;
+
+    return $items[0] if @items == 1;
+    return "$items[0] and $items[1]" if @items == 2;
+
+    my $tail = pop @items;
+    my $list = join ', ', @items;
+    $list .= ', and ' . $tail;
+
+    return $list;
+}
 
 1;
 
@@ -173,7 +221,7 @@ This is a set of utility functions to help working with Moose classes, and
 is used internally by Moose itself. The goal is to provide useful functions
 that for both Moose users and Moose extenders (MooseX:: authors).
 
-This is a relatively new addition to the Moose toolchest, so ideas, 
+This is a relatively new addition to the Moose tool chest, so 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.
@@ -201,7 +249,7 @@ Given an C<$applicant> (which can somehow be turned into either a
 metaclass or a metarole) and a list of C<@roles> this will do the 
 right thing to apply the C<@roles> to the C<$applicant>. This is 
 actually used internally by both L<Moose> and L<Moose::Role>, and the
-C<@roles> will be pre-processed through L<Data::OptList::mkopt>
+C<@roles> will be preprocessed through L<Data::OptList::mkopt>
 to allow for the additional arguments to be passed. 
 
 =item B<get_all_attribute_values($meta, $instance)>
@@ -226,6 +274,14 @@ Resolve a short name like in e.g.
 
 to a full class name.
 
+=item B<add_method_modifier ($class_or_obj, $modifier_name, $args)>
+
+=item B<english_list(@items)>
+
+Given a list of scalars, turns them into a proper list in English
+("one and two", "one, two, three, and four"). This is used to help us
+make nicer error messages.
+
 =back
 
 =head1 TODO
@@ -258,7 +314,7 @@ Stevan Little
 
 =head1 COPYRIGHT AND LICENSE
 
-Copyright 2007-2008 by Infinity Interactive, Inc.
+Copyright 2007-2009 by Infinity Interactive, Inc.
 
 L<http://www.iinteractive.com>