File Coverage

blib/lib/Acme/Mitey/Cards/Mite.pm
Criterion Covered Total %
statement 142 231 61.4
branch 18 64 28.1
condition 1 19 5.2
subroutine 46 61 75.4
pod 0 27 0.0
total 207 402 51.4


line stmt bran cond sub pod time code
1             # NOTE: Since the intention is to ship this file with a project, this file
2             # cannot have any non-core dependencies.
3             package Acme::Mitey::Cards::Mite;
4 10     10   237 use 5.008001;
  10         37  
5 10     10   59 use strict;
  10         17  
  10         228  
6 10     10   60 use warnings;
  10         20  
  10         388  
7 10     10   57 no strict 'refs';
  10         20  
  10         3264  
8              
9             if ( $] < 5.009005 ) { require MRO::Compat; }
10             else { require mro; }
11              
12             defined ${^GLOBAL_PHASE}
13             or eval { require Devel::GlobalDestruction; 1 }
14             or do {
15             carp( "WARNING: Devel::GlobalDestruction recommended!" );
16             *Devel::GlobalDestruction::in_global_destruction = sub { undef; };
17             };
18              
19             # Constants
20             sub true () { !!1 }
21             sub false () { !!0 }
22             sub ro () { 'ro' }
23             sub rw () { 'rw' }
24             sub rwp () { 'rwp' }
25             sub lazy () { 'lazy' }
26             sub bare () { 'bare' }
27              
28             # More complicated constants
29             BEGIN {
30 10     10   59 my @bool = ( \&false, \&true );
31 10         21 *_HAS_AUTOCLEAN = $bool[ 0+!! eval { require namespace::autoclean } ];
  10         1466  
32 10   0     23071 *STRICT = $bool[ 0+!! ( $ENV{PERL_STRICT} || $ENV{EXTENDED_TESTING} || $ENV{AUTHOR_TESTING} || $ENV{RELEASE_TESTING} ) ];
33             };
34              
35             # Exportable error handlers
36             sub _error_handler {
37 4     4   17 my ( $func, $message, @args ) = @_;
38 4 100       15 if ( @args ) {
39 3         2038 require Data::Dumper;
40 3         20809 local $Data::Dumper::Terse = 1;
41 3         9 local $Data::Dumper::Indent = 0;
42             $message = sprintf $message, map {
43 3 50       11 ref($_) ? Data::Dumper::Dumper($_) : defined($_) ? $_ : '(undef)'
  6 50       46  
44             } @args;
45             }
46 4         11 my $next = do { require Carp; \&{"Carp::$func"} };
  4         27  
  4         9  
  4         18  
47 4         16 @_ = ( $message );
48 4         825 goto $next;
49             }
50              
51 1     1 0 2 sub carp { unshift @_, 'carp' ; goto \&_error_handler }
  1         3  
52 3     3 0 16 sub croak { unshift @_, 'croak' ; goto \&_error_handler }
  3         13  
53 0     0 0 0 sub confess { unshift @_, 'confess'; goto \&_error_handler }
  0         0  
