rudementary support for attribute traits
[gitmo/Moose.git] / lib / Moose / Util.pm
1 package Moose::Util;
2
3 use strict;
4 use warnings;
5
6 use Sub::Exporter;
7 use Scalar::Util 'blessed';
8 use Carp         'confess';
9 use Class::MOP   ();
10
11 our $VERSION   = '0.02';
12 our $AUTHORITY = 'cpan:STEVAN';
13
14 my @exports = qw[
15     find_meta 
16     does_role
17     search_class_by_role   
18     apply_all_roles
19 ];
20
21 Sub::Exporter::setup_exporter({
22     exports => \@exports,
23     groups  => { all => \@exports }
24 });
25
26 ## some utils for the utils ...
27
28 sub find_meta { 
29     return unless $_[0];
30     return Class::MOP::get_metaclass_by_name(blessed($_[0]) || $_[0]);
31 }
32
33 ## the functions ...
34
35 sub does_role {
36     my ($class_or_obj, $role) = @_;
37
38     my $meta = find_meta($class_or_obj);
39     
40     return unless defined $meta;
41
42     return 1 if $meta->does_role($role);
43     return;
44 }
45
46 sub search_class_by_role {
47     my ($class_or_obj, $role_name) = @_;
48     
49     my $meta = find_meta($class_or_obj);
50
51     return unless defined $meta;
52
53     foreach my $class ($meta->class_precedence_list) {
54         
55         my $_meta = find_meta($class);        
56
57         next unless defined $_meta;
58
59         foreach my $role (@{ $_meta->roles || [] }) {
60             return $class if $role->name eq $role_name;
61         }
62     }
63
64     return;
65 }
66
67 sub apply_all_roles {
68     my $applicant = shift;
69     
70     confess "Must specify at least one role to apply to $applicant" unless @_;
71     
72     my $roles = Data::OptList::mkopt([ @_ ]);
73     
74     #use Data::Dumper;
75     #warn Dumper $roles;
76     
77     my $meta = (blessed $applicant ? $applicant : find_meta($applicant));
78     
79     Class::MOP::load_class($_->[0]) for @$roles;
80     
81     ($_->[0]->can('meta') && $_->[0]->meta->isa('Moose::Meta::Role'))
82         || confess "You can only consume roles, " . $_->[0] . " is not a Moose role"
83             foreach @$roles;
84
85     if (scalar @$roles == 1) {
86         my ($role, $params) = @{$roles->[0]};
87         $role->meta->apply($meta, (defined $params ? %$params : ()));
88     }
89     else {
90         Moose::Meta::Role->combine(
91             @$roles
92         )->apply($meta);
93     }    
94 }
95
96
97 1;
98
99 __END__
100
101 =pod
102
103 =head1 NAME
104
105 Moose::Util - Utilities for working with Moose classes
106
107 =head1 SYNOPSIS
108
109   use Moose::Util qw/find_meta does_role search_class_by_role/;
110
111   my $meta = find_meta($object) || die "No metaclass found";
112
113   if (does_role($object, $role)) {
114     print "The object can do $role!\n";
115   }
116
117   my $class = search_class_by_role($object, 'FooRole');
118   print "Nearest class with 'FooRole' is $class\n";
119
120 =head1 DESCRIPTION
121
122 This is a set of utility functions to help working with Moose classes. This 
123 is an experimental module, and it's not 100% clear what purpose it will serve. 
124 That said, ideas, suggestions and contributions to this collection are most 
125 welcome. See the L<TODO> section below for a list of ideas for possible 
126 functions to write.
127
128 =head1 EXPORTED FUNCTIONS
129
130 =over 4
131
132 =item B<find_meta ($class_or_obj)>
133
134 This will attempt to locate a metaclass for the given C<$class_or_obj>
135 and return it.
136
137 =item B<does_role ($class_or_obj, $role_name)>
138
139 Returns true if C<$class_or_obj> can do the role C<$role_name>.
140
141 =item B<search_class_by_role ($class_or_obj, $role_name)>
142
143 Returns first class in precedence list that consumed C<$role_name>.
144
145 =item B<apply_all_roles ($applicant, @roles)>
146
147 Given an C<$applicant> (which can somehow be turned into either a 
148 metaclass or a metarole) and a list of C<@roles> this will do the 
149 right thing to apply the C<@roles> to the C<$applicant>. This is 
150 actually used internally by both L<Moose> and L<Moose::Role>.
151
152 =back
153
154 =head1 TODO
155
156 Here is a list of possible functions to write
157
158 =over 4
159
160 =item discovering original method from modified method
161
162 =item search for origin class of a method or attribute
163
164 =back
165
166 =head1 BUGS
167
168 All complex software has bugs lurking in it, and this module is no 
169 exception. If you find a bug please either email me, or add the bug
170 to cpan-RT.
171
172 =head1 AUTHOR
173
174 Anders Nor Berle E<lt>debolaz@gmail.comE<gt>
175
176 B<with contributions from:>
177
178 Robert (phaylon) Sedlacek
179
180 Stevan Little
181
182 =head1 COPYRIGHT AND LICENSE
183
184 Copyright 2007-2008 by Infinity Interactive, Inc.
185
186 L<http://www.iinteractive.com>
187
188 This library is free software; you can redistribute it and/or modify
189 it under the same terms as Perl itself. 
190
191 =cut
192