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