8 use Scalar::Util 'blessed';
11 our $VERSION = '1.02';
12 $VERSION = eval $VERSION;
13 our $AUTHORITY = 'cpan:STEVAN';
22 get_all_attribute_values
23 resolve_metatrait_alias
24 resolve_metaclass_alias
31 Sub::Exporter::setup_exporter({
33 groups => { all => \@exports }
36 ## some utils for the utils ...
38 sub find_meta { Class::MOP::class_of(@_) }
43 my ($class_or_obj, $role) = @_;
45 my $meta = find_meta($class_or_obj);
47 return unless defined $meta;
48 return unless $meta->can('does_role');
49 return 1 if $meta->does_role($role);
53 sub search_class_by_role {
54 my ($class_or_obj, $role) = @_;
56 my $meta = find_meta($class_or_obj);
58 return unless defined $meta;
60 my $role_name = blessed $role ? $role->name : $role;
62 foreach my $class ($meta->class_precedence_list) {
64 my $_meta = find_meta($class);
66 next unless defined $_meta;
68 foreach my $role (@{ $_meta->roles || [] }) {
69 return $class if $role->name eq $role_name;
76 # this can possibly behave in unexpected ways because the roles being composed
77 # before being applied could differ from call to call; I'm not sure if or how
78 # to document this possible quirk.
79 sub ensure_all_roles {
80 my $applicant = shift;
81 _apply_all_roles($applicant, sub { !does_role($applicant, $_) }, @_);
85 my $applicant = shift;
86 _apply_all_roles($applicant, undef, @_);
89 sub _apply_all_roles {
90 my $applicant = shift;
91 my $role_filter = shift;
95 Moose->throw_error("Must specify at least one role to apply to $applicant");
98 my $roles = Data::OptList::mkopt( [@_] );
101 foreach my $role (@$roles) {
104 if ( blessed $role->[0] ) {
108 Class::MOP::load_class( $role->[0] , $role->[1] );
109 $meta = Class::MOP::class_of( $role->[0] );
112 unless ($meta && $meta->isa('Moose::Meta::Role') ) {
114 Moose->throw_error( "You can only consume roles, "
116 . " is not a Moose role" );
119 push @role_metas, [ $meta, $role->[1] ];
122 if ( defined $role_filter ) {
123 @role_metas = grep { local $_ = $_->[0]; $role_filter->() } @role_metas;
126 return unless @role_metas;
128 my $meta = ( blessed $applicant ? $applicant : find_meta($applicant) );
130 if ( scalar @role_metas == 1 ) {
131 my ( $role, $params ) = @{ $role_metas[0] };
132 $role->apply( $meta, ( defined $params ? %$params : () ) );
135 Moose::Meta::Role->combine(@role_metas)->apply($meta);
139 # instance deconstruction ...
141 sub get_all_attribute_values {
142 my ($class, $instance) = @_;
144 map { $_->name => $_->get_value($instance) }
145 grep { $_->has_value($instance) }
146 $class->get_all_attributes
150 sub get_all_init_args {
151 my ($class, $instance) = @_;
153 map { $_->init_arg => $_->get_value($instance) }
154 grep { $_->has_value($instance) }
155 grep { defined($_->init_arg) }
156 $class->get_all_attributes
160 sub resolve_metatrait_alias {
161 return resolve_metaclass_alias( @_, trait => 1 );
164 sub _build_alias_package_name {
165 my ($type, $name, $trait) = @_;
166 return 'Moose::Meta::'
169 . ( $trait ? 'Trait::' : '' )
176 sub resolve_metaclass_alias {
177 my ( $type, $metaclass_name, %options ) = @_;
179 my $cache_key = $type . q{ } . ( $options{trait} ? '-Trait' : '' );
180 return $cache{$cache_key}{$metaclass_name}
181 if $cache{$cache_key}{$metaclass_name};
183 my $possible_full_name = _build_alias_package_name(
184 $type, $metaclass_name, $options{trait}
187 my $loaded_class = Class::MOP::load_first_existing_class(
192 return $cache{$cache_key}{$metaclass_name}
193 = $loaded_class->can('register_implementation')
194 ? $loaded_class->register_implementation
199 sub add_method_modifier {
200 my ( $class_or_obj, $modifier_name, $args ) = @_;
202 = $class_or_obj->can('add_before_method_modifier')
204 : find_meta($class_or_obj);
205 my $code = pop @{$args};
206 my $add_modifier_method = 'add_' . $modifier_name . '_method_modifier';
207 if ( my $method_modifier_type = ref( @{$args}[0] ) ) {
208 if ( $method_modifier_type eq 'Regexp' ) {
209 my @all_methods = $meta->get_all_methods;
211 = grep { $_->name =~ @{$args}[0] } @all_methods;
212 $meta->$add_modifier_method( $_->name, $code )
213 for @matched_methods;
215 elsif ($method_modifier_type eq 'ARRAY') {
216 $meta->$add_modifier_method( $_, $code ) for @{$args->[0]};
221 "Methods passed to %s must be provided as a list, arrayref or regex, not %s",
223 $method_modifier_type,
229 $meta->$add_modifier_method( $_, $code ) for @{$args};
236 return $items[0] if @items == 1;
237 return "$items[0] and $items[1]" if @items == 2;
239 my $tail = pop @items;
240 my $list = join ', ', @items;
241 $list .= ', and ' . $tail;
247 my $level = @_ ? ($_[0] + 1) : 2;
249 @info{qw(package file line)} = caller($level);
254 my ($type, $name, $trait, $for) = @_;
255 my $package = _build_alias_package_name($type, $name, $trait);
256 Class::MOP::Class->initialize($package)->add_method(
257 register_implementation => sub { $for }
261 sub meta_attribute_alias {
262 my ($to, $from) = @_;
264 my $meta = Class::MOP::class_of($from);
265 my $trait = $meta->isa('Moose::Meta::Role');
266 _create_alias('Attribute', $to, $trait, $from);
269 sub meta_class_alias {
270 my ($to, $from) = @_;
272 my $meta = Class::MOP::class_of($from);
273 my $trait = $meta->isa('Moose::Meta::Role');
274 _create_alias('Class', $to, $trait, $from);
285 Moose::Util - Utilities for working with Moose classes
289 use Moose::Util qw/find_meta does_role search_class_by_role/;
291 my $meta = find_meta($object) || die "No metaclass found";
293 if (does_role($object, $role)) {
294 print "The object can do $role!\n";
297 my $class = search_class_by_role($object, 'FooRole');
298 print "Nearest class with 'FooRole' is $class\n";
302 This module provides a set of utility functions. Many of these
303 functions are intended for use in Moose itself or MooseX modules, but
304 some of them may be useful for use in your own code.
306 =head1 EXPORTED FUNCTIONS
310 =item B<find_meta($class_or_obj)>
312 This method takes a class name or object and attempts to find a
313 metaclass for the class, if one exists. It will B<not> create one if it
316 =item B<does_role($class_or_obj, $role_or_obj)>
318 Returns true if C<$class_or_obj> does the given C<$role_or_obj>. The role can
319 be provided as a name or a L<Moose::Meta::Role> object.
321 The class must already have a metaclass for this to work. If it doesn't, this
322 function simply returns false.
324 =item B<search_class_by_role($class_or_obj, $role_or_obj)>
326 Returns the first class in the class's precedence list that does
327 C<$role_or_obj>, if any. The role can be either a name or a
328 L<Moose::Meta::Role> object.
330 The class must already have a metaclass for this to work.
332 =item B<apply_all_roles($applicant, @roles)>
334 This function applies one or more roles to the given C<$applicant> The
335 applicant can be a role name, class name, or object.
337 The C<$applicant> must already have a metaclass object.
339 The list of C<@roles> should a list of names or L<Moose::Meta::Role> objects,
340 each of which can be followed by an optional hash reference of options
341 (C<-excludes> and C<-alias>).
343 =item B<ensure_all_roles($applicant, @roles)>
345 This function is similar to L</apply_all_roles>, but only applies roles that
346 C<$applicant> does not already consume.
348 =item B<get_all_attribute_values($meta, $instance)>
350 Returns a hash reference containing all of the C<$instance>'s
351 attributes. The keys are attribute names.
353 =item B<get_all_init_args($meta, $instance)>
355 Returns a hash reference containing all of the C<init_arg> values for
356 the instance's attributes. The values are the associated attribute
357 values. If an attribute does not have a defined C<init_arg>, it is
360 This could be useful in cloning an object.
362 =item B<resolve_metaclass_alias($category, $name, %options)>
364 =item B<resolve_metatrait_alias($category, $name, %options)>
366 Resolves a short name to a full class name. Short names are often used
367 when specifying the C<metaclass> or C<traits> option for an attribute:
373 The name resolution mechanism is covered in
374 L<Moose/Metaclass and Trait Name Resolution>.
376 =item B<meta_class_alias($to[, $from])>
378 =item B<meta_attribute_alias($to[, $from])>
380 Create an alias from the class C<$from> (or the current package, if
381 C<$from> is unspecified), so that
382 L<Moose/Metaclass and Trait Name Resolution> works properly.
384 =item B<english_list(@items)>
386 Given a list of scalars, turns them into a proper list in English
387 ("one and two", "one, two, three, and four"). This is used to help us
388 make nicer error messages.
394 Here is a list of possible functions to write
398 =item discovering original method from modified method
400 =item search for origin class of a method or attribute
406 See L<Moose/BUGS> for details on reporting bugs.
410 Anders Nor Berle E<lt>debolaz@gmail.comE<gt>
412 B<with contributions from:>
414 Robert (phaylon) Sedlacek
418 =head1 COPYRIGHT AND LICENSE
420 Copyright 2007-2009 by Infinity Interactive, Inc.
422 L<http://www.iinteractive.com>
424 This library is free software; you can redistribute it and/or modify
425 it under the same terms as Perl itself.