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