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