File Coverage

blib/lib/Mite/Trait/HasRoles.pm
Criterion Covered Total %
statement 88 99 88.8
branch 15 26 57.6
condition 6 11 54.5
subroutine 16 17 94.1
pod 0 5 0.0
total 125 158 79.1


line stmt bran cond sub pod time code
1 108     108   2074 use 5.010001;
  108         436  
2 108     108   576 use strict;
  108         324  
  108         2395  
3 108     108   628 use warnings;
  108         207  
  108         4894  
4              
5             use Mite::Miteception -role, -all;
6 108     108   740  
  108         275  
  108         805  
7             our $AUTHORITY = 'cpan:TOBYINK';
8             our $VERSION = '0.010008';
9              
10             requires qw(
11             source
12             native_methods
13             );
14              
15             has roles =>
16             is => rw,
17             isa => ArrayRef[MiteRole],
18             builder => sub { [] };
19 160     160   437  
20             has role_args =>
21             is => rw,
22             isa => Map[ NonEmptyStr, HashRef|Undef ],
23             builder => sub { {} };
24 162     162   619  
25             my $self = shift;
26              
27 143     143 0 309 my %methods;
28             for my $role ( @{ $self->roles } ) {
29 143         283 my $role_args = $self->role_args->{ $role->name } || {};
30 143         288 my %exported = %{ $role->methods_to_export( $role_args ) };
  143         512  
31 13   100     52 for my $name ( sort keys %exported ) {
32 13         30 if ( defined $methods{$name} and $methods{$name} ne $exported{$name} ) {
  13         64  
33 13         62 croak "Conflict between %s and %s; %s must implement %s\n",
34 13 50 33     38 $methods{$name}, $exported{$name}, $self->name, $name;
35             }
36 0         0 else {
37             $methods{$name} = $exported{$name};
38             }
39 13         38 }
40             }
41              
42             # This package provides a native version of these
43             # methods, so don't import.
44             my %native = %{ $self->native_methods };
45             for my $name ( keys %native ) {
46 143         311 delete $methods{$name};
  143         516  
47 143         458 }
48 57         132  
49             # Never propagate
50             delete $methods{$_} for qw(
51             new
52 143         571 DESTROY
53             DOES
54             does
55             __META__
56             __FINALIZE_APPLICATION__
57             CREATE_CLASS
58             APPLY_TO
59             );
60              
61             return \%methods;
62             }
63 143         473  
64             my ( $self, $role ) = @_;
65              
66             my @attr = sort { $a->_order <=> $b->_order }
67 11     11 0 32 values %{ $role->attributes };
68             for my $attr ( @attr ) {
69 6         24 $self->add_attribute( $attr )
70 11         22 unless $self->attributes->{ $attr->name };
  11         64  
71 11         43 }
72             push @{ $self->roles }, $role;
73 10 100       34  
74             return;
75 11         36 }
  11         72  
