1 package Mouse::Meta::Role;
2 use Mouse::Util qw(:meta not_supported); # enables strict and warnings
4 use Mouse::Meta::Module;
5 our @ISA = qw(Mouse::Meta::Module);
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, $consumer, $args) = @_;
70 if($args->{_to} eq 'role'){
71 $consumer->add_required_methods($role->get_required_method_list);
73 else{ # to class or instance
74 my $consumer_class_name = $consumer->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 $consumer_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 Mouse::Util::quoted_english_list(@missing),
89 $consumer_class_name);
97 my($role, $consumer, $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(!$consumer->has_method($method_name)){
109 # The third argument $role is used in Role::Composite
110 $consumer->add_method($method_name => $code, $role);
114 if(exists $alias->{$method_name}){
115 my $dstname = $alias->{$method_name};
117 my $dstcode = $consumer->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 $consumer->add_method($dstname => $code, $role);
131 sub _apply_attributes{
132 #my($role, $consumer, $args) = @_;
133 my($role, $consumer) = @_;
135 for my $attr_name ($role->get_attribute_list) {
136 next if $consumer->has_attribute($attr_name);
138 $consumer->add_attribute($attr_name => $role->get_attribute($attr_name));
143 sub _apply_modifiers{
144 #my($role, $consumer, $args) = @_;
145 my($role, $consumer) = @_;
148 if(my $modifiers = $role->{override_method_modifiers}){
149 foreach my $method_name (keys %{$modifiers}){
150 $consumer->add_override_method_modifier($method_name => $modifiers->{$method_name});
154 for my $modifier_type (qw/before around after/) {
155 my $table = $role->{"${modifier_type}_method_modifiers"}
158 my $add_modifier = "add_${modifier_type}_method_modifier";
160 while(my($method_name, $modifiers) = each %{$table}){
161 foreach my $code(@{ $modifiers }){
162 next if $consumer->{"_applied_$modifier_type"}{$method_name, $code}++; # skip applied modifiers
163 $consumer->$add_modifier($method_name => $code);
171 #my($role, $consumer, $args) = @_;
172 my($role, $consumer) = @_;
174 my $roles = $consumer->{roles};
176 foreach my $r($role, @{$role->get_roles}){
177 if(!$consumer->does_role($r)){
184 # Moose uses Application::ToInstance, Application::ToClass, Application::ToRole
187 my $consumer = shift;
189 my %args = (@_ == 1) ? %{ $_[0] } : @_;
193 if(Mouse::Util::is_a_metaclass($consumer)){ # Application::ToClass
194 $args{_to} = 'class';
196 elsif(Mouse::Util::is_a_metarole($consumer)){ # Application::ToRole
199 else{ # Appplication::ToInstance
200 $args{_to} = 'instance';
201 $instance = $consumer;
203 $consumer = (Mouse::Util::class_of($instance) || 'Mouse::Meta::Class')->create_anon_class(
204 superclasses => [ref $instance],
209 if($args{alias} && !exists $args{-alias}){
210 $args{-alias} = $args{alias};
212 if($args{excludes} && !exists $args{-excludes}){
213 $args{-excludes} = $args{excludes};
216 $args{aliased_methods} = {};
217 if(my $alias = $args{-alias}){
218 @{$args{aliased_methods}}{ values %{$alias} } = ();
221 if(my $excludes = $args{-excludes}){
222 $args{-excludes} = {}; # replace with a hash ref
224 %{$args{-excludes}} = (map{ $_ => undef } @{$excludes});
227 $args{-excludes}{$excludes} = undef;
231 $self->_check_required_methods($consumer, \%args);
232 $self->_apply_attributes($consumer, \%args);
233 $self->_apply_methods($consumer, \%args);
234 $self->_apply_modifiers($consumer, \%args);
235 $self->_append_roles($consumer, \%args);
238 if(defined $instance){ # Application::ToInstance
240 bless $instance, $consumer->name;
241 $consumer->_initialize_object($instance, $instance);
249 my($self, @role_specs) = @_;
251 require 'Mouse/Meta/Role/Composite.pm'; # we don't want to create its namespace
253 my $composite = Mouse::Meta::Role::Composite->create_anon_role();
255 foreach my $role_spec (@role_specs) {
256 my($role_name, $args) = @{$role_spec};
257 $role_name->meta->apply($composite, %{$args});
262 sub add_before_method_modifier;
263 sub add_around_method_modifier;
264 sub add_after_method_modifier;
266 sub get_before_method_modifiers;
267 sub get_around_method_modifiers;
268 sub get_after_method_modifiers;
270 sub add_override_method_modifier{
271 my($self, $method_name, $method) = @_;
273 if($self->has_method($method_name)){
274 # This error happens in the override keyword or during role composition,
275 # so I added a message, "A local method of ...", only for compatibility (gfx)
276 $self->throw_error("Cannot add an override of method '$method_name' "
277 . "because there is a local version of '$method_name'"
278 . "(A local method of the same name as been found)");
281 $self->{override_method_modifiers}->{$method_name} = $method;
284 sub get_override_method_modifier {
285 my ($self, $method_name) = @_;
286 return $self->{override_method_modifiers}->{$method_name};
290 my ($self, $role_name) = @_;
293 || $self->throw_error("You must supply a role name to look for");
295 $role_name = $role_name->name if ref $role_name;
297 # if we are it,.. then return true
298 return 1 if $role_name eq $self->name;
299 # otherwise.. check our children
300 for my $role (@{ $self->get_roles }) {
301 return 1 if $role->does_role($role_name);
311 Mouse::Meta::Role - The Mouse Role metaclass
315 This document describes Mouse version 0.50_09