54              
55             # Exportable guard function
56             {
57             my $GUARD_PACKAGE = __PACKAGE__ . '::Guard';
58 0 0   0   0 *{"$GUARD_PACKAGE\::DESTROY"} = sub { $_[0][0] or $_[0][1]->() };
59 0     0   0 *{"$GUARD_PACKAGE\::restore"} = sub { $_[0]->DESTROY; $_[0][0] = true };
  0         0  
60 0     0   0 *{"$GUARD_PACKAGE\::dismiss"} = sub { $_[0][0] = true };
61 0     0   0 *{"$GUARD_PACKAGE\::peek"} = sub { $_[0][2] };
62 0     0   0 *guard = sub (&) { bless [ 0, @_ ] => $GUARD_PACKAGE };
63             }
64              
65             # Exportable lock and unlock
66             sub _lul {
67 0     0   0 my ( $lul, $ref ) = @_;
68 0 0       0 if ( ref $ref eq 'ARRAY' ) {
69 0         0 &Internals::SvREADONLY( $ref, $lul );
70 0         0 &Internals::SvREADONLY( \$_, $lul ) for @$ref;
71 0         0 return;
72             }
73 0 0       0 if ( ref $ref eq 'HASH' ) {
74 0         0 &Internals::hv_clear_placeholders( $ref );
75 0         0 &Internals::SvREADONLY( $ref, $lul );
76 0         0 &Internals::SvREADONLY( \$_, $lul ) for values %$ref;
77 0         0 return;
78             }
79 0         0 return;
80             }
81              
82             sub lock {
83 0     0 0 0 unshift @_, true;
84 0         0 goto \&_lul;
85             }
86              
87             sub unlock {
88 0     0 0 0 my $ref = shift;
89 0         0 _lul( 0 , $ref );
90 0     0   0 &guard( sub { _lul( 1, $ref ) } );
  0         0  
91             }
92              
93             sub _is_compiling {
94 39 50   39   170 defined $Mite::COMPILING and $Mite::COMPILING eq __PACKAGE__;
95             }
96              
97             sub import {
98 39     39   107 my $me = shift;
99 39         104 my %arg = map { lc($_) => true } @_;
  39         205  
100 39         173 my ( $caller, $file ) = caller;
101              
102 39 50       110 if( _is_compiling() ) {
103 0         0 require Mite::Project;
104 0         0 Mite::Project->default->inject_mite_functions(
105             package => $caller,
106             file => $file,
107             arg => \%arg,
108             shim => $me,
109             );
110             }
111             else {
112             # Changes to this filename must be coordinated with Mite::Compiled
113 39         110 my $mite_file = $file . ".mite.pm";
114 39 50       726 if( !-e $mite_file ) {
115 0         0 croak "Compiled Mite file ($mite_file) for $file is missing";
116             }
117              
118             {
119 39         97 local @INC = ('.', @INC);
  39         263  
120 39         16999 require $mite_file;
121             }
122             }
123              
124 39         427 warnings->import;
125 39         236 strict->import;
126             'namespace::autoclean'->import( -cleanee => $caller )
127 39         1301 if _HAS_AUTOCLEAN && !$arg{'-unclean'};
128             }
129              
130             {
131             my ( $cb_before, $cb_after );
132             sub _finalize_application_roletiny {
133 0     0   0 my ( $me, $role, $caller, $args ) = @_;
134 0 0       0 if ( $INC{'Role/Hooks.pm'} ) {
135 0   0     0 $cb_before ||= \%Role::Hooks::CALLBACKS_BEFORE_APPLY;
136 0   0     0 $cb_after ||= \%Role::Hooks::CALLBACKS_AFTER_APPLY;
137             }
138 0 0       0 if ( $cb_before ) {
139 0 0       0 $_->( $role, $caller ) for @{ $cb_before->{$role} || [] };
  0         0  
140             }
141 0         0 'Role::Tiny'->_check_requires( $caller, $role );
142 0         0 my $info = $Role::Tiny::INFO{$role};
143 0 0       0 for ( @{ $info->{modifiers} || [] } ) {
  0         0  
144 0         0 my @args = @$_;
145 0         0 my $modification = shift @args;
146 0         0 my $handler = "HANDLE_$modification";
147 0         0 $me->$handler( $caller, undef, @args );
148             }
149 0 0       0 if ( $cb_after ) {
150 0 0       0 $_->( $role, $caller ) for @{ $cb_after->{$role} || [] };
  0         0  
151             }
152 0         0 return;
153             }
154              
155             # Usage: $me, $caller, @with_args
156             sub HANDLE_with {
157 0     0 0 0 my ( $me, $caller ) = ( shift, shift );
158 0         0 while ( @_ ) {
159 0         0 my $role = shift;
160 0 0       0 my $args = ref($_[0]) ? shift : undef;
161 0 0 0     0 if ( $INC{'Role/Tiny.pm'} and 'Role::Tiny'->is_role( $role ) ) {
162 0         0 $me->_finalize_application_roletiny( $role, $caller, $args );
163             }
164             else {
165 0         0 $role->__FINALIZE_APPLICATION__( $caller, $args );
166             }
167             }
168 0         0 return;
169             }
170             }
171              
172             # Usage: $me, $caller, $keyword, @has_args
173             sub HANDLE_has {
174 67     67 0 211 my ( $me, $caller, $keyword, $names ) = ( shift, shift, shift, shift );
175 67 50       214 if ( @_ % 2 ) {
176 0         0 my $default = shift;
177 0 0       0 unshift @_, ( 'CODE' eq ref( $default ) )
178             ? ( is => lazy, builder => $default )
179             : ( is => ro, default => $default );
180             }
181 67         240 my %spec = @_;
182 67         115 my $code;
183 67 50       193 for my $name ( ref($names) ? @$names : $names ) {
184 67         138 $name =~ s/^\+//;
185             'CODE' eq ref( $code = $spec{default} )
186 67 50       228 and ${"$caller\::__$name\_DEFAULT__"} = $code;
  0         0  
187             'CODE' eq ref( $code = $spec{builder} )
188 67 100       182 and *{"$caller\::_build_$name"} = $code;
  15         103  
189             'CODE' eq ref( $code = $spec{trigger} )
190 67 50       172 and *{"$caller\::_trigger_$name"} = $code;
  0         0  
191             'CODE' eq ref( $code = $spec{clone} )
192 67 50       179 and *{"$caller\::_clone_$name"} = $code;
  0         0  
193             }
194 67         217 return;
195             }
196              
197             {
198             my $_kind = sub { ${ shift() . '::USES_MITE' } =~ /Role/ ? 'role' : 'class' };
199              
200             sub _get_orig_method {
201 80     80   162 my ( $caller, $name ) = @_;
202 80         561 my $orig = $caller->can( $name );
203 80 50       259 return $orig if $orig;
204 0         0 croak "Cannot modify method $name in $caller: no such method";
205             }
206              
207             sub _parse_mm_args {
208 80     80   127 my $coderef = pop;
209 80 50       202 my $names = [ map { ref($_) ? @$_ : $_ } @_ ];
  80         355  
210 80         225 ( $names, $coderef );
211             }
212              
213             # Usage: $me, $caller, $caller_kind, @before_args
214             sub HANDLE_before {
215 0     0 0 0 my ( $me, $caller, $kind ) = ( shift, shift, shift );
216 0         0 my ( $names, $coderef ) = &_parse_mm_args;
217 0   0     0 $kind ||= $caller->$_kind;
218 0 0       0 if ( $kind eq 'role' ) {
219 0         0 push @{"$caller\::METHOD_MODIFIERS"},
  0         0  
220             [ before => $names, $coderef ];
221 0         0 return;
222             }
223 0         0 for my $name ( @$names ) {
224 0         0 my $orig = _get_orig_method( $caller, $name );
225 0         0 local $@;
226 0 0       0 eval <<"BEFORE" or die $@;
227             package $caller;
228             no warnings 'redefine';
229             sub $name {
230             \$coderef->( \@_ );
231             \$orig->( \@_ );
232             }
233             1;
234             BEFORE
235             }
236 0         0 return;
237             }
238              
239             # Usage: $me, $caller, $caller_kind, @after_args
240             sub HANDLE_after {
241 0     0 0 0 my ( $me, $caller, $kind ) = ( shift, shift, shift );
242 0         0 my ( $names, $coderef ) = &_parse_mm_args;
243 0   0     0 $kind ||= $caller->$_kind;
244 0 0       0 if ( $kind eq 'role' ) {
245 0         0 push @{"$caller\::METHOD_MODIFIERS"},
  0         0  
246             [ after => $names, $coderef ];
247 0         0 return;
248             }
249 0         0 for my $name ( @$names ) {
250 0         0 my $orig = _get_orig_method( $caller, $name );
251 0         0 local $@;
252 0 0       0 eval <<"AFTER" or die $@;
253             package $caller;
254             no warnings 'redefine';
255             sub $name {
256             my \@r;
257             if ( wantarray ) {
258             \@r = \$orig->( \@_ );
259             }
260             elsif ( defined wantarray ) {
261             \@r = scalar \$orig->( \@_ );
262             }
263             else {
264             \$orig->( \@_ );
265             1;
266             }
267             \$coderef->( \@_ );
268             wantarray ? \@r : \$r[0];
269             }
270             1;
271             AFTER
272             }
273 0         0 return;
274             }
275              
276             # Usage: $me, $caller, $caller_kind, @around_args
277             sub HANDLE_around {
278 80     80 0 177 my ( $me, $caller, $kind ) = ( shift, shift, shift );
279 80         169 my ( $names, $coderef ) = &_parse_mm_args;
280 80   33     203 $kind ||= $caller->$_kind;
281 80 50       203 if ( $kind eq 'role' ) {
282 0         0 push @{"$caller\::METHOD_MODIFIERS"},
  0         0  
283             [ around => $names, $coderef ];
284 0         0 return;
285             }
286 80         161 for my $name ( @$names ) {
287 80         178 my $orig = _get_orig_method( $caller, $name );
288 80         137 local $@;
289 10 50   10 0 76 eval <<"AROUND" or die $@;
  10     9 0 42  
  10     8 0 631  
  9     8 0 68  
  9     6 0 23  
  9     5 0 448  
  8     5 0 54  
  8     5 0 20  
  8     3 0 445  
  8     3 0 55  
  8     3 0 18  
  8     3 0 379  
  6     3 0 43  
  6     3 0 15  
  6     3 0 313  
  5     3 0 35  
  5     4   11  
  5     25   248  
  5     2   32  
  5     9   11  
  5     1   267  
  5     38   33  
  5     8   12  
  5     122   221  
  3     4   23  
  3     1   8  
  3     6   143  
  3     39   25  
  3     5   8  
  3     120   159  
  3     3   22  
  3     0   6  
  3         148  
  3         23  
  3         10  
  3         185  
  3         25  
  3         7  
  3         136  
  3         22  
  3         10  
  3         163  
  3         21  
  3         9  
  3         155  
  3         25  
  3         18  
  3         156  
  80         6058  
  4         19  
  25         2191  
  2         70  
  9         1887  
  1         8  
  38         110  
  8         3222  
  122         339  
  4         1083  
  1         7  
  6         59  
  39         122  
  5         23  
  120         327  
  3         16  
  0         0  
290             package $caller;
291             no warnings 'redefine';
292             sub $name {
293             \$coderef->( \$orig, \@_ );
294             }
295             1;
296             AROUND
297             }
298 80         233 return;
299             }
300             }
301              
302             # Usage: $me, $caller, $caller_kind, @signature_for_args
303             sub HANDLE_signature_for {
304 80     80 0 226 my ( $me, $caller, $kind, $name ) = @_;
305 80         196 $name =~ s/^\+//;
306 80         155 $me->HANDLE_around( $caller, $kind, $name, ${"$caller\::SIGNATURE_FOR"}{$name} );
  80         463  
307 80         235 return;
308             }
309              
310             1;