File Coverage

blib/lib/Mouse/Meta/Role/Application.pm
Criterion Covered Total %
statement 99 104 95.1
branch 47 52 90.3
condition 5 14 35.7
subroutine 8 8 100.0
pod 0 6 0.0
total 159 184 86.4


line stmt bran cond sub pod time code
1             package Mouse::Meta::Role::Application;
2 82     82   9040 use Mouse::Util qw(:meta);
  82         92  
  82         570  
3              
4             sub new {
5 352     352 0 4248 my $class = shift;
6 352         4631 my $args = $class->Mouse::Object::BUILDARGS(@_);
7              
8 352 50 33     4928 if(exists $args->{exclude} or exists $args->{alias}) {
9 0         0 warnings::warnif(deprecated =>
10             'The alias and excludes options for role application have been'
11             . ' renamed -alias and -exclude');
12              
13 0 0 0     0 if($args->{alias} && !exists $args->{-alias}){
14 0         0 $args->{-alias} = $args->{alias};
15             }
16 0 0 0     0 if($args->{excludes} && !exists $args->{-excludes}){
17 0         0 $args->{-excludes} = $args->{excludes};
18             }
19             }
20              
21 352         4075 $args->{aliased_methods} = {};
22 352 100       4438 if(my $alias = $args->{-alias}){
23 30         25 @{$args->{aliased_methods}}{ values %{$alias} } = ();
  30         63  
  30         55  
24             }
25              
26 352 100       4179 if(my $excludes = $args->{-excludes}){
27 24         40 $args->{-excludes} = {}; # replace with a hash ref
28 24 100       49 if(ref $excludes){
29 13         9 %{$args->{-excludes}} = (map{ $_ => undef } @{$excludes});
  13         34  
  25         35  
  13         20  
30             }
31             else{
32 11         21 $args->{-excludes}{$excludes} = undef;
33             }
34             }
35 352         3974 my $self = bless $args, $class;
36 352 100       4189 if($class ne __PACKAGE__){
37 50         875 $self->meta->_initialize_object($self, $args);
38             }
39 352         8019 return $self;
40             }
41              
42             sub apply {
43 352     352 0 4013 my($self, $role, $consumer, @extra) = @_;
44 352         3907 my $instance;
45              
46 352 100       5287 if(Mouse::Util::is_a_metaclass($consumer)) { # Application::ToClass
    100          
47 169         1985 $self->{_to} = 'class';
48             }
49             elsif(Mouse::Util::is_a_metarole($consumer)) { # Application::ToRole
50 159         4506 $self->{_to} = 'role';
51             }
52             else { # Appplication::ToInstance
53 24         760 $self->{_to} = 'instance';
54 24         714 $instance = $consumer;
55              
56 24         803 my $meta = Mouse::Util::class_of($instance);
57 24   100     838 $consumer = ($meta || 'Mouse::Meta::Class')
58             ->create_anon_class(
59             superclasses => [ref $instance],
60             roles => [$role],
61             cache => 0,
62              
63             in_application_to_instance => 1, # suppress to apply roles
64             );
65             }
66              
67             #$self->check_role_exclusions($role, $consumer, @extra);
68 351         4166 $self->check_required_methods($role, $consumer, @extra);
69             #$self->check_required_attributes($role, $consumer, @extra);
70              
71 344         4021 $self->apply_attributes($role, $consumer, @extra);
72 342         4214 $self->apply_methods($role, $consumer, @extra);
73             #$self->apply_override_method_modifiers($role, $consumer, @extra);
74             #$self->apply_before_method_modifiers($role, $consumer, @extra);
75             #$self->apply_around_method_modifiers($role, $consumer, @extra);
76             #$self->apply_after_method_modifiers($role, $consumer, @extra);
77 334         4187 $self->apply_modifiers($role, $consumer, @extra);
78              
79 331         4097 $self->_append_roles($role, $consumer);
80              
81 331 100       4043 if(defined $instance){ # Application::ToInstance
82             # rebless instance
83 23         775 bless $instance, $consumer->name;
84 23         861 $consumer->_initialize_object($instance, $instance, 1);
85             }
86              
87 331         13009 return;
88             }
89              
90             sub check_required_methods {
91 351     351 0 3926 my($self, $role, $consumer) = @_;
92              
93 351 100       4199 if($self->{_to} eq 'role'){
94 159         2468 $consumer->add_required_methods($role->get_required_method_list);
95             }
96             else{ # to class or instance
97 192         2023 my $consumer_class_name = $consumer->name;
98              
99 192         1677 my @missing;
100 192         1605 foreach my $method_name(@{$role->{required_methods}}){
  192         3316  
101 60 100       116 next if exists $self->{aliased_methods}{$method_name};
102 58 100       93 next if exists $role->{methods}{$method_name};
103 38 100       225 next if $consumer_class_name->can($method_name);
104              
105 14         16 push @missing, $method_name;
106             }
107 192 100       3589 if(@missing){
108 7 100       30 $role->throw_error(sprintf "'%s' requires the method%s %s to be implemented by '%s'",
109             $role->name,
110             (@missing == 1 ? '' : 's'), # method or methods
111             Mouse::Util::quoted_english_list(@missing),
112             $consumer_class_name);
113             }
114             }
115              
116 344         7512 return;
117             }
118              
119             sub apply_methods {
120 338     338 0 4125 my($self, $role, $consumer) = @_;
121              
122 338         3997 my $alias = $self->{-alias};
123 338         3871 my $excludes = $self->{-excludes};
124              
125 338         4502 foreach my $method_name($role->get_method_list){
126 689 100       10237 next if $method_name eq 'meta';
127              
128 353         2167 my $code = $role->get_method_body($method_name);
129              
130 353 100       2138 if(!exists $excludes->{$method_name}){
131 317 100       2103 if(!$consumer->has_method($method_name)){
132             # The third argument $role is used in Role::Composite
133 305         5767 $consumer->add_method($method_name => $code, $role);
134             }
135             }
136              
137 353 100       2273 if(exists $alias->{$method_name}){
138 34         39 my $dstname = $alias->{$method_name};
139              
140 34         74 my $dstcode = $consumer->get_method_body($dstname);
141              
142 34 100 66     102 if(defined($dstcode) && $dstcode != $code){
143 4         13 $role->throw_error("Cannot create a method alias if a local method of the same name exists");
144             }
145             else{
146 30         164 $consumer->add_method($dstname => $code, $role);
147             }
148             }
149             }
150              
151 334         7880 return;
152             }
153              
154             sub apply_attributes {
155 344     344 0 3854 my($self, $role, $consumer) = @_;
156              
157 344         4578 for my $attr_name ($role->get_attribute_list) {
158 112 100       287 next if $consumer->has_attribute($attr_name);
159              
160 109         290 $consumer->add_attribute($attr_name
161             => $role->get_attribute($attr_name));
162             }
163 342         7406 return;
164             }
165              
166             sub apply_modifiers {
167 334     334 0 3886 my($self, $role, $consumer) = @_;
168              
169 334 100       4187 if(my $modifiers = $role->{override_method_modifiers}){
170 16         16 foreach my $method_name (keys %{$modifiers}){
  16         28  
171             $consumer->add_override_method_modifier(
172 18         42 $method_name => $modifiers->{$method_name});
173             }
174             }
175              
176 331         3917 for my $modifier_type (qw/before around after/) {
177 993 100       23521 my $table = $role->{"${modifier_type}_method_modifiers"}
178             or next;
179              
180 53         85 my $add_modifier = "add_${modifier_type}_method_modifier";
181              
182 53         48 while(my($method_name, $modifiers) = each %{$table}){
  106         281  
183 53         41 foreach my $code(@{ $modifiers }) {
  53         62  
184             # skip if the modifier is already applied
185 55 100       274 next if $consumer->{"_applied_$modifier_type"}{$method_name, $code}++;
186 54         264 $consumer->$add_modifier($method_name => $code);
187             }
188             }
189             }
190 331         7461 return;
191             }
192              
193             sub _append_roles {
194 331     331   3810 my($self, $role, $metaclass_or_role) = @_;
195              
196 331         3934 my $roles = $metaclass_or_role->{roles};
197 331         3847 foreach my $r($role, @{$role->get_roles}){
  331         8199  
198 463 100       4629 if(!$metaclass_or_role->does_role($r)){
199 326         3813 push @{$roles}, $r;
  326         14163  
200             }
201             }
202 331         7522 return;
203             }
204             1;
205             __END__