Commit | Line | Data |
e185c027 |
1 | |
2 | package Moose::Meta::Role; |
3 | |
4 | use strict; |
5 | use warnings; |
6 | use metaclass; |
7 | |
bdabd620 |
8 | use Carp 'confess'; |
9 | use Scalar::Util 'blessed'; |
10 | |
25374f01 |
11 | our $VERSION = '0.11'; |
d44714be |
12 | our $AUTHORITY = 'cpan:STEVAN'; |
e185c027 |
13 | |
8ee73eeb |
14 | use Moose::Meta::Class; |
39b3bc94 |
15 | use Moose::Meta::Role::Method; |
d67145ed |
16 | use Moose::Meta::Role::Method::Required; |
8ee73eeb |
17 | |
68efb014 |
18 | use base 'Class::MOP::Module'; |
80572233 |
19 | |
80572233 |
20 | |
21716c07 |
21 | # NOTE: |
22 | # I normally don't do this, but I am doing |
23 | # a whole bunch of meta-programmin in this |
24 | # module, so it just makes sense. |
25 | # - SL |
80572233 |
26 | |
21716c07 |
27 | my $META = __PACKAGE__->meta; |
28 | |
29 | ## ------------------------------------------------------------------ |
30 | ## attributes ... |
e185c027 |
31 | |
21716c07 |
32 | # NOTE: |
33 | # since roles are lazy, we hold all the attributes |
34 | # of the individual role in 'statis' until which |
35 | # time when it is applied to a class. This means |
36 | # keeping a lot of things in hash maps, so we are |
37 | # using a little of that meta-programmin' magic |
38 | # here an saving lots of extra typin. |
39 | # - SL |
d79e62fd |
40 | |
21716c07 |
41 | $META->add_attribute($_->{name} => ( |
42 | reader => $_->{reader}, |
d79e62fd |
43 | default => sub { {} } |
21716c07 |
44 | )) for ( |
45 | { name => 'excluded_roles_map', reader => 'get_excluded_roles_map' }, |
46 | { name => 'attribute_map', reader => 'get_attribute_map' }, |
47 | { name => 'required_methods', reader => 'get_required_methods_map' }, |
48 | ); |
49 | |
50 | # NOTE: |
51 | # many of these attributes above require similar |
52 | # functionality to support them, so we again use |
53 | # the wonders of meta-programmin' to deliver a |
54 | # very compact solution to this normally verbose |
55 | # problem. |
56 | # - SL |
57 | |
58 | foreach my $action ( |
59 | { |
60 | attr_reader => 'get_excluded_roles_map' , |
61 | methods => { |
62 | add => 'add_excluded_roles', |
63 | get_list => 'get_excluded_roles_list', |
64 | existence => 'excludes_role', |
65 | } |
66 | }, |
67 | { |
68 | attr_reader => 'get_required_methods_map', |
69 | methods => { |
70 | add => 'add_required_methods', |
71 | remove => 'remove_required_methods', |
72 | get_list => 'get_required_method_list', |
73 | existence => 'requires_method', |
74 | } |
75 | }, |
76 | { |
77 | attr_reader => 'get_attribute_map', |
78 | methods => { |
79 | get => 'get_attribute', |
80 | get_list => 'get_attribute_list', |
81 | existence => 'has_attribute', |
82 | remove => 'remove_attribute', |
83 | } |
84 | } |
85 | ) { |
86 | |
87 | my $attr_reader = $action->{attr_reader}; |
88 | my $methods = $action->{methods}; |
89 | |
90 | $META->add_method($methods->{add} => sub { |
91 | my ($self, @values) = @_; |
92 | $self->$attr_reader->{$_} = undef foreach @values; |
93 | }) if exists $methods->{add}; |
94 | |
95 | $META->add_method($methods->{get_list} => sub { |
96 | my ($self) = @_; |
97 | keys %{$self->$attr_reader}; |
98 | }) if exists $methods->{get_list}; |
99 | |
100 | $META->add_method($methods->{get} => sub { |
101 | my ($self, $name) = @_; |
102 | $self->$attr_reader->{$name} |
103 | }) if exists $methods->{get}; |
104 | |
105 | $META->add_method($methods->{existence} => sub { |
106 | my ($self, $name) = @_; |
107 | exists $self->$attr_reader->{$name} ? 1 : 0; |
108 | }) if exists $methods->{existence}; |
109 | |
110 | $META->add_method($methods->{remove} => sub { |
111 | my ($self, @values) = @_; |
112 | delete $self->$attr_reader->{$_} foreach @values; |
113 | }) if exists $methods->{remove}; |
114 | } |
d79e62fd |
115 | |
21716c07 |
116 | ## some things don't always fit, so they go here ... |
80572233 |
117 | |
21716c07 |
118 | sub add_attribute { |
119 | my $self = shift; |
120 | my $name = shift; |
121 | my $attr_desc; |
122 | if (scalar @_ == 1 && ref($_[0]) eq 'HASH') { |
123 | $attr_desc = $_[0]; |
124 | } |
125 | else { |
126 | $attr_desc = { @_ }; |
127 | } |
128 | $self->get_attribute_map->{$name} = $attr_desc; |
129 | } |
e185c027 |
130 | |
21716c07 |
131 | sub _clean_up_required_methods { |
132 | my $self = shift; |
133 | foreach my $method ($self->get_required_method_list) { |
134 | $self->remove_required_methods($method) |
135 | if $self->has_method($method); |
136 | } |
137 | } |
1331430a |
138 | |
21716c07 |
139 | ## ------------------------------------------------------------------ |
140 | ## method modifiers |
141 | |
142 | $META->add_attribute($_->{name} => ( |
143 | reader => $_->{reader}, |
1331430a |
144 | default => sub { {} } |
21716c07 |
145 | )) for ( |
146 | { name => 'before_method_modifiers', reader => 'get_before_method_modifiers_map' }, |
147 | { name => 'after_method_modifiers', reader => 'get_after_method_modifiers_map' }, |
148 | { name => 'around_method_modifiers', reader => 'get_around_method_modifiers_map' }, |
149 | { name => 'override_method_modifiers', reader => 'get_override_method_modifiers_map' }, |
150 | ); |
151 | |
152 | # NOTE: |
153 | # the before/around/after method modifiers are |
154 | # stored by name, but there can be many methods |
155 | # then associated with that name. So again we have |
156 | # lots of similar functionality, so we can do some |
157 | # meta-programmin' and save some time. |
158 | # - SL |
159 | |
160 | foreach my $modifier_type (qw[ before around after ]) { |
161 | |
162 | my $attr_reader = "get_${modifier_type}_method_modifiers_map"; |
163 | |
164 | $META->add_method("get_${modifier_type}_method_modifiers" => sub { |
165 | my ($self, $method_name) = @_; |
166 | @{$self->$attr_reader->{$method_name}}; |
167 | }); |
168 | |
169 | $META->add_method("has_${modifier_type}_method_modifiers" => sub { |
170 | my ($self, $method_name) = @_; |
171 | # NOTE: |
172 | # for now we assume that if it exists,.. |
173 | # it has at least one modifier in it |
174 | (exists $self->$attr_reader->{$method_name}) ? 1 : 0; |
175 | }); |
176 | |
177 | $META->add_method("add_${modifier_type}_method_modifier" => sub { |
178 | my ($self, $method_name, $method) = @_; |
179 | |
180 | $self->$attr_reader->{$method_name} = [] |
181 | unless exists $self->$attr_reader->{$method_name}; |
182 | |
183 | my $modifiers = $self->$attr_reader->{$method_name}; |
184 | |
185 | # NOTE: |
186 | # check to see that we aren't adding the |
187 | # same code twice. We err in favor of the |
188 | # first on here, this may not be as expected |
189 | foreach my $modifier (@{$modifiers}) { |
190 | return if $modifier == $method; |
191 | } |
192 | |
193 | push @{$modifiers} => $method; |
194 | }); |
195 | |
196 | } |
1331430a |
197 | |
21716c07 |
198 | ## ------------------------------------------------------------------ |
199 | ## override method mofidiers |
0558683c |
200 | |
21716c07 |
201 | # NOTE: |
202 | # these are a little different because there |
203 | # can only be one per name, whereas the other |
204 | # method modifiers can have multiples. |
205 | # - SL |
0558683c |
206 | |
21716c07 |
207 | sub add_override_method_modifier { |
208 | my ($self, $method_name, $method) = @_; |
209 | (!$self->has_method($method_name)) |
210 | || confess "Cannot add an override of method '$method_name' " . |
211 | "because there is a local version of '$method_name'"; |
212 | $self->get_override_method_modifiers_map->{$method_name} = $method; |
213 | } |
0558683c |
214 | |
21716c07 |
215 | sub has_override_method_modifier { |
216 | my ($self, $method_name) = @_; |
217 | # NOTE: |
218 | # for now we assume that if it exists,.. |
219 | # it has at least one modifier in it |
220 | (exists $self->get_override_method_modifiers_map->{$method_name}) ? 1 : 0; |
221 | } |
0558683c |
222 | |
21716c07 |
223 | sub get_override_method_modifier { |
224 | my ($self, $method_name) = @_; |
225 | $self->get_override_method_modifiers_map->{$method_name}; |
226 | } |
0558683c |
227 | |
21716c07 |
228 | ## general list accessor ... |
80572233 |
229 | |
21716c07 |
230 | sub get_method_modifier_list { |
231 | my ($self, $modifier_type) = @_; |
232 | my $accessor = "get_${modifier_type}_method_modifiers_map"; |
233 | keys %{$self->$accessor}; |
234 | } |
e185c027 |
235 | |
21716c07 |
236 | ## ------------------------------------------------------------------ |
80572233 |
237 | ## subroles |
238 | |
21716c07 |
239 | __PACKAGE__->meta->add_attribute('roles' => ( |
240 | reader => 'get_roles', |
241 | default => sub { [] } |
242 | )); |
243 | |
80572233 |
244 | sub add_role { |
245 | my ($self, $role) = @_; |
246 | (blessed($role) && $role->isa('Moose::Meta::Role')) |
247 | || confess "Roles must be instances of Moose::Meta::Role"; |
248 | push @{$self->get_roles} => $role; |
249 | } |
250 | |
b8aeb4dc |
251 | sub calculate_all_roles { |
252 | my $self = shift; |
253 | my %seen; |
21716c07 |
254 | grep { |
255 | !$seen{$_->name}++ |
256 | } ($self, |
257 | map { |
258 | $_->calculate_all_roles |
259 | } @{ $self->get_roles }); |
b8aeb4dc |
260 | } |
261 | |
80572233 |
262 | sub does_role { |
263 | my ($self, $role_name) = @_; |
264 | (defined $role_name) |
265 | || confess "You must supply a role name to look for"; |
bdabd620 |
266 | # if we are it,.. then return true |
267 | return 1 if $role_name eq $self->name; |
268 | # otherwise.. check our children |
80572233 |
269 | foreach my $role (@{$self->get_roles}) { |
bdabd620 |
270 | return 1 if $role->does_role($role_name); |
80572233 |
271 | } |
272 | return 0; |
273 | } |
274 | |
21716c07 |
275 | ## ------------------------------------------------------------------ |
276 | ## methods |
1331430a |
277 | |
21716c07 |
278 | sub method_metaclass { 'Moose::Meta::Role::Method' } |
80572233 |
279 | |
40e89659 |
280 | # FIXME: |
093b12c2 |
281 | # this is an UGLY hack |
282 | sub get_method_map { |
283 | my $self = shift; |
5cf3dbcf |
284 | $self->{'%!methods'} ||= {}; |
638853cb |
285 | $self->reset_package_cache_flag; |
093b12c2 |
286 | $self->Moose::Meta::Class::get_method_map() |
287 | } |
638853cb |
288 | sub update_package_cache_flag { () } |
289 | sub reset_package_cache_flag { (shift)->{'$!_package_cache_flag'} = undef; } |
093b12c2 |
290 | |
291 | # FIXME: |
40e89659 |
292 | # Yes, this is a really really UGLY hack |
293 | # but it works, and until I can figure |
294 | # out a better way, this is gonna be it. |
295 | |
68efb014 |
296 | sub get_method { (shift)->Moose::Meta::Class::get_method(@_) } |
68efb014 |
297 | sub has_method { (shift)->Moose::Meta::Class::has_method(@_) } |
298 | sub alias_method { (shift)->Moose::Meta::Class::alias_method(@_) } |
093b12c2 |
299 | sub get_method_list { |
300 | grep { |
342ac837 |
301 | !/^meta$/ |
093b12c2 |
302 | } (shift)->Moose::Meta::Class::get_method_list(@_) |
e185c027 |
303 | } |
304 | |
1db8ecc7 |
305 | sub find_method_by_name { (shift)->get_method(@_) } |
093b12c2 |
306 | |
21716c07 |
307 | ## ------------------------------------------------------------------ |
308 | ## role construction |
309 | ## ------------------------------------------------------------------ |
e185c027 |
310 | |
21716c07 |
311 | my $anon_counter = 0; |
e185c027 |
312 | |
21716c07 |
313 | sub apply { |
314 | my ($self, $other) = @_; |
315 | |
316 | unless ($other->isa('Moose::Meta::Class') || $other->isa('Moose::Meta::Role')) { |
317 | |
318 | # Runtime Role mixins |
319 | |
320 | # FIXME: |
321 | # We really should do this better, and |
322 | # cache the results of our efforts so |
323 | # that we don't need to repeat them. |
324 | |
325 | my $pkg_name = __PACKAGE__ . "::__RUNTIME_ROLE_ANON_CLASS__::" . $anon_counter++; |
326 | eval "package " . $pkg_name . "; our \$VERSION = '0.00';"; |
327 | die $@ if $@; |
0558683c |
328 | |
21716c07 |
329 | my $object = $other; |
0558683c |
330 | |
21716c07 |
331 | $other = Moose::Meta::Class->initialize($pkg_name); |
332 | $other->superclasses(blessed($object)); |
333 | |
334 | bless $object => $pkg_name; |
0558683c |
335 | } |
21716c07 |
336 | |
337 | $self->_check_excluded_roles($other); |
338 | $self->_check_required_methods($other); |
0558683c |
339 | |
21716c07 |
340 | $self->_apply_attributes($other); |
341 | $self->_apply_methods($other); |
53dd42d8 |
342 | |
343 | # NOTE: |
344 | # we need a clear cache flag too ... |
638853cb |
345 | $other->reset_package_cache_flag; |
0558683c |
346 | |
21716c07 |
347 | $self->_apply_override_method_modifiers($other); |
348 | $self->_apply_before_method_modifiers($other); |
349 | $self->_apply_around_method_modifiers($other); |
350 | $self->_apply_after_method_modifiers($other); |
0558683c |
351 | |
21716c07 |
352 | $other->add_role($self); |
0558683c |
353 | } |
354 | |
21716c07 |
355 | sub combine { |
356 | my ($class, @roles) = @_; |
357 | |
358 | my $pkg_name = __PACKAGE__ . "::__COMPOSITE_ROLE_SANDBOX__::" . $anon_counter++; |
359 | eval "package " . $pkg_name . "; our \$VERSION = '0.00';"; |
360 | die $@ if $@; |
361 | |
362 | my $combined = $class->initialize($pkg_name); |
363 | |
364 | foreach my $role (@roles) { |
365 | $role->apply($combined); |
366 | } |
367 | |
368 | $combined->_clean_up_required_methods; |
369 | |
370 | return $combined; |
0558683c |
371 | } |
372 | |
21716c07 |
373 | ## ------------------------------------------------------------------ |
e185c027 |
374 | |
bdabd620 |
375 | ## applying a role to a class ... |
376 | |
a2eec5e7 |
377 | sub _check_excluded_roles { |
bdabd620 |
378 | my ($self, $other) = @_; |
d79e62fd |
379 | if ($other->excludes_role($self->name)) { |
380 | confess "Conflict detected: " . $other->name . " excludes role '" . $self->name . "'"; |
381 | } |
d79e62fd |
382 | foreach my $excluded_role_name ($self->get_excluded_roles_list) { |
9c429218 |
383 | if ($other->does_role($excluded_role_name)) { |
d79e62fd |
384 | confess "The class " . $other->name . " does the excluded role '$excluded_role_name'"; |
385 | } |
386 | else { |
387 | if ($other->isa('Moose::Meta::Role')) { |
d79e62fd |
388 | $other->add_excluded_roles($excluded_role_name); |
389 | } |
a2eec5e7 |
390 | # else -> ignore it :) |
d79e62fd |
391 | } |
392 | } |
a2eec5e7 |
393 | } |
394 | |
395 | sub _check_required_methods { |
396 | my ($self, $other) = @_; |
1331430a |
397 | # NOTE: |
398 | # we might need to move this down below the |
399 | # the attributes so that we can require any |
400 | # attribute accessors. However I am thinking |
401 | # that maybe those are somehow exempt from |
402 | # the require methods stuff. |
403 | foreach my $required_method_name ($self->get_required_method_list) { |
8c835eba |
404 | |
be4427d0 |
405 | unless ($other->find_method_by_name($required_method_name)) { |
fa1be058 |
406 | if ($other->isa('Moose::Meta::Role')) { |
407 | $other->add_required_methods($required_method_name); |
408 | } |
409 | else { |
410 | confess "'" . $self->name . "' requires the method '$required_method_name' " . |
411 | "to be implemented by '" . $other->name . "'"; |
412 | } |
413 | } |
0558683c |
414 | else { |
415 | # NOTE: |
416 | # we need to make sure that the method is |
417 | # not a method modifier, because those do |
418 | # not satisfy the requirements ... |
1db8ecc7 |
419 | my $method = $other->find_method_by_name($required_method_name); |
e7f8d0c2 |
420 | |
421 | # check if it is a generated accessor ... |
422 | (!$method->isa('Class::MOP::Method::Accessor')) |
423 | || confess "'" . $self->name . "' requires the method '$required_method_name' " . |
424 | "to be implemented by '" . $other->name . "', the method is only an attribute accessor"; |
425 | |
426 | # NOTE: |
427 | # All other tests here have been removed, they were tests |
428 | # for overriden methods and before/after/around modifiers. |
429 | # But we realized that for classes any overriden or modified |
430 | # methods would be backed by a real method of that name |
431 | # (and therefore meet the requirement). And for roles, the |
432 | # overriden and modified methods are "in statis" and so would |
433 | # not show up in this test anyway (and as a side-effect they |
434 | # would not fufill the requirement, which is exactly what we |
435 | # want them to do anyway). |
436 | # - SL |
0558683c |
437 | } |
a2eec5e7 |
438 | } |
439 | } |
440 | |
441 | sub _apply_attributes { |
442 | my ($self, $other) = @_; |
bdabd620 |
443 | foreach my $attribute_name ($self->get_attribute_list) { |
db1ab48d |
444 | # it if it has one already |
a2eec5e7 |
445 | if ($other->has_attribute($attribute_name) && |
446 | # make sure we haven't seen this one already too |
447 | $other->get_attribute($attribute_name) != $self->get_attribute($attribute_name)) { |
db1ab48d |
448 | # see if we are being composed |
449 | # into a role or not |
a2eec5e7 |
450 | if ($other->isa('Moose::Meta::Role')) { |
db1ab48d |
451 | # all attribute conflicts between roles |
452 | # result in an immediate fatal error |
453 | confess "Role '" . $self->name . "' has encountered an attribute conflict " . |
454 | "during composition. This is fatal error and cannot be disambiguated."; |
455 | } |
456 | else { |
457 | # but if this is a class, we |
458 | # can safely skip adding the |
459 | # attribute to the class |
460 | next; |
461 | } |
462 | } |
463 | else { |
ac0ece3d |
464 | # NOTE: |
465 | # this is kinda ugly ... |
466 | if ($other->isa('Moose::Meta::Class')) { |
467 | $other->_process_attribute( |
468 | $attribute_name, |
469 | %{$self->get_attribute($attribute_name)} |
470 | ); |
471 | } |
472 | else { |
473 | $other->add_attribute( |
474 | $attribute_name, |
475 | $self->get_attribute($attribute_name) |
476 | ); |
477 | } |
db1ab48d |
478 | } |
a2eec5e7 |
479 | } |
480 | } |
481 | |
482 | sub _apply_methods { |
483 | my ($self, $other) = @_; |
bdabd620 |
484 | foreach my $method_name ($self->get_method_list) { |
db1ab48d |
485 | # it if it has one already |
d30bc041 |
486 | if ($other->has_method($method_name) && |
487 | # and if they are not the same thing ... |
093b12c2 |
488 | $other->get_method($method_name)->body != $self->get_method($method_name)->body) { |
db1ab48d |
489 | # see if we are composing into a role |
490 | if ($other->isa('Moose::Meta::Role')) { |
491 | # method conflicts between roles result |
492 | # in the method becoming a requirement |
493 | $other->add_required_methods($method_name); |
494 | # NOTE: |
495 | # we have to remove the method from our |
496 | # role, if this is being called from combine() |
497 | # which means the meta is an anon class |
498 | # this *may* cause problems later, but it |
499 | # is probably fairly safe to assume that |
500 | # anon classes will only be used internally |
501 | # or by people who know what they are doing |
68efb014 |
502 | $other->Moose::Meta::Class::remove_method($method_name) |
40e89659 |
503 | if $other->name =~ /__COMPOSITE_ROLE_SANDBOX__/; |
db1ab48d |
504 | } |
505 | else { |
506 | next; |
507 | } |
508 | } |
509 | else { |
510 | # add it, although it could be overriden |
511 | $other->alias_method( |
512 | $method_name, |
513 | $self->get_method($method_name) |
514 | ); |
515 | } |
a2eec5e7 |
516 | } |
517 | } |
518 | |
0558683c |
519 | sub _apply_override_method_modifiers { |
520 | my ($self, $other) = @_; |
521 | foreach my $method_name ($self->get_method_modifier_list('override')) { |
522 | # it if it has one already then ... |
523 | if ($other->has_method($method_name)) { |
524 | # if it is being composed into another role |
525 | # we have a conflict here, because you cannot |
526 | # combine an overriden method with a locally |
527 | # defined one |
528 | if ($other->isa('Moose::Meta::Role')) { |
529 | confess "Role '" . $self->name . "' has encountered an 'override' method conflict " . |
530 | "during composition (A local method of the same name as been found). This " . |
531 | "is fatal error."; |
532 | } |
533 | else { |
534 | # if it is a class, then we |
535 | # just ignore this here ... |
536 | next; |
537 | } |
538 | } |
539 | else { |
540 | # if no local method is found, then we |
541 | # must check if we are a role or class |
542 | if ($other->isa('Moose::Meta::Role')) { |
543 | # if we are a role, we need to make sure |
544 | # we dont have a conflict with the role |
545 | # we are composing into |
546 | if ($other->has_override_method_modifier($method_name) && |
547 | $other->get_override_method_modifier($method_name) != $self->get_override_method_modifier($method_name)) { |
548 | confess "Role '" . $self->name . "' has encountered an 'override' method conflict " . |
549 | "during composition (Two 'override' methods of the same name encountered). " . |
550 | "This is fatal error."; |
551 | } |
552 | else { |
553 | # if there is no conflict, |
554 | # just add it to the role |
555 | $other->add_override_method_modifier( |
556 | $method_name, |
557 | $self->get_override_method_modifier($method_name) |
558 | ); |
559 | } |
560 | } |
561 | else { |
562 | # if this is not a role, then we need to |
563 | # find the original package of the method |
564 | # so that we can tell the class were to |
565 | # find the right super() method |
566 | my $method = $self->get_override_method_modifier($method_name); |
53dd42d8 |
567 | my ($package) = Class::MOP::get_code_info($method); |
0558683c |
568 | # if it is a class, we just add it |
569 | $other->add_override_method_modifier($method_name, $method, $package); |
570 | } |
571 | } |
572 | } |
573 | } |
574 | |
575 | sub _apply_method_modifiers { |
576 | my ($self, $modifier_type, $other) = @_; |
577 | my $add = "add_${modifier_type}_method_modifier"; |
578 | my $get = "get_${modifier_type}_method_modifiers"; |
579 | foreach my $method_name ($self->get_method_modifier_list($modifier_type)) { |
580 | $other->$add( |
581 | $method_name, |
582 | $_ |
583 | ) foreach $self->$get($method_name); |
584 | } |
585 | } |
586 | |
587 | sub _apply_before_method_modifiers { (shift)->_apply_method_modifiers('before' => @_) } |
588 | sub _apply_around_method_modifiers { (shift)->_apply_method_modifiers('around' => @_) } |
589 | sub _apply_after_method_modifiers { (shift)->_apply_method_modifiers('after' => @_) } |
590 | |
e185c027 |
591 | 1; |
592 | |
593 | __END__ |
594 | |
595 | =pod |
596 | |
597 | =head1 NAME |
598 | |
599 | Moose::Meta::Role - The Moose Role metaclass |
600 | |
601 | =head1 DESCRIPTION |
602 | |
d44714be |
603 | Please see L<Moose::Role> for more information about roles. |
604 | For the most part, this has no user-serviceable parts inside |
605 | this module. It's API is still subject to some change (although |
02a0fb52 |
606 | probably not that much really). |
79592a54 |
607 | |
e185c027 |
608 | =head1 METHODS |
609 | |
610 | =over 4 |
611 | |
612 | =item B<meta> |
613 | |
614 | =item B<new> |
615 | |
78cd1d3b |
616 | =item B<apply> |
617 | |
db1ab48d |
618 | =item B<combine> |
619 | |
e185c027 |
620 | =back |
621 | |
622 | =over 4 |
623 | |
624 | =item B<name> |
625 | |
626 | =item B<version> |
627 | |
628 | =item B<role_meta> |
629 | |
630 | =back |
631 | |
632 | =over 4 |
633 | |
80572233 |
634 | =item B<get_roles> |
635 | |
636 | =item B<add_role> |
637 | |
638 | =item B<does_role> |
639 | |
640 | =back |
641 | |
642 | =over 4 |
643 | |
d79e62fd |
644 | =item B<add_excluded_roles> |
645 | |
646 | =item B<excludes_role> |
647 | |
648 | =item B<get_excluded_roles_list> |
649 | |
650 | =item B<get_excluded_roles_map> |
651 | |
2b14ac61 |
652 | =item B<calculate_all_roles> |
653 | |
d79e62fd |
654 | =back |
655 | |
656 | =over 4 |
657 | |
68efb014 |
658 | =item B<method_metaclass> |
659 | |
be4427d0 |
660 | =item B<find_method_by_name> |
661 | |
e185c027 |
662 | =item B<get_method> |
663 | |
664 | =item B<has_method> |
665 | |
bdabd620 |
666 | =item B<alias_method> |
667 | |
e185c027 |
668 | =item B<get_method_list> |
669 | |
093b12c2 |
670 | =item B<get_method_map> |
671 | |
638853cb |
672 | =item B<update_package_cache_flag> |
673 | |
53dd42d8 |
674 | =item B<reset_package_cache_flag> |
675 | |
e185c027 |
676 | =back |
677 | |
678 | =over 4 |
679 | |
680 | =item B<add_attribute> |
681 | |
682 | =item B<has_attribute> |
683 | |
684 | =item B<get_attribute> |
685 | |
686 | =item B<get_attribute_list> |
687 | |
688 | =item B<get_attribute_map> |
689 | |
690 | =item B<remove_attribute> |
691 | |
692 | =back |
693 | |
694 | =over 4 |
695 | |
1331430a |
696 | =item B<add_required_methods> |
697 | |
38f1204c |
698 | =item B<remove_required_methods> |
699 | |
1331430a |
700 | =item B<get_required_method_list> |
701 | |
702 | =item B<get_required_methods_map> |
703 | |
704 | =item B<requires_method> |
705 | |
706 | =back |
707 | |
0558683c |
708 | =over 4 |
709 | |
710 | =item B<add_after_method_modifier> |
711 | |
712 | =item B<add_around_method_modifier> |
713 | |
714 | =item B<add_before_method_modifier> |
715 | |
716 | =item B<add_override_method_modifier> |
717 | |
718 | =over 4 |
719 | |
720 | =back |
721 | |
722 | =item B<has_after_method_modifiers> |
723 | |
724 | =item B<has_around_method_modifiers> |
725 | |
726 | =item B<has_before_method_modifiers> |
727 | |
728 | =item B<has_override_method_modifier> |
729 | |
730 | =over 4 |
731 | |
732 | =back |
733 | |
734 | =item B<get_after_method_modifiers> |
735 | |
736 | =item B<get_around_method_modifiers> |
737 | |
738 | =item B<get_before_method_modifiers> |
739 | |
740 | =item B<get_method_modifier_list> |
741 | |
742 | =over 4 |
743 | |
744 | =back |
745 | |
746 | =item B<get_override_method_modifier> |
747 | |
748 | =item B<get_after_method_modifiers_map> |
749 | |
750 | =item B<get_around_method_modifiers_map> |
751 | |
752 | =item B<get_before_method_modifiers_map> |
753 | |
754 | =item B<get_override_method_modifiers_map> |
755 | |
756 | =back |
757 | |
e185c027 |
758 | =head1 BUGS |
759 | |
760 | All complex software has bugs lurking in it, and this module is no |
761 | exception. If you find a bug please either email me, or add the bug |
762 | to cpan-RT. |
763 | |
764 | =head1 AUTHOR |
765 | |
766 | Stevan Little E<lt>stevan@iinteractive.comE<gt> |
767 | |
768 | =head1 COPYRIGHT AND LICENSE |
769 | |
b77fdbed |
770 | Copyright 2006, 2007 by Infinity Interactive, Inc. |
e185c027 |
771 | |
772 | L<http://www.iinteractive.com> |
773 | |
774 | This library is free software; you can redistribute it and/or modify |
775 | it under the same terms as Perl itself. |
776 | |
b8aeb4dc |
777 | =cut |