1 package Mouse::Meta::Role;
2 use Mouse::Util qw(:meta not_supported english_list); # enables strict and warnings
4 use Mouse::Meta::Module;
5 our @ISA = qw(Mouse::Meta::Module);
7 sub method_metaclass(){ 'Mouse::Meta::Role::Method' } # required for get_method()
15 $args{attributes} = {};
16 $args{required_methods} = [];
19 my $self = bless \%args, ref($class) || $class;
20 if($class ne __PACKAGE__){
21 $self->meta->_initialize_object($self, \%args);
29 return $self->create(undef, @_);
36 sub calculate_all_roles {
39 return grep { !$seen{ $_->name }++ }
40 ($self, map { $_->calculate_all_roles } @{ $self->get_roles });
43 sub get_required_method_list{
44 return @{ $_[0]->{required_methods} };
47 sub add_required_methods {
48 my($self, @methods) = @_;
49 my %required = map{ $_ => 1 } @{$self->{required_methods}};
50 push @{$self->{required_methods}}, grep{ !$required{$_}++ && !$self->has_method($_) } @methods;
55 my($self, $name) = @_;
56 return scalar( grep{ $_ eq $name } @{ $self->{required_methods} } ) != 0;
63 $self->{attributes}->{$name} = (@_ == 1) ? $_[0] : { @_ };
67 sub _check_required_methods{
68 my($role, $applicant, $args) = @_;
70 if($args->{_to} eq 'role'){
71 $applicant->add_required_methods($role->get_required_method_list);
73 else{ # to class or instance
74 my $applicant_class_name = $applicant->name;
77 foreach my $method_name(@{$role->{required_methods}}){
78 next if exists $args->{aliased_methods}{$method_name};
79 next if exists $role->{methods}{$method_name};
80 next if $applicant_class_name->can($method_name);
82 push @missing, $method_name;
85 $role->throw_error(sprintf "'%s' requires the method%s %s to be implemented by '%s'",
87 (@missing == 1 ? '' : 's'), # method or methods
88 english_list(map{ sprintf q{'%s'}, $_ } @missing),
89 $applicant_class_name);
97 my($role, $applicant, $args) = @_;
99 my $alias = $args->{-alias};
100 my $excludes = $args->{-excludes};
102 foreach my $method_name($role->get_method_list){
103 next if $method_name eq 'meta';
105 my $code = $role->get_method_body($method_name);
107 if(!exists $excludes->{$method_name}){
108 if(!$applicant->has_method($method_name)){
109 # The third argument $role is used in Role::Composite
110 $applicant->add_method($method_name => $code, $role);
114 if(exists $alias->{$method_name}){
115 my $dstname = $alias->{$method_name};
117 my $dstcode = $applicant->get_method_body($dstname);
119 if(defined($dstcode) && $dstcode != $code){
120 $role->throw_error("Cannot create a method alias if a local method of the same name exists");
123 $applicant->add_method($dstname => $code, $role);
131 sub _apply_attributes{
132 my($role, $applicant, $args) = @_;
134 for my $attr_name ($role->get_attribute_list) {
135 next if $applicant->has_attribute($attr_name);
137 $applicant->add_attribute($attr_name => $role->get_attribute($attr_name));
142 sub _apply_modifiers{
143 my($role, $applicant, $args) = @_;
145 if(my $modifiers = $role->{override_method_modifiers}){
146 foreach my $method_name (keys %{$modifiers}){
147 $applicant->add_override_method_modifier($method_name => $modifiers->{$method_name});
151 for my $modifier_type (qw/before around after/) {
152 my $modifiers = $role->{"${modifier_type}_method_modifiers"}
155 my $add_modifier = "add_${modifier_type}_method_modifier";
157 foreach my $method_name (keys %{$modifiers}){
158 foreach my $code(@{ $modifiers->{$method_name} }){
159 next if $applicant->{"_applied_$modifier_type"}{$method_name, $code}++; # skip applied modifiers
160 $applicant->$add_modifier($method_name => $code);
168 my($role, $applicant, $args) = @_;
170 my $roles = ($args->{_to} eq 'role') ? $applicant->get_roles : $applicant->roles;
172 foreach my $r($role, @{$role->get_roles}){
173 if(!$applicant->does_role($r->name)){
180 # Moose uses Application::ToInstance, Application::ToClass, Application::ToRole
183 my $applicant = shift;
185 my %args = (@_ == 1) ? %{ $_[0] } : @_;
189 if(Mouse::Util::is_a_metaclass($applicant)){ # Application::ToClass
190 $args{_to} = 'class';
192 elsif(Mouse::Util::is_a_metarole($applicant)){ # Application::ToRole
195 else{ # Appplication::ToInstance
196 $args{_to} = 'instance';
197 $instance = $applicant;
199 $applicant = (Mouse::Util::class_of($instance) || 'Mouse::Meta::Class')->create_anon_class(
200 superclasses => [ref $instance],
205 if($args{alias} && !exists $args{-alias}){
206 $args{-alias} = $args{alias};
208 if($args{excludes} && !exists $args{-excludes}){
209 $args{-excludes} = $args{excludes};
212 $args{aliased_methods} = {};
213 if(my $alias = $args{-alias}){
214 @{$args{aliased_methods}}{ values %{$alias} } = ();
217 if(my $excludes = $args{-excludes}){
218 $args{-excludes} = {}; # replace with a hash ref
220 %{$args{-excludes}} = (map{ $_ => undef } @{$excludes});
223 $args{-excludes}{$excludes} = undef;
227 $self->_check_required_methods($applicant, \%args);
228 $self->_apply_attributes($applicant, \%args);
229 $self->_apply_methods($applicant, \%args);
230 $self->_apply_modifiers($applicant, \%args);
231 $self->_append_roles($applicant, \%args);
234 if(defined $instance){ # Application::ToInstance
236 bless $instance, $applicant->name;
237 $applicant->_initialize_object($instance, $instance);
245 my($role_class, @role_specs) = @_;
247 require 'Mouse/Meta/Role/Composite.pm'; # we don't want to create its namespace
249 my $composite = Mouse::Meta::Role::Composite->create_anon_role();
251 foreach my $role_spec (@role_specs) {
252 my($role_name, $args) = @{$role_spec};
253 $role_name->meta->apply($composite, %{$args});
258 sub add_before_method_modifier {
259 my ($self, $method_name, $method) = @_;
261 push @{ $self->{before_method_modifiers}{$method_name} ||= [] }, $method;
264 sub add_around_method_modifier {
265 my ($self, $method_name, $method) = @_;
267 push @{ $self->{around_method_modifiers}{$method_name} ||= [] }, $method;
270 sub add_after_method_modifier {
271 my ($self, $method_name, $method) = @_;
273 push @{ $self->{after_method_modifiers}{$method_name} ||= [] }, $method;
277 sub get_before_method_modifiers {
278 my ($self, $method_name) = @_;
279 return @{ $self->{before_method_modifiers}{$method_name} ||= [] }
281 sub get_around_method_modifiers {
282 my ($self, $method_name) = @_;
283 return @{ $self->{around_method_modifiers}{$method_name} ||= [] }
285 sub get_after_method_modifiers {
286 my ($self, $method_name) = @_;
287 return @{ $self->{after_method_modifiers}{$method_name} ||= [] }
290 sub add_override_method_modifier{
291 my($self, $method_name, $method) = @_;
293 if($self->has_method($method_name)){
294 # This error happens in the override keyword or during role composition,
295 # so I added a message, "A local method of ...", only for compatibility (gfx)
296 $self->throw_error("Cannot add an override of method '$method_name' "
297 . "because there is a local version of '$method_name'"
298 . "(A local method of the same name as been found)");
301 $self->{override_method_modifiers}->{$method_name} = $method;
304 sub get_override_method_modifier {
305 my ($self, $method_name) = @_;
306 return $self->{override_method_modifiers}->{$method_name};
310 my ($self, $role_name) = @_;
313 || $self->throw_error("You must supply a role name to look for");
315 # if we are it,.. then return true
316 return 1 if $role_name eq $self->name;
317 # otherwise.. check our children
318 for my $role (@{ $self->get_roles }) {
319 return 1 if $role->does_role($role_name);
329 Mouse::Meta::Role - The Mouse Role metaclass
333 This document describes Mouse version 0.40_05