bump version to 0.62
[gitmo/Moose.git] / lib / Moose / Util.pm
CommitLineData
9a641848 1package Moose::Util;
2
9a641848 3use strict;
4use warnings;
5
7125b244 6use Sub::Exporter;
d7d8a8c7 7use Scalar::Util 'blessed';
f5bc97e5 8use Class::MOP 0.60;
9a641848 9
aead17e7 10our $VERSION = '0.62';
e606ae5f 11$VERSION = eval $VERSION;
7125b244 12our $AUTHORITY = 'cpan:STEVAN';
9a641848 13
7125b244 14my @exports = qw[
6532ca5a 15 find_meta
16 does_role
7125b244 17 search_class_by_role
d7d8a8c7 18 apply_all_roles
ab76842e 19 get_all_init_args
20 get_all_attribute_values
a5e883ae 21 resolve_metatrait_alias
22 resolve_metaclass_alias
5f71050b 23 add_method_modifier
7125b244 24];
9a641848 25
7125b244 26Sub::Exporter::setup_exporter({
27 exports => \@exports,
11065d1f 28 groups => { all => \@exports }
7125b244 29});
30
31## some utils for the utils ...
32
6532ca5a 33sub find_meta {
7125b244 34 return unless $_[0];
d7d8a8c7 35 return Class::MOP::get_metaclass_by_name(blessed($_[0]) || $_[0]);
7125b244 36}
9a641848 37
7125b244 38## the functions ...
adf82331 39
7125b244 40sub does_role {
41 my ($class_or_obj, $role) = @_;
adf82331 42
6532ca5a 43 my $meta = find_meta($class_or_obj);
7125b244 44
45 return unless defined $meta;
10a745f5 46 return unless $meta->can('does_role');
7125b244 47 return 1 if $meta->does_role($role);
48 return;
9a641848 49}
50
1631b53f 51sub search_class_by_role {
7125b244 52 my ($class_or_obj, $role_name) = @_;
53
6532ca5a 54 my $meta = find_meta($class_or_obj);
7125b244 55
56 return unless defined $meta;
57
58 foreach my $class ($meta->class_precedence_list) {
59
6532ca5a 60 my $_meta = find_meta($class);
1631b53f 61
7125b244 62 next unless defined $_meta;
63
64 foreach my $role (@{ $_meta->roles || [] }) {
1631b53f 65 return $class if $role->name eq $role_name;
66 }
67 }
68
7125b244 69 return;
1631b53f 70}
71
d7d8a8c7 72sub apply_all_roles {
73 my $applicant = shift;
e606ae5f 74
c245d69b 75 Moose->throw_error("Must specify at least one role to apply to $applicant") unless @_;
e606ae5f 76
77 my $roles = Data::OptList::mkopt( [@_] );
78
79 my $meta = ( blessed $applicant ? $applicant : find_meta($applicant) );
80
9c10b5ad 81 foreach my $role_spec (@$roles) {
e606ae5f 82 Class::MOP::load_class( $role_spec->[0] );
9c10b5ad 83 }
d7d8a8c7 84
e606ae5f 85 ( $_->[0]->can('meta') && $_->[0]->meta->isa('Moose::Meta::Role') )
c245d69b 86 || Moose->throw_error("You can only consume roles, "
e606ae5f 87 . $_->[0]
4c0b3599 88 . " is not a Moose role")
e606ae5f 89 foreach @$roles;
90
91 if ( scalar @$roles == 1 ) {
92 my ( $role, $params ) = @{ $roles->[0] };
93 $role->meta->apply( $meta, ( defined $params ? %$params : () ) );
d7d8a8c7 94 }
95 else {
e606ae5f 96 Moose::Meta::Role->combine( @$roles )->apply($meta);
97 }
d7d8a8c7 98}
99
ab76842e 100# instance deconstruction ...
101
102sub get_all_attribute_values {
103 my ($class, $instance) = @_;
104 return +{
105 map { $_->name => $_->get_value($instance) }
106 grep { $_->has_value($instance) }
107 $class->compute_all_applicable_attributes
108 };
109}
110
111sub get_all_init_args {
112 my ($class, $instance) = @_;
113 return +{
114 map { $_->init_arg => $_->get_value($instance) }
115 grep { $_->has_value($instance) }
116 grep { defined($_->init_arg) }
117 $class->compute_all_applicable_attributes
118 };
119}
120
50fbbf3d 121sub resolve_metatrait_alias {
50fbbf3d 122 return resolve_metaclass_alias( @_, trait => 1 );
a3738e5b 123}
124
50fbbf3d 125{
126 my %cache;
a3738e5b 127
50fbbf3d 128 sub resolve_metaclass_alias {
129 my ( $type, $metaclass_name, %options ) = @_;
a3738e5b 130
50fbbf3d 131 my $cache_key = $type . q{ } . ( $options{trait} ? '-Trait' : '' );
132 return $cache{$cache_key}{$metaclass_name}
133 if $cache{$cache_key}{$metaclass_name};
134
135 my $possible_full_name
136 = 'Moose::Meta::'
137 . $type
138 . '::Custom::'
139 . ( $options{trait} ? "Trait::" : "" )
140 . $metaclass_name;
141
142 my $loaded_class = Class::MOP::load_first_existing_class(
143 $possible_full_name,
144 $metaclass_name
145 );
146
147 return $cache{$cache_key}{$metaclass_name}
148 = $loaded_class->can('register_implementation')
149 ? $loaded_class->register_implementation
150 : $loaded_class;
151 }
a3738e5b 152}
153
5f71050b 154sub add_method_modifier {
155 my ( $class_or_obj, $modifier_name, $args ) = @_;
156 my $meta = find_meta($class_or_obj);
157 my $code = pop @{$args};
158 my $add_modifier_method = 'add_' . $modifier_name . '_method_modifier';
159 if ( my $method_modifier_type = ref( @{$args}[0] ) ) {
160 if ( $method_modifier_type eq 'Regexp' ) {
e606ae5f 161 my @all_methods = $meta->get_all_methods;
5f71050b 162 my @matched_methods
e606ae5f 163 = grep { $_->name =~ @{$args}[0] } @all_methods;
164 $meta->$add_modifier_method( $_->name, $code )
5f71050b 165 for @matched_methods;
166 }
167 }
168 else {
169 $meta->$add_modifier_method( $_, $code ) for @{$args};
170 }
171}
d9bb6c63 172
9a641848 1731;
174
175__END__
176
177=pod
178
179=head1 NAME
180
7125b244 181Moose::Util - Utilities for working with Moose classes
9a641848 182
183=head1 SYNOPSIS
184
6532ca5a 185 use Moose::Util qw/find_meta does_role search_class_by_role/;
186
187 my $meta = find_meta($object) || die "No metaclass found";
9a641848 188
adf82331 189 if (does_role($object, $role)) {
190 print "The object can do $role!\n";
9a641848 191 }
192
1631b53f 193 my $class = search_class_by_role($object, 'FooRole');
194 print "Nearest class with 'FooRole' is $class\n";
195
7125b244 196=head1 DESCRIPTION
197
004222dc 198This is a set of utility functions to help working with Moose classes, and
199is used internally by Moose itself. The goal is to provide useful functions
200that for both Moose users and Moose extenders (MooseX:: authors).
201
202This is a relatively new addition to the Moose toolchest, so ideas,
203suggestions and contributions to this collection are most welcome.
204See the L<TODO> section below for a list of ideas for possible functions
205to write.
7125b244 206
207=head1 EXPORTED FUNCTIONS
9a641848 208
209=over 4
210
6532ca5a 211=item B<find_meta ($class_or_obj)>
212
213This will attempt to locate a metaclass for the given C<$class_or_obj>
214and return it.
215
7125b244 216=item B<does_role ($class_or_obj, $role_name)>
217
218Returns true if C<$class_or_obj> can do the role C<$role_name>.
219
220=item B<search_class_by_role ($class_or_obj, $role_name)>
221
222Returns first class in precedence list that consumed C<$role_name>.
223
d7d8a8c7 224=item B<apply_all_roles ($applicant, @roles)>
225
226Given an C<$applicant> (which can somehow be turned into either a
227metaclass or a metarole) and a list of C<@roles> this will do the
228right thing to apply the C<@roles> to the C<$applicant>. This is
3bb22459 229actually used internally by both L<Moose> and L<Moose::Role>, and the
230C<@roles> will be pre-processed through L<Data::OptList::mkopt>
231to allow for the additional arguments to be passed.
d7d8a8c7 232
ab76842e 233=item B<get_all_attribute_values($meta, $instance)>
234
235Returns the values of the C<$instance>'s fields keyed by the attribute names.
236
237=item B<get_all_init_args($meta, $instance)>
238
239Returns a hash reference where the keys are all the attributes' C<init_arg>s
240and the values are the instance's fields. Attributes without an C<init_arg>
241will be skipped.
242
a3738e5b 243=item B<resolve_metaclass_alias($category, $name, %options)>
244
245=item B<resolve_metatrait_alias($category, $name, %options)>
246
247Resolve a short name like in e.g.
248
249 has foo => (
250 metaclass => "Bar",
251 );
252
253to a full class name.
254
5f71050b 255=item B<add_method_modifier ($class_or_obj, $modifier_name, $args)>
256
7125b244 257=back
9a641848 258
7125b244 259=head1 TODO
9a641848 260
7125b244 261Here is a list of possible functions to write
9a641848 262
7125b244 263=over 4
1631b53f 264
7125b244 265=item discovering original method from modified method
1631b53f 266
7125b244 267=item search for origin class of a method or attribute
1631b53f 268
9a641848 269=back
270
271=head1 BUGS
272
273All complex software has bugs lurking in it, and this module is no
274exception. If you find a bug please either email me, or add the bug
275to cpan-RT.
276
277=head1 AUTHOR
278
279Anders Nor Berle E<lt>debolaz@gmail.comE<gt>
280
7125b244 281B<with contributions from:>
282
283Robert (phaylon) Sedlacek
284
285Stevan Little
286
9a641848 287=head1 COPYRIGHT AND LICENSE
288
778db3ac 289Copyright 2007-2008 by Infinity Interactive, Inc.
9a641848 290
291L<http://www.iinteractive.com>
292
293This library is free software; you can redistribute it and/or modify
294it under the same terms as Perl itself.
295
296=cut
297