File Coverage

blib/lib/Acme/Mitey/Cards/Mite.pm
Criterion Covered Total %
statement 169 233 72.5
branch 29 78 37.1
condition 2 13 15.3
subroutine 53 66 80.3
pod 0 22 0.0
total 253 412 61.4


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