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