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   8442 use Mouse::Util qw(:meta);
  82         91  
  82         558  
3              
4             sub new {
5 352     352 0 4286 my $class = shift;
6 352         4588 my $args = $class->Mouse::Object::BUILDARGS(@_);
7              
8 352 50 33     4775 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         4100 $args->{aliased_methods} = {};
22 352 100       4422 if(my $alias = $args->{-alias}){
23 30         23 @{$args->{aliased_methods}}{ values %{$alias} } = ();
  30         55  
  30         54  
24             }
25              
26 352 100       4245 if(my $excludes = $args->{-excludes}){
27 24         34 $args->{-excludes} = {}; # replace with a hash ref
28 24 100       41 if(ref $excludes){
29 13         10 %{$args->{-excludes}} = (map{ $_ => undef } @{$excludes});
  13         32  
  25         34  
  13         20  
30             }
31             else{
32 11         19 $args->{-excludes}{$excludes} = undef;
33             }
34             }
35 352         4002 my $self = bless $args, $class;
36 352 100       4127 if($class ne __PACKAGE__){
37 50         879 $self->meta->_initialize_object($self, $args);
38             }
39 352         7969 return $self;
40             }
41              
42             sub apply {
43 352     352 0 4158 my($self, $role, $consumer, @extra) = @_;
44 352         3876 my $instance;
45              
46 352 100       5896 if(Mouse::Util::is_a_metaclass($consumer)) { # Application::ToClass
    100          
47 169         1814 $self->{_to} = 'class';
48             }
49             elsif(Mouse::Util::is_a_metarole($consumer)) { # Application::ToRole
50 159         4638 $self->{_to} = 'role';
51             }
52             else { # Appplication::ToInstance
53 24         793 $self->{_to} = 'instance';
54 24         738 $instance = $consumer;
55              
56 24         784 my $meta = Mouse::Util::class_of($instance);
57 24   100     881 $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         4242 $self->check_required_methods($role, $consumer, @extra);
69             #$self->check_required_attributes($role, $consumer, @extra);
70              
71 344         4142 $self->apply_attributes($role, $consumer, @extra);
72 342         4091 $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         4239 $self->apply_modifiers($role, $consumer, @extra);
78              
79 331         4160 $self->_append_roles($role, $consumer);
80              
81 331 100       4344 if(defined $instance){ # Application::ToInstance
82             # rebless instance
83 23         878 bless $instance, $consumer->name;
84 23         885 $consumer->_initialize_object($instance, $instance, 1);
85             }
86              
87 331         13044 return;
88             }
89              
90             sub check_required_methods {
91 351     351 0 3915 my($self, $role, $consumer) = @_;
92              
93 351 100       4243 if($self->{_to} eq 'role'){
94 159         2533 $consumer->add_required_methods($role->get_required_method_list);
95             }
96             else{ # to class or instance
97 192         2019 my $consumer_class_name = $consumer->name;
98              
99 192         1584 my @missing;
100 192         1597 foreach my $method_name(@{$role->{required_methods}}){
  192         3344  
101 60 100       118 next if exists $self->{aliased_methods}{$method_name};
102 58 100       91 next if exists $role->{methods}{$method_name};
103 38 100       223 next if $consumer_class_name->can($method_name);
104              
105 14         17 push @missing, $method_name;
106             }
107 192 100       3258 if(@missing){
108 7 100       27 $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         7586 return;
117             }
118              
119             sub apply_methods {
120 338     338 0 3873 my($self, $role, $consumer) = @_;
121              
122 338         4019 my $alias = $self->{-alias};
123 338         3979 my $excludes = $self->{-excludes};
124              
125 338         4460 foreach my $method_name($role->get_method_list){
126 685 100       9880 next if $method_name eq 'meta';
127              
128 351         2129 my $code = $role->get_method_body($method_name);
129              
130 351 100       1964 if(!exists $excludes->{$method_name}){
131 315 100       2002 if(!$consumer->has_method($method_name)){
132             # The third argument $role is used in Role::Composite
133 303         5568 $consumer->add_method($method_name => $code, $role);
134             }
135             }
136              
137 351 100       3532 if(exists $alias->{$method_name}){
138 34         42 my $dstname = $alias->{$method_name};
139              
140 34         69 my $dstcode = $consumer->get_method_body($dstname);
141              
142 34 100 66     97 if(defined($dstcode) && $dstcode != $code){
143 4         9 $role->throw_error("Cannot create a method alias if a local method of the same name exists");
144             }
145             else{
146 30         159 $consumer->add_method($dstname => $code, $role);
147             }
148             }
149             }
150              
151 334         7840 return;
152             }
153              
154             sub apply_attributes {
155 344     344 0 4006 my($self, $role, $consumer) = @_;
156              
157 344         4661 for my $attr_name ($role->get_attribute_list) {
158 112 100       331 next if $consumer->has_attribute($attr_name);
159              
160 109         316 $consumer->add_attribute($attr_name
161             => $role->get_attribute($attr_name));
162             }
163 342         7509 return;
164             }
165              
166             sub apply_modifiers {
167 334     334 0 3915 my($self, $role, $consumer) = @_;
168              
169 334 100       4262 if(my $modifiers = $role->{override_method_modifiers}){
170 16         16 foreach my $method_name (keys %{$modifiers}){
  16         43  
171             $consumer->add_override_method_modifier(
172 18         48 $method_name => $modifiers->{$method_name});
173             }
174             }
175              
176 331         3961 for my $modifier_type (qw/before around after/) {
177 993 100       23381 my $table = $role->{"${modifier_type}_method_modifiers"}
178             or next;
179              
180 53         76 my $add_modifier = "add_${modifier_type}_method_modifier";
181              
182 53         59 while(my($method_name, $modifiers) = each %{$table}){
  106         291  
183 53         44 foreach my $code(@{ $modifiers }) {
  53         62  
184             # skip if the modifier is already applied
185 55 100       279 next if $consumer->{"_applied_$modifier_type"}{$method_name, $code}++;
186 54         264 $consumer->$add_modifier($method_name => $code);
187             }
188             }
189             }
190 331         7455 return;
191             }
192              
193             sub _append_roles {
194 331     331   3881 my($self, $role, $metaclass_or_role) = @_;
195              
196 331         3885 my $roles = $metaclass_or_role->{roles};
197 331         3875 foreach my $r($role, @{$role->get_roles}){
  331         8106  
198 462 100       4669 if(!$metaclass_or_role->does_role($r)){
199 325         3842 push @{$roles}, $r;
  325         14028  
200             }
201             }
202 331         7877 return;
203             }
204             1;
205             __END__