76              
77 11         36 my ( $self, @names ) = @_;
78              
79             for my $name ( @names ) {
80             my $role = $self->_get_role( $name );
81 11     11 0 39 $self->add_role( $role );
82             }
83 11         29  
84 11         49 return;
85 11         56 }
86              
87             my ( $self, $role_name ) = ( shift, @_ );
88 11         40  
89             my $project = $self->project;
90              
91             # See if it's already loaded
92 11     11   32 my $role = $project->class($role_name);
93             return $role if $role;
94 11         43  
95             # If not, try to load it
96             eval "require $role_name; 1"
97 11         68 or do {
98 11 100       51 my $file_name = $role_name;
99             if ( my $yuck = $project->_module_fakeout_namespace ) {
100             $file_name =~ s/$yuck\:://g;
101             }
102 2 50       114 $file_name =~ s/::/\//g;
103 0         0 $file_name = "lib/$file_name.pm";
104 0 0       0 $project->_load_file( $file_name );
105 0         0 };
106             if ( $INC{'Role/Tiny.pm'} and 'Role::Tiny'->is_role( $role_name ) ) {
107 0         0 require Mite::Role::Tiny;
108 0         0 $role = 'Mite::Role::Tiny'->inhale( $role_name );
109 0         0 }
110             else {
111 2 50 33     14 $role = $project->class( $role_name, 'Mite::Role' );
112 2         755 }
113 2         16 return $role if $role;
114              
115             croak <<"ERROR", $role_name;
116 0         0 %s loaded but is not a recognized role. Mite roles and Role::Tiny
117             roles are the only supported roles. Sorry.
118 2 50       11 ERROR
119             }
120 0         0  
121             my $self = shift;
122             return (
123             $self->name,
124             map( $_->does_list, @{ $self->roles } ),
125             );
126             }
127 24     24 0 40  
128             my $self = shift;
129              
130 24         61 while ( @_ ) {
  24         114  
131             my $role = shift;
132             my $args = Str->check( $_[0] ) ? undef : shift;
133             $self->role_args->{$role} = $args;
134             $self->add_roles_by_name( $role );
135 11     11 0 27 }
136              
137 11         42 return;
138 11         24 }
139 11 50       43  
140 11         194 before inject_mite_functions => sub {
141 11         58 my ( $self, $file, $arg ) = ( shift, @_ );
142              
143             my $requested = sub { $arg->{$_[0]} ? 1 : $arg->{'!'.$_[0]} ? 0 : $arg->{'-all'} ? 1 : $_[1]; };
144 11         42 my $defaults = ! $arg->{'!-defaults'};
145             my $shim = $self->shim_name;
146             my $package = $self->name;
147             my $fake_ns = $self->project->can('_module_fakeout_namespace') && $self->project->_module_fakeout_namespace;
148              
149             no strict 'refs';
150              
151             if ( $requested->( 'with', $defaults ) ) {
152              
153             *{ $package .'::with' } = sub {
154             return $self->handle_with_keyword(
155             defined( $fake_ns )
156 108     108   904 ? ( map Str->check($_) ? "$fake_ns\::$_" : $_, @_ )
  108         288  
  108         70910  
157             : @_
158             );
159             };
160              
161 0 0   0     $self->imported_keywords->{with} = 'sub { $SHIM->HANDLE_with( $CALLER, @_ ) }';
    0          
162             }
163             };
164              
165             around compilation_stages => sub {
166             my ( $next, $self ) = ( shift, shift );
167             my @stages = $self->$next( @_ );
168             push @stages, qw(
169             _compile_with
170             _compile_does
171             _compile_composed_methods
172             );
173             return @stages;
174             };
175              
176             my $self = shift;
177              
178             my $roles = [ map $_->name, @{ $self->roles } ];
179             return unless @$roles;
180              
181             my $source = $self->source;
182              
183             my $require_list = join "\n\t",
184 131     131   292 map { "require $_;" }
185             # Don't require a role from the same source
186 131         250 grep { !$source || !$source->has_class($_) }
  131         519  
187 131 100       731 @$roles;
188              
189 11         44 my $version_tests = join "\n\t",
190             map { sprintf '%s->VERSION( %s );',
191             B::perlstring( $_ ),
192 2         10 B::perlstring( $self->role_args->{$_}{'-version'} )
193             }
194 11   66     37 grep {
  11         90  
195             $self->role_args->{$_}
196             and $self->role_args->{$_}{'-version'}
197             }
198             @$roles;
199              
200 0         0 my $does_hash = join ", ", map sprintf( "%s => 1", B::perlstring($_) ), $self->does_list;
201              
202             return <<"END";
203 11         44 BEGIN {
204 11 100       44 $require_list
205             $version_tests
206             our \%DOES = ( $does_hash );
207             }
208 11         49 END
209             }
210 11         91  
211             my $self = shift;
212             return <<'CODE'
213             # See UNIVERSAL
214             sub DOES {
215             my ( $self, $role ) = @_;
216             our %DOES;
217             return $DOES{$role} if exists $DOES{$role};
218             return 1 if $role eq __PACKAGE__;
219             if ( $INC{'Moose/Util.pm'} and my $meta = Moose::Util::find_meta( ref $self or $self ) ) {
220 131     131   300 $meta->can( 'does_role' ) and $meta->does_role( $role ) and return 1;
221             }
222             return $self->SUPER::DOES( $role );
223             }
224              
225             # Alias for Moose/Moo-compatibility
226             sub does {
227             shift->DOES( @_ );
228             }
229             CODE
230             }
231              
232             my $self = shift;
233             my $code = '';
234              
235             my %methods = %{ $self->methods_to_import_from_roles };
236             keys %methods or return;
237              
238             $code .= "# Methods from roles\n";
239 131         531 for my $name ( sort keys %methods ) {
240             # Use goto to help namespace::autoclean recognize these as
241             # not being imported methods.
242 131     131   260 $code .= sprintf 'sub %s { goto \&%s; }' . "\n", $name, $methods{$name};
243 131         308 }
244              
245 131         251 return $code;
  131         532  
246 131 100       970 }
247              
248 4         12 around _compile_mop_postamble => sub {
249 4         23 my ( $next, $self ) = ( shift, shift );
250             my $code = $self->$next( @_ );
251              
252 7         29 my @roles = @{ $self->roles || [] }
253             or return $code;
254              
255 4         37 for my $role ( @roles ) {
256             $code .= sprintf "Moose::Util::find_meta( %s )->add_role( Moose::Util::find_meta( %s ) );\n",
257             B::perlstring( $self->name ), B::perlstring( $role->name );
258             }
259              
260             return $code;
261             };
262              
263             1;