File Coverage

blib/lib/Sub/HandlesVia/Toolkit/Mite.pm
Criterion Covered Total %
statement 98 122 80.3
branch 37 64 57.8
condition 8 17 47.0
subroutine 17 19 89.4
pod 0 3 0.0
total 160 225 71.1


line stmt bran cond sub pod time code
1 10     10   227 use 5.008;
  10         37  
2 10     10   53 use strict;
  10         19  
  10         243  
3 10     10   58 use warnings;
  10         19  
  10         786  
4              
5              
6             our $AUTHORITY = 'cpan:TOBYINK';
7             our $VERSION = '0.045';
8              
9             use Sub::HandlesVia::Mite -all;
10 10     10   4486 extends 'Sub::HandlesVia::Toolkit';
  10         26  
  10         76  
11              
12             use Types::Standard -types, -is;
13 10     10   1041  
  10         21  
  10         204  
14             my $me = shift;
15             my ($target) = @_;
16 10     10 0 25 $me->install_has_wrapper($target);
17 10         31 }
18 10         33  
19             my %SPECS;
20             my $me = shift;
21             my ($target) = @_;
22            
23 10     10 0 21 no strict 'refs';
24 10         19 no warnings 'redefine';
25            
26 10     10   141182 my $orig = \&{ "$target\::has" };
  10         21  
  10         443  
27 10     10   63 my $uses_mite = ${ "$target\::USES_MITE" };
  10         18  
  10         17867  
28             my $mite_shim = ${ "$target\::MITE_SHIM" };
29 10         17  
  10         144  
30 10         20 *{ "$target\::has" } = sub {
  10         49  
31 10         19 my ( $names, %spec ) = @_;
  10         38  
32             return $orig->($names, %spec) unless $spec{handles}; # shortcut
33 10         95
34 10     10   10019 my @shv;
35 10 50       45 for my $name ( ref($names) ? @$names : $names) {
36             ( my $real_name = $name ) =~ s/^[+]//;
37 10         21 my $shv = $me->clean_spec( $target, $real_name, \%spec );
38 10 50       42 $SPECS{$target}{$real_name} = \%spec;
39 10         30 $orig->( $name, %spec );
40 10         85 push @shv, $shv if $shv;
41 10         36 }
42 10         62
43 10 50       493 if ( $ENV{MITE_COMPILE}
44             or defined($Mite::COMPILING) && ( $Mite::COMPILING eq $mite_shim )) {
45             return;
46 10 50 33     99 }
      33        
47            
48 0         0 if ( $uses_mite eq 'Mite::Role' ) {
49             require Role::Hooks;
50             'Role::Hooks'->after_apply( $target, sub {
51 10 100       40 my ( $from, $to ) = @_;
52 1         683 return if 'Role::Hooks'->is_role( $to );
53             for my $shv ( @shv ) {
54 2         3837 $me->install_delegations( { %$shv, target => $to } );
55 2 100       17 }
56 1         16 } );
57 1         31 }
58             else {
59 1         6107 for my $shv ( @shv ) {
60             $me->install_delegations( $shv );
61             }
62 9         22 }
63 9         63
64             return;
65             };
66             }
67 10         468  
68 10         49 my @method_name_generator = (
69             { # public
70             reader => sub { "get_$_" },
71             writer => sub { "set_$_" },
72             accessor => sub { $_ },
73             lvalue => sub { $_ },
74             clearer => sub { "clear_$_" },
75             predicate => sub { "has_$_" },
76             builder => sub { "_build_$_" },
77             trigger => sub { "_trigger_$_" },
78             },
79             { # private
80             reader => sub { "_get_$_" },
81             writer => sub { "_set_$_" },
82             accessor => sub { $_ },
83             lvalue => sub { $_ },
84             clearer => sub { "_clear_$_" },
85             predicate => sub { "_has_$_" },
86             builder => sub { "_build_$_" },
87             trigger => sub { "_trigger_$_" },
88             },
89             );
90              
91             my ( $me, $target, $attrname ) = ( shift, @_ );
92            
93             my $name = $attrname->[0];
94             my $spec = $SPECS{$target}{$name};
95 10     10 0 45 my $env = {};
96            
97 10         31 my $private = 0+!! ( $name =~ /^_/ );
98 10         42
99 10         24 $spec->{is} ||= bare;
100             if ( $spec->{is} eq lazy ) {
101 10         47 $spec->{builder} = 1 unless exists $spec->{builder};
102             $spec->{is} = ro;
103 10   100     51 }
104 10 50       52 if ( $spec->{is} eq ro ) {
105 0 0       0 $spec->{reader} = '%s' unless exists $spec->{reader};
106 0         0 }
107             if ( $spec->{is} eq rw ) {
108 10 100       48 $spec->{accessor} = '%s' unless exists $spec->{accessor};
109 1 50       3 }
110             if ( $spec->{is} eq rwp ) {
111 10 50       48 $spec->{reader} = '%s' unless exists $spec->{reader};
112 0 0       0 $spec->{writer} = '_set_%s' unless exists $spec->{writer};
113             }
114 10 100       47
115 8 50       41 for my $property ( 'reader', 'writer', 'accessor', 'builder', 'lvalue' ) {
116 8 50       36 defined( my $methodname = $spec->{$property} ) or next;
117             if ( $methodname eq 1 ) {
118             my $gen = $method_name_generator[$private]{$property};
119 10         46 local $_ = $name;
120 50 100       156 $spec->{$property} = $gen->( $_ );
121 17 50       56 }
122 0         0 $spec->{$property} =~ s/\%s/$name/g;
123 0         0 }
124 0         0
125             my ( $get, $set, $get_is_lvalue, $set_checks_isa, $default, $slot );
126 17         107
127             if ( my $reader = $spec->{reader} || $spec->{accessor} || $spec->{lvalue} ) {
128             $get = sub { shift->generate_self . "->$reader" };
129 10         80 $get_is_lvalue = false;
130             }
131 10 100 33     86 else {
132 9     173   56 $get = sub { shift->generate_self . "->{q[$name]}" };
  173         440  
133 9         28 $get_is_lvalue = true;
134             }
135            
136 1     3   7 if ( my $writer = $spec->{writer} || $spec->{accessor} ) {
  3         9  
137 1         4 $set = sub {
138             my ( $gen, $expr ) = @_;
139             $gen->generate_self . "->$writer($expr)";
140 10 100 66     69 };
    50          
141             $set_checks_isa = true;
142 49     49   218 }
143 49         142 elsif ( $writer = $spec->{lvalue} ) {
144 8         47 $set = sub {
145 8         26 my ( $gen, $expr ) = @_;
146             "( " . $gen->generate_self . "->$writer = $expr )";
147             };
148             $set_checks_isa = false;
149 0     0   0 }
150 0         0 else {
151 0         0 $set = sub {
152 0         0 my ( $gen, $expr ) = @_;
153             "( " . $gen->generate_self . "->{q[$name]} = $expr )";
154             };
155             $set_checks_isa = false;
156 5     5   25 }
157 5         28
158 2         10 $slot = sub { shift->generate_self . "->{q[$name]}" };
159 2         5
160             if ( ref $spec->{builder} ) {
161             $default = $spec->{builder};
162 10     1   71 $env->{'$shv_default_for_reset'} = \$default;
  1         6  
163             }
164 10 50       81 elsif ( $spec->{builder} ) {
    50          
    100          
    50          
165 0         0 $default = $spec->{builder};
166 0         0 }
167             elsif ( ref $spec->{default} ) {
168             $default = $spec->{default};
169 0         0 $env->{'$shv_default_for_reset'} = \$default;
170             }
171             elsif ( exists $spec->{default} ) {
172 9         26 my $value = $spec->{default};
173 9         29 $default = sub { $value };
174             $env->{'$shv_default_for_reset'} = \$default;
175             }
176 0         0
177 0     0   0 require Sub::HandlesVia::CodeGenerator;
  0         0  
