bump all versions to 0.60
[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
f5bc97e5 10our $VERSION = '0.60';
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 {
122 my ( $type, $metaclass_name ) = @_;
123
124 return resolve_metaclass_alias( @_, trait => 1 );
a3738e5b 125}
126
50fbbf3d 127{
128 my %cache;
a3738e5b 129
50fbbf3d 130 sub resolve_metaclass_alias {
131 my ( $type, $metaclass_name, %options ) = @_;
a3738e5b 132
50fbbf3d 133 my $cache_key = $type . q{ } . ( $options{trait} ? '-Trait' : '' );
134 return $cache{$cache_key}{$metaclass_name}
135 if $cache{$cache_key}{$metaclass_name};
136
137 my $possible_full_name
138 = 'Moose::Meta::'
139 . $type
140 . '::Custom::'
141 . ( $options{trait} ? "Trait::" : "" )
142 . $metaclass_name;
143
144 my $loaded_class = Class::MOP::load_first_existing_class(
145 $possible_full_name,
146 $metaclass_name
147 );
148
149 return $cache{$cache_key}{$metaclass_name}
150 = $loaded_class->can('register_implementation')
151 ? $loaded_class->register_implementation
152 : $loaded_class;
153 }
a3738e5b 154}
155
5f71050b 156sub add_method_modifier {
157 my ( $class_or_obj, $modifier_name, $args ) = @_;
158 my $meta = find_meta($class_or_obj);
159 my $code = pop @{$args};
160 my $add_modifier_method = 'add_' . $modifier_name . '_method_modifier';
161 if ( my $method_modifier_type = ref( @{$args}[0] ) ) {
162 if ( $method_modifier_type eq 'Regexp' ) {
e606ae5f 163 my @all_methods = $meta->get_all_methods;
5f71050b 164 my @matched_methods
e606ae5f 165 = grep { $_->name =~ @{$args}[0] } @all_methods;
166 $meta->$add_modifier_method( $_->name, $code )
5f71050b 167 for @matched_methods;
168 }
169 }
170 else {
171 $meta->$add_modifier_method( $_, $code ) for @{$args};
172 }
173}
d9bb6c63 174
9a641848 1751;
176
177__END__
178
179=pod
180
181=head1 NAME
182
7125b244 183Moose::Util - Utilities for working with Moose classes
9a641848 184
185=head1 SYNOPSIS
186
6532ca5a 187 use Moose::Util qw/find_meta does_role search_class_by_role/;
188
189 my $meta = find_meta($object) || die "No metaclass found";
9a641848 190
adf82331 191 if (does_role($object, $role)) {
192 print "The object can do $role!\n";
9a641848 193 }
194
1631b53f 195 my $class = search_class_by_role($object, 'FooRole');
196 print "Nearest class with 'FooRole' is $class\n";
197
7125b244 198=head1 DESCRIPTION
199
004222dc 200This is a set of utility functions to help working with Moose classes, and
201is used internally by Moose itself. The goal is to provide useful functions
202that for both Moose users and Moose extenders (MooseX:: authors).
203
204This is a relatively new addition to the Moose toolchest, so ideas,
205suggestions and contributions to this collection are most welcome.
206See the L<TODO> section below for a list of ideas for possible functions
207to write.
7125b244 208
209=head1 EXPORTED FUNCTIONS
9a641848 210
211=over 4
212
6532ca5a 213=item B<find_meta ($class_or_obj)>
214
215This will attempt to locate a metaclass for the given C<$class_or_obj>
216and return it.
217
7125b244 218=item B<does_role ($class_or_obj, $role_name)>
219
220Returns true if C<$class_or_obj> can do the role C<$role_name>.
221
222=item B<search_class_by_role ($class_or_obj, $role_name)>
223
224Returns first class in precedence list that consumed C<$role_name>.
225
d7d8a8c7 226=item B<apply_all_roles ($applicant, @roles)>
227
228Given an C<$applicant> (which can somehow be turned into either a
229metaclass or a metarole) and a list of C<@roles> this will do the
230right thing to apply the C<@roles> to the C<$applicant>. This is
3bb22459 231actually used internally by both L<Moose> and L<Moose::Role>, and the
232C<@roles> will be pre-processed through L<Data::OptList::mkopt>
233to allow for the additional arguments to be passed.
d7d8a8c7 234
ab76842e 235=item B<get_all_attribute_values($meta, $instance)>
236
237Returns the values of the C<$instance>'s fields keyed by the attribute names.
238
239=item B<get_all_init_args($meta, $instance)>
240
241Returns a hash reference where the keys are all the attributes' C<init_arg>s
242and the values are the instance's fields. Attributes without an C<init_arg>
243will be skipped.
244
a3738e5b 245=item B<resolve_metaclass_alias($category, $name, %options)>
246
247=item B<resolve_metatrait_alias($category, $name, %options)>
248
249Resolve a short name like in e.g.
250
251 has foo => (
252 metaclass => "Bar",
253 );
254
255to a full class name.
256
5f71050b 257=item B<add_method_modifier ($class_or_obj, $modifier_name, $args)>
258
7125b244 259=back
9a641848 260
7125b244 261=head1 TODO
9a641848 262
7125b244 263Here is a list of possible functions to write
9a641848 264
7125b244 265=over 4
1631b53f 266
7125b244 267=item discovering original method from modified method
1631b53f 268
7125b244 269=item search for origin class of a method or attribute
1631b53f 270
9a641848 271=back
272
273=head1 BUGS
274
275All complex software has bugs lurking in it, and this module is no
276exception. If you find a bug please either email me, or add the bug
277to cpan-RT.
278
279=head1 AUTHOR
280
281Anders Nor Berle E<lt>debolaz@gmail.comE<gt>
282
7125b244 283B<with contributions from:>
284
285Robert (phaylon) Sedlacek
286
287Stevan Little
288
9a641848 289=head1 COPYRIGHT AND LICENSE
290
778db3ac 291Copyright 2007-2008 by Infinity Interactive, Inc.
9a641848 292
293L<http://www.iinteractive.com>
294
295This library is free software; you can redistribute it and/or modify
296it under the same terms as Perl itself.
297
298=cut
299