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