File Coverage

blib/lib/Acme/Mitey/Cards/Mite.pm
Criterion Covered Total %
statement 145 235 61.7
branch 19 66 28.7
condition 5 25 20.0
subroutine 46 61 75.4
pod 0 27 0.0
total 215 414 51.9


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