No more alias_method for roles either. This meant more or less copying
[gitmo/Moose.git] / lib / Moose / Meta / Role / Application / ToRole.pm
1 package Moose::Meta::Role::Application::ToRole;
2
3 use strict;
4 use warnings;
5 use metaclass;
6
7 use Scalar::Util    'blessed';
8
9 our $VERSION   = '0.57';
10 $VERSION = eval $VERSION;
11 our $AUTHORITY = 'cpan:STEVAN';
12
13 use base 'Moose::Meta::Role::Application';
14
15 sub apply {
16     my ($self, $role1, $role2) = @_;    
17     $self->SUPER::apply($role1, $role2);   
18     $role2->add_role($role1);     
19 }
20
21 sub check_role_exclusions {
22     my ($self, $role1, $role2) = @_;
23     Moose->throw_error("Conflict detected: " . $role2->name . " excludes role '" . $role1->name . "'")
24         if $role2->excludes_role($role1->name);
25     foreach my $excluded_role_name ($role1->get_excluded_roles_list) {
26         Moose->throw_error("The class " . $role2->name . " does the excluded role '$excluded_role_name'")
27             if $role2->does_role($excluded_role_name);
28         $role2->add_excluded_roles($excluded_role_name);
29     }
30 }
31
32 sub check_required_methods {
33     my ($self, $role1, $role2) = @_;
34     foreach my $required_method_name ($role1->get_required_method_list) {
35             
36         next if $self->is_aliased_method($required_method_name);
37                     
38         $role2->add_required_methods($required_method_name)
39             unless $role2->find_method_by_name($required_method_name);
40     }
41 }
42
43 sub check_required_attributes {
44     
45 }
46
47 sub apply_attributes {
48     my ($self, $role1, $role2) = @_;
49     foreach my $attribute_name ($role1->get_attribute_list) {
50         # it if it has one already
51         if ($role2->has_attribute($attribute_name) &&
52             # make sure we haven't seen this one already too
53             $role2->get_attribute($attribute_name) != $role1->get_attribute($attribute_name)) {
54             Moose->throw_error("Role '" . $role1->name . "' has encountered an attribute conflict " .
55                     "during composition. This is fatal error and cannot be disambiguated.");
56         }
57         else {
58             $role2->add_attribute(
59                 $attribute_name,
60                 $role1->get_attribute($attribute_name)
61             );
62         }
63     }
64 }
65
66 sub apply_methods {
67     my ($self, $role1, $role2) = @_;
68     foreach my $method_name ($role1->get_method_list) {
69         
70         next if $self->is_method_excluded($method_name);        
71
72         if ($self->is_method_aliased($method_name)) {
73             my $aliased_method_name = $self->get_method_aliases->{$method_name};
74             # it if it has one already
75             if ($role2->has_method($aliased_method_name) &&
76                 # and if they are not the same thing ...
77                 $role2->get_method($aliased_method_name)->body != $role1->get_method($method_name)->body) {
78                 Moose->throw_error("Cannot create a method alias if a local method of the same name exists");
79             }
80
81             $role2->add_method(
82                 $aliased_method_name,
83                 $role1->get_method($method_name)
84             );
85
86             if (!$role2->has_method($method_name)) {
87                 $role2->add_required_methods($method_name);
88             }
89
90             next;
91         }        
92         
93         # it if it has one already
94         if ($role2->has_method($method_name) &&
95             # and if they are not the same thing ...
96             $role2->get_method($method_name)->body != $role1->get_method($method_name)->body) {
97             # method conflicts between roles result
98             # in the method becoming a requirement
99             $role2->add_required_methods($method_name);
100         }
101         else {
102             # add it, although it could be overriden
103             $role2->add_method(
104                 $method_name,
105                 $role1->get_method($method_name)
106             );
107                         
108         }
109         
110     }
111 }
112
113 sub apply_override_method_modifiers {
114     my ($self, $role1, $role2) = @_;
115     foreach my $method_name ($role1->get_method_modifier_list('override')) {
116         # it if it has one already then ...
117         if ($role2->has_method($method_name)) {
118             # if it is being composed into another role
119             # we have a conflict here, because you cannot
120             # combine an overriden method with a locally
121             # defined one
122             Moose->throw_error("Role '" . $role1->name . "' has encountered an 'override' method conflict " .
123                     "during composition (A local method of the same name as been found). This " .
124                     "is fatal error.");
125         }
126         else {
127             # if we are a role, we need to make sure
128             # we dont have a conflict with the role
129             # we are composing into
130             if ($role2->has_override_method_modifier($method_name) &&
131                 $role2->get_override_method_modifier($method_name) != $role2->get_override_method_modifier($method_name)) {
132                 Moose->throw_error("Role '" . $role1->name . "' has encountered an 'override' method conflict " .
133                         "during composition (Two 'override' methods of the same name encountered). " .
134                         "This is fatal error.");
135             }
136             else {
137                 # if there is no conflict,
138                 # just add it to the role
139                 $role2->add_override_method_modifier(
140                     $method_name,
141                     $role1->get_override_method_modifier($method_name)
142                 );
143             }
144         }
145     }
146 }
147
148 sub apply_method_modifiers {
149     my ($self, $modifier_type, $role1, $role2) = @_;
150     my $add = "add_${modifier_type}_method_modifier";
151     my $get = "get_${modifier_type}_method_modifiers";
152     foreach my $method_name ($role1->get_method_modifier_list($modifier_type)) {
153         $role2->$add(
154             $method_name,
155             $_
156         ) foreach $role1->$get($method_name);
157     }
158 }
159
160
161 1;
162
163 __END__
164
165 =pod
166
167 =head1 NAME
168
169 Moose::Meta::Role::Application::ToRole - Compose a role into another role
170
171 =head1 DESCRIPTION
172
173 =head2 METHODS
174
175 =over 4
176
177 =item B<new>
178
179 =item B<meta>
180
181 =item B<apply>
182
183 =item B<check_role_exclusions>
184
185 =item B<check_required_methods>
186
187 =item B<check_required_attributes>
188
189 =item B<apply_attributes>
190
191 =item B<apply_methods>
192
193 =item B<apply_method_modifiers>
194
195 =item B<apply_override_method_modifiers>
196
197 =back
198
199 =head1 BUGS
200
201 All complex software has bugs lurking in it, and this module is no
202 exception. If you find a bug please either email me, or add the bug
203 to cpan-RT.
204
205 =head1 AUTHOR
206
207 Stevan Little E<lt>stevan@iinteractive.comE<gt>
208
209 =head1 COPYRIGHT AND LICENSE
210
211 Copyright 2006-2008 by Infinity Interactive, Inc.
212
213 L<http://www.iinteractive.com>
214
215 This library is free software; you can redistribute it and/or modify
216 it under the same terms as Perl itself.
217
218 =cut
219