bump version to 1.15
[gitmo/Moose.git] / lib / Moose / Util.pm
CommitLineData
9a641848 1package Moose::Util;
2
9a641848 3use strict;
4use warnings;
5
9ac41ce6 6use Data::OptList;
88e88a7b 7use Params::Util qw( _STRING );
7125b244 8use Sub::Exporter;
d7d8a8c7 9use Scalar::Util 'blessed';
d2782813 10use List::Util qw(first);
11use List::MoreUtils qw(any all);
f5bc97e5 12use Class::MOP 0.60;
9a641848 13
efa728b4 14our $VERSION = '1.15';
e606ae5f 15$VERSION = eval $VERSION;
7125b244 16our $AUTHORITY = 'cpan:STEVAN';
9a641848 17
7125b244 18my @exports = qw[
d03bd989 19 find_meta
6532ca5a 20 does_role
d03bd989 21 search_class_by_role
b099a649 22 ensure_all_roles
d7d8a8c7 23 apply_all_roles
d26f5671 24 with_traits
ab76842e 25 get_all_init_args
26 get_all_attribute_values
a5e883ae 27 resolve_metatrait_alias
28 resolve_metaclass_alias
5f71050b 29 add_method_modifier
d939e016 30 english_list
27f2f43f 31 meta_attribute_alias
32 meta_class_alias
7125b244 33];
9a641848 34
7125b244 35Sub::Exporter::setup_exporter({
36 exports => \@exports,
11065d1f 37 groups => { all => \@exports }
7125b244 38});
39
40## some utils for the utils ...
41
56ea1a11 42sub find_meta { Class::MOP::class_of(@_) }
9a641848 43
7125b244 44## the functions ...
adf82331 45
7125b244 46sub does_role {
47 my ($class_or_obj, $role) = @_;
adf82331 48
6532ca5a 49 my $meta = find_meta($class_or_obj);
d03bd989 50
7125b244 51 return unless defined $meta;
10a745f5 52 return unless $meta->can('does_role');
7125b244 53 return 1 if $meta->does_role($role);
54 return;
9a641848 55}
56
1631b53f 57sub search_class_by_role {
560c498d 58 my ($class_or_obj, $role) = @_;
d03bd989 59
6532ca5a 60 my $meta = find_meta($class_or_obj);
7125b244 61
62 return unless defined $meta;
63
560c498d 64 my $role_name = blessed $role ? $role->name : $role;
65
7125b244 66 foreach my $class ($meta->class_precedence_list) {
d03bd989 67
68 my $_meta = find_meta($class);
1631b53f 69
7125b244 70 next unless defined $_meta;
71
72 foreach my $role (@{ $_meta->roles || [] }) {
1631b53f 73 return $class if $role->name eq $role_name;
74 }
75 }
76
7125b244 77 return;
1631b53f 78}
79
b099a649 80# this can possibly behave in unexpected ways because the roles being composed
81# before being applied could differ from call to call; I'm not sure if or how
82# to document this possible quirk.
83sub ensure_all_roles {
84 my $applicant = shift;
85 _apply_all_roles($applicant, sub { !does_role($applicant, $_) }, @_);
86}
87
d7d8a8c7 88sub apply_all_roles {
89 my $applicant = shift;
8d4d1cdc 90 _apply_all_roles($applicant, undef, @_);
b099a649 91}
92
93sub _apply_all_roles {
94 my $applicant = shift;
95 my $role_filter = shift;
e606ae5f 96
70ea9161 97 unless (@_) {
98 require Moose;
99 Moose->throw_error("Must specify at least one role to apply to $applicant");
100 }
e606ae5f 101
102 my $roles = Data::OptList::mkopt( [@_] );
103
560c498d 104 my @role_metas;
70ea9161 105 foreach my $role (@$roles) {
560c498d 106 my $meta;
107
108 if ( blessed $role->[0] ) {
109 $meta = $role->[0];
110 }
111 else {
2e7f6cf4 112 Class::MOP::load_class( $role->[0] , $role->[1] );
560c498d 113 $meta = Class::MOP::class_of( $role->[0] );
114 }
70ea9161 115
c8d9f1e2 116 unless ($meta && $meta->isa('Moose::Meta::Role') ) {
70ea9161 117 require Moose;
118 Moose->throw_error( "You can only consume roles, "
119 . $role->[0]
120 . " is not a Moose role" );
121 }
560c498d 122
123 push @role_metas, [ $meta, $role->[1] ];
70ea9161 124 }
e606ae5f 125
82a24871 126 if ( defined $role_filter ) {
560c498d 127 @role_metas = grep { local $_ = $_->[0]; $role_filter->() } @role_metas;
8d4d1cdc 128 }
b099a649 129
560c498d 130 return unless @role_metas;
b099a649 131
6fab0b75 132 my $meta = ( blessed $applicant ? $applicant : find_meta($applicant) );
133
560c498d 134 if ( scalar @role_metas == 1 ) {
135 my ( $role, $params ) = @{ $role_metas[0] };
136 $role->apply( $meta, ( defined $params ? %$params : () ) );
d7d8a8c7 137 }
138 else {
560c498d 139 Moose::Meta::Role->combine(@role_metas)->apply($meta);
e606ae5f 140 }
d7d8a8c7 141}
142
d26f5671 143sub with_traits {
144 my ($class, @roles) = @_;
145 return $class unless @roles;
146 return Moose::Meta::Class->create_anon_class(
147 superclasses => [$class],
148 roles => \@roles,
149 cache => 1,
150 )->name;
151}
152
ab76842e 153# instance deconstruction ...
154
155sub get_all_attribute_values {
156 my ($class, $instance) = @_;
157 return +{
158 map { $_->name => $_->get_value($instance) }
159 grep { $_->has_value($instance) }
b2df9268 160 $class->get_all_attributes
ab76842e 161 };
162}
163
164sub get_all_init_args {
165 my ($class, $instance) = @_;
166 return +{
167 map { $_->init_arg => $_->get_value($instance) }
168 grep { $_->has_value($instance) }
d03bd989 169 grep { defined($_->init_arg) }
b2df9268 170 $class->get_all_attributes
ab76842e 171 };
172}
173
50fbbf3d 174sub resolve_metatrait_alias {
50fbbf3d 175 return resolve_metaclass_alias( @_, trait => 1 );
a3738e5b 176}
177
27f2f43f 178sub _build_alias_package_name {
179 my ($type, $name, $trait) = @_;
180 return 'Moose::Meta::'
181 . $type
182 . '::Custom::'
183 . ( $trait ? 'Trait::' : '' )
184 . $name;
185}
186
50fbbf3d 187{
188 my %cache;
a3738e5b 189
50fbbf3d 190 sub resolve_metaclass_alias {
191 my ( $type, $metaclass_name, %options ) = @_;
a3738e5b 192
50fbbf3d 193 my $cache_key = $type . q{ } . ( $options{trait} ? '-Trait' : '' );
194 return $cache{$cache_key}{$metaclass_name}
195 if $cache{$cache_key}{$metaclass_name};
196
27f2f43f 197 my $possible_full_name = _build_alias_package_name(
198 $type, $metaclass_name, $options{trait}
199 );
50fbbf3d 200
201 my $loaded_class = Class::MOP::load_first_existing_class(
202 $possible_full_name,
203 $metaclass_name
204 );
205
206 return $cache{$cache_key}{$metaclass_name}
207 = $loaded_class->can('register_implementation')
208 ? $loaded_class->register_implementation
209 : $loaded_class;
210 }
a3738e5b 211}
212
5f71050b 213sub add_method_modifier {
214 my ( $class_or_obj, $modifier_name, $args ) = @_;
d5447d26 215 my $meta
216 = $class_or_obj->can('add_before_method_modifier')
217 ? $class_or_obj
218 : find_meta($class_or_obj);
5f71050b 219 my $code = pop @{$args};
220 my $add_modifier_method = 'add_' . $modifier_name . '_method_modifier';
221 if ( my $method_modifier_type = ref( @{$args}[0] ) ) {
222 if ( $method_modifier_type eq 'Regexp' ) {
e606ae5f 223 my @all_methods = $meta->get_all_methods;
5f71050b 224 my @matched_methods
e606ae5f 225 = grep { $_->name =~ @{$args}[0] } @all_methods;
226 $meta->$add_modifier_method( $_->name, $code )
5f71050b 227 for @matched_methods;
228 }
775666aa 229 elsif ($method_modifier_type eq 'ARRAY') {
230 $meta->$add_modifier_method( $_, $code ) for @{$args->[0]};
231 }
232 else {
233 $meta->throw_error(
234 sprintf(
235 "Methods passed to %s must be provided as a list, arrayref or regex, not %s",
236 $modifier_name,
237 $method_modifier_type,
238 )
239 );
240 }
5f71050b 241 }
242 else {
243 $meta->$add_modifier_method( $_, $code ) for @{$args};
244 }
245}
d9bb6c63 246
d939e016 247sub english_list {
248 my @items = sort @_;
249
250 return $items[0] if @items == 1;
251 return "$items[0] and $items[1]" if @items == 2;
252
253 my $tail = pop @items;
254 my $list = join ', ', @items;
255 $list .= ', and ' . $tail;
256
257 return $list;
258}
259
833b56a7 260sub _caller_info {
261 my $level = @_ ? ($_[0] + 1) : 2;
262 my %info;
263 @info{qw(package file line)} = caller($level);
264 return \%info;
265}
266
27f2f43f 267sub _create_alias {
268 my ($type, $name, $trait, $for) = @_;
269 my $package = _build_alias_package_name($type, $name, $trait);
270 Class::MOP::Class->initialize($package)->add_method(
271 register_implementation => sub { $for }
272 );
273}
274
275sub meta_attribute_alias {
276 my ($to, $from) = @_;
277 $from ||= caller;
278 my $meta = Class::MOP::class_of($from);
279 my $trait = $meta->isa('Moose::Meta::Role');
280 _create_alias('Attribute', $to, $trait, $from);
281}
282
283sub meta_class_alias {
284 my ($to, $from) = @_;
285 $from ||= caller;
286 my $meta = Class::MOP::class_of($from);
287 my $trait = $meta->isa('Moose::Meta::Role');
288 _create_alias('Class', $to, $trait, $from);
289}
290
88e88a7b 291# XXX - this should be added to Params::Util
292sub _STRINGLIKE ($) {
293 return _STRING( $_[0] )
294 || ( blessed $_[0]
295 && overload::Method( $_[0], q{""} )
296 && length "$_[0]" );
297}
298
61907a02 299sub _reconcile_roles_for_metaclass {
300 my ($class_meta_name, $super_meta_name) = @_;
301
302 my @role_differences = _role_differences(
303 $class_meta_name, $super_meta_name,
304 );
305
306 # handle the case where we need to fix compatibility between a class and
307 # its parent, but all roles in the class are already also done by the
308 # parent
309 # see t/050/054.t
310 return $super_meta_name
311 unless @role_differences;
312
313 return Moose::Meta::Class->create_anon_class(
314 superclasses => [$super_meta_name],
315 roles => [map { $_->name } @role_differences],
316 cache => 1,
317 )->name;
318}
319
320sub _role_differences {
321 my ($class_meta_name, $super_meta_name) = @_;
322 my @super_role_metas = $super_meta_name->meta->can('calculate_all_roles_with_inheritance')
323 ? $super_meta_name->meta->calculate_all_roles_with_inheritance
cfa43121 324 : $super_meta_name->meta->can('calculate_all_roles')
325 ? $super_meta_name->meta->calculate_all_roles
61907a02 326 : ();
327 my @role_metas = $class_meta_name->meta->can('calculate_all_roles_with_inheritance')
328 ? $class_meta_name->meta->calculate_all_roles_with_inheritance
cfa43121 329 : $class_meta_name->meta->can('calculate_all_roles')
330 ? $class_meta_name->meta->calculate_all_roles
61907a02 331 : ();
332 my @differences;
333 for my $role_meta (@role_metas) {
334 push @differences, $role_meta
335 unless any { $_->name eq $role_meta->name } @super_role_metas;
336 }
337 return @differences;
338}
339
d2782813 340sub _classes_differ_by_roles_only {
341 my ( $self_meta_name, $super_meta_name ) = @_;
342
343 my $common_base_name
344 = _find_common_base( $self_meta_name, $super_meta_name );
345
346 return unless defined $common_base_name;
347
348 my @super_meta_name_ancestor_names
349 = _get_ancestors_until( $super_meta_name, $common_base_name );
350 my @class_meta_name_ancestor_names
351 = _get_ancestors_until( $self_meta_name, $common_base_name );
352
353 return
354 unless all { _is_role_only_subclass($_) }
355 @super_meta_name_ancestor_names,
356 @class_meta_name_ancestor_names;
357
358 return 1;
359}
360
361sub _find_common_base {
362 my ($meta1, $meta2) = map { Class::MOP::class_of($_) } @_;
363 return unless defined $meta1 && defined $meta2;
364
365 # FIXME? This doesn't account for multiple inheritance (not sure
366 # if it needs to though). For example, if somewhere in $meta1's
367 # history it inherits from both ClassA and ClassB, and $meta2
368 # inherits from ClassB & ClassA, does it matter? And what crazy
369 # fool would do that anyway?
370
371 my %meta1_parents = map { $_ => 1 } $meta1->linearized_isa;
372
373 return first { $meta1_parents{$_} } $meta2->linearized_isa;
374}
375
376sub _get_ancestors_until {
377 my ($start_name, $until_name) = @_;
378
379 my @ancestor_names;
380 for my $ancestor_name (Class::MOP::class_of($start_name)->linearized_isa) {
381 last if $ancestor_name eq $until_name;
382 push @ancestor_names, $ancestor_name;
383 }
384 return @ancestor_names;
385}
386
387sub _is_role_only_subclass {
388 my ($meta_name) = @_;
389 my $meta = Class::MOP::Class->initialize($meta_name);
390 my @parent_names = $meta->superclasses;
391
392 # XXX: don't feel like messing with multiple inheritance here... what would
393 # that even do?
394 return unless @parent_names == 1;
395 my ($parent_name) = @parent_names;
396 my $parent_meta = Class::MOP::Class->initialize($parent_name);
397
398 # only get the roles attached to this particular class, don't look at
399 # superclasses
400 my @roles = $meta->can('calculate_all_roles')
401 ? $meta->calculate_all_roles
402 : ();
403
404 # it's obviously not a role-only subclass if it doesn't do any roles
405 return unless @roles;
406
407 # loop over all methods that are a part of the current class
408 # (not inherited)
409 for my $method ( $meta->_get_local_methods ) {
410 # always ignore meta
ba7d613d 411 next if $method->isa('Class::MOP::Method::Meta');
d2782813 412 # we'll deal with attributes below
413 next if $method->can('associated_attribute');
414 # if the method comes from a role we consumed, ignore it
415 next if $meta->can('does_role')
416 && $meta->does_role($method->original_package_name);
417 # FIXME - this really isn't right. Just because a modifier is
418 # defined in a role doesn't mean it isn't _also_ defined in the
419 # subclass.
420 next if $method->isa('Class::MOP::Method::Wrapped')
421 && (
422 (!scalar($method->around_modifiers)
423 || any { $_->has_around_method_modifiers($method->name) } @roles)
424 && (!scalar($method->before_modifiers)
425 || any { $_->has_before_method_modifiers($method->name) } @roles)
426 && (!scalar($method->after_modifiers)
427 || any { $_->has_after_method_modifiers($method->name) } @roles)
428 );
429
430 return 0;
431 }
432
433 # loop over all attributes that are a part of the current class
434 # (not inherited)
435 # FIXME - this really isn't right. Just because an attribute is
436 # defined in a role doesn't mean it isn't _also_ defined in the
437 # subclass.
438 for my $attr (map { $meta->get_attribute($_) } $meta->get_attribute_list) {
439 next if any { $_->has_attribute($attr->name) } @roles;
440
441 return 0;
442 }
443
444 return 1;
445}
446
9a641848 4471;
448
449__END__
450
451=pod
452
453=head1 NAME
454
7125b244 455Moose::Util - Utilities for working with Moose classes
9a641848 456
457=head1 SYNOPSIS
458
6532ca5a 459 use Moose::Util qw/find_meta does_role search_class_by_role/;
460
461 my $meta = find_meta($object) || die "No metaclass found";
9a641848 462
adf82331 463 if (does_role($object, $role)) {
464 print "The object can do $role!\n";
9a641848 465 }
466
1631b53f 467 my $class = search_class_by_role($object, 'FooRole');
468 print "Nearest class with 'FooRole' is $class\n";
469
7125b244 470=head1 DESCRIPTION
471
2c3bf4e7 472This module provides a set of utility functions. Many of these
473functions are intended for use in Moose itself or MooseX modules, but
474some of them may be useful for use in your own code.
7125b244 475
476=head1 EXPORTED FUNCTIONS
9a641848 477
478=over 4
479
2c3bf4e7 480=item B<find_meta($class_or_obj)>
481
482This method takes a class name or object and attempts to find a
3ff98e47 483metaclass for the class, if one exists. It will B<not> create one if it
2c3bf4e7 484does not yet exist.
485
560c498d 486=item B<does_role($class_or_obj, $role_or_obj)>
2c3bf4e7 487
560c498d 488Returns true if C<$class_or_obj> does the given C<$role_or_obj>. The role can
489be provided as a name or a L<Moose::Meta::Role> object.
6532ca5a 490
560c498d 491The class must already have a metaclass for this to work. If it doesn't, this
492function simply returns false.
6532ca5a 493
560c498d 494=item B<search_class_by_role($class_or_obj, $role_or_obj)>
7125b244 495
2c3bf4e7 496Returns the first class in the class's precedence list that does
560c498d 497C<$role_or_obj>, if any. The role can be either a name or a
498L<Moose::Meta::Role> object.
7125b244 499
2c3bf4e7 500The class must already have a metaclass for this to work.
7125b244 501
2c3bf4e7 502=item B<apply_all_roles($applicant, @roles)>
7125b244 503
2c3bf4e7 504This function applies one or more roles to the given C<$applicant> The
505applicant can be a role name, class name, or object.
d7d8a8c7 506
2c3bf4e7 507The C<$applicant> must already have a metaclass object.
508
560c498d 509The list of C<@roles> should a list of names or L<Moose::Meta::Role> objects,
510each of which can be followed by an optional hash reference of options
511(C<-excludes> and C<-alias>).
d7d8a8c7 512
b099a649 513=item B<ensure_all_roles($applicant, @roles)>
514
515This function is similar to L</apply_all_roles>, but only applies roles that
516C<$applicant> does not already consume.
517
d26f5671 518=item B<with_traits($class_name, @role_names)>
519
520This function creates a new class from C<$class_name> with each of
521C<@role_names> applied. It returns the name of the new class.
522
ab76842e 523=item B<get_all_attribute_values($meta, $instance)>
524
2c3bf4e7 525Returns a hash reference containing all of the C<$instance>'s
526attributes. The keys are attribute names.
ab76842e 527
528=item B<get_all_init_args($meta, $instance)>
529
2c3bf4e7 530Returns a hash reference containing all of the C<init_arg> values for
531the instance's attributes. The values are the associated attribute
532values. If an attribute does not have a defined C<init_arg>, it is
533skipped.
534
535This could be useful in cloning an object.
ab76842e 536
a3738e5b 537=item B<resolve_metaclass_alias($category, $name, %options)>
538
539=item B<resolve_metatrait_alias($category, $name, %options)>
540
2c3bf4e7 541Resolves a short name to a full class name. Short names are often used
542when specifying the C<metaclass> or C<traits> option for an attribute:
a3738e5b 543
544 has foo => (
545 metaclass => "Bar",
546 );
547
8a8856de 548The name resolution mechanism is covered in
549L<Moose/Metaclass and Trait Name Resolution>.
5f71050b 550
27f2f43f 551=item B<meta_class_alias($to[, $from])>
552
553=item B<meta_attribute_alias($to[, $from])>
554
555Create an alias from the class C<$from> (or the current package, if
556C<$from> is unspecified), so that
557L<Moose/Metaclass and Trait Name Resolution> works properly.
558
57385c0d 559=item B<english_list(@items)>
560
561Given a list of scalars, turns them into a proper list in English
562("one and two", "one, two, three, and four"). This is used to help us
563make nicer error messages.
564
7125b244 565=back
9a641848 566
7125b244 567=head1 TODO
9a641848 568
7125b244 569Here is a list of possible functions to write
9a641848 570
7125b244 571=over 4
1631b53f 572
7125b244 573=item discovering original method from modified method
1631b53f 574
7125b244 575=item search for origin class of a method or attribute
1631b53f 576
9a641848 577=back
578
579=head1 BUGS
580
d4048ef3 581See L<Moose/BUGS> for details on reporting bugs.
9a641848 582
583=head1 AUTHOR
584
585Anders Nor Berle E<lt>debolaz@gmail.comE<gt>
586
7125b244 587B<with contributions from:>
588
589Robert (phaylon) Sedlacek
590
591Stevan Little
592
9a641848 593=head1 COPYRIGHT AND LICENSE
594
2840a3b2 595Copyright 2007-2009 by Infinity Interactive, Inc.
9a641848 596
597L<http://www.iinteractive.com>
598
599This library is free software; you can redistribute it and/or modify
b60c9fa0 600it under the same terms as Perl itself.
9a641848 601
602=cut
603