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