178 0         0 return 'Sub::HandlesVia::CodeGenerator'->new(
179             toolkit => $me,
180             target => $target,
181 10         5574 attribute => $name,
182             env => $env,
183             isa => $spec->{type},
184             coerce => $spec->{coerce},
185             generator_for_get => $get,
186             generator_for_set => $set,
187             get_is_lvalue => $get_is_lvalue,
188             set_checks_isa => $set_checks_isa,
189             set_strictly => true,
190             generator_for_default => sub {
191             my ( $gen, $handler ) = @_ or die;
192             if ( !$default and $handler ) {
193             return $handler->default_for_reset->();
194             }
195 6 50   6   42 elsif ( is_CodeRef $default ) {
196 6 50 33     86 return sprintf(
    100          
    50          
    50          
    0          
    0          
197 0         0 '(%s)->$shv_default_for_reset',
198             $gen->generate_self,
199             );
200 5         27 }
201             elsif ( is_Str $default ) {
202             require B;
203             return sprintf(
204             '(%s)->${\ %s }',
205             $gen->generate_self,
206 0         0 B::perlstring( $default ),
207 0         0 );
208             }
209             elsif ( is_ScalarRef $default ) {
210             return $$default;
211             }
212             elsif ( is_HashRef $default ) {
213             return '{}';
214 1         5 }
215             elsif ( is_ArrayRef $default ) {
216             return '[]';
217 0           }
218             return;
219             },
220 0           ( $slot ? ( generator_for_slot => $slot ) : () ),
221             );
222 0           }
223              
224 10 50       217 1;
225