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   18891 use Mouse::Util qw(:meta);
  82         265  
  82         673  
3              
4             sub new {
5 352     352 0 4353 my $class = shift;
6 352         4912 my $args = $class->Mouse::Object::BUILDARGS(@_);
7              
8 352 50 33     5450 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         4085 $args->{aliased_methods} = {};
22 352 100       4584 if(my $alias = $args->{-alias}){
23 30         61 @{$args->{aliased_methods}}{ values %{$alias} } = ();
  30         112  
  30         86  
24             }
25              
26 352 100       4351 if(my $excludes = $args->{-excludes}){
27 24         60 $args->{-excludes} = {}; # replace with a hash ref
28 24 100       68 if(ref $excludes){
29 13         27 %{$args->{-excludes}} = (map{ $_ => undef } @{$excludes});
  13         47  
  25         63  
  13         30  
30             }
31             else{
32 11         28 $args->{-excludes}{$excludes} = undef;
33             }
34             }
35 352         4003 my $self = bless $args, $class;
36 352 100       4303 if($class ne __PACKAGE__){
37 50         921 $self->meta->_initialize_object($self, $args);
38             }
39 352         7868 return $self;
40             }
41              
42             sub apply {
43 352     352 0 4298 my($self, $role, $consumer, @extra) = @_;
44 352         4002 my $instance;
45              
46 352 100       5880 if(Mouse::Util::is_a_metaclass($consumer)) { # Application::ToClass
    100          
47 169         2001 $self->{_to} = 'class';
48             }
49             elsif(Mouse::Util::is_a_metarole($consumer)) { # Application::ToRole
50 159         4614 $self->{_to} = 'role';
51             }
52             else { # Appplication::ToInstance
53 24         741 $self->{_to} = 'instance';
54 24         661 $instance = $consumer;
55              
56 24         767 my $meta = Mouse::Util::class_of($instance);
57 24   100     831 $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         4707 $self->check_required_methods($role, $consumer, @extra);
69             #$self->check_required_attributes($role, $consumer, @extra);
70              
71 344         4497 $self->apply_attributes($role, $consumer, @extra);
72 342         4364 $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         4361 $self->apply_modifiers($role, $consumer, @extra);
78              
79 331         4446 $self->_append_roles($role, $consumer);
80              
81 331 100       6371 if(defined $instance){ # Application::ToInstance
82             # rebless instance
83 23         683 bless $instance, $consumer->name;
84 23         828 $consumer->_initialize_object($instance, $instance, 1);
85             }
86              
87 331         12804 return;
88             }
89              
90             sub check_required_methods {
91 351     351 0 4116 my($self, $role, $consumer) = @_;
92              
93 351 100       4290 if($self->{_to} eq 'role'){
94 159         2695 $consumer->add_required_methods($role->get_required_method_list);
95             }
96             else{ # to class or instance
97 192         2068 my $consumer_class_name = $consumer->name;
98              
99 192         1590 my @missing;
100 192         1562 foreach my $method_name(@{$role->{required_methods}}){
  192         3148  
101 60 100       172 next if exists $self->{aliased_methods}{$method_name};
102 58 100       190 next if exists $role->{methods}{$method_name};
103 38 100       266 next if $consumer_class_name->can($method_name);
104              
105 14         29 push @missing, $method_name;
106             }
107 192 100       3335 if(@missing){
108 7 100       40 $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         7246 return;
117             }
118              
119             sub apply_methods {
120 338     338 0 3790 my($self, $role, $consumer) = @_;
121              
122 338         3894 my $alias = $self->{-alias};
123 338         3936 my $excludes = $self->{-excludes};
124              
125 338         4709 foreach my $method_name($role->get_method_list){
126 691 100       10279 next if $method_name eq 'meta';
127              
128 355         2554 my $code = $role->get_method_body($method_name);
129              
130 355 100       2596 if(!exists $excludes->{$method_name}){
131 319 100       2488 if(!$consumer->has_method($method_name)){
132             # The third argument $role is used in Role::Composite
133 307         6230 $consumer->add_method($method_name => $code, $role);
134             }
135             }
136              
137 355 100       2626 if(exists $alias->{$method_name}){
138 34         71 my $dstname = $alias->{$method_name};
139              
140 34         108 my $dstcode = $consumer->get_method_body($dstname);
141              
142 34 100 66     127 if(defined($dstcode) && $dstcode != $code){
143 4         19 $role->throw_error("Cannot create a method alias if a local method of the same name exists");
144             }
145             else{
146 30         207 $consumer->add_method($dstname => $code, $role);
147             }
148             }
149             }
150              
151 334         7206 return;
152             }
153              
154             sub apply_attributes {
155 344     344 0 4406 my($self, $role, $consumer) = @_;
156              
157 344         4695 for my $attr_name ($role->get_attribute_list) {
158 112 100       469 next if $consumer->has_attribute($attr_name);
159              
160 109         440 $consumer->add_attribute($attr_name
161             => $role->get_attribute($attr_name));
162             }
163 342         7008 return;
164             }
165              
166             sub apply_modifiers {
167 334     334 0 3910 my($self, $role, $consumer) = @_;
168              
169 334 100       4373 if(my $modifiers = $role->{override_method_modifiers}){
170 16         25 foreach my $method_name (keys %{$modifiers}){
  16         49  
171             $consumer->add_override_method_modifier(
172 18         72 $method_name => $modifiers->{$method_name});
173             }
174             }
175              
176 331         4244 for my $modifier_type (qw/before around after/) {
177 993 100       22184 my $table = $role->{"${modifier_type}_method_modifiers"}
178             or next;
179              
180 53         130 my $add_modifier = "add_${modifier_type}_method_modifier";
181              
182 53         110 while(my($method_name, $modifiers) = each %{$table}){
  106         452  
183 53         101 foreach my $code(@{ $modifiers }) {
  53         118  
184             # skip if the modifier is already applied
185 55 100       366 next if $consumer->{"_applied_$modifier_type"}{$method_name, $code}++;
186 54         367 $consumer->$add_modifier($method_name => $code);
187             }
188             }
189             }
190 331         7383 return;
191             }
192              
193             sub _append_roles {
194 331     331   4085 my($self, $role, $metaclass_or_role) = @_;
195              
196 331         3833 my $roles = $metaclass_or_role->{roles};
197 331         3740 foreach my $r($role, @{$role->get_roles}){
  331         7745  
198 463 100       5075 if(!$metaclass_or_role->does_role($r)){
199 326         3713 push @{$roles}, $r;
  326         12821  
200             }
201             }
202 331         6852 return;
203             }
204             1;
205             __END__