File Coverage

blib/lib/Sub/HandlesVia/Toolkit/Mouse.pm
Criterion Covered Total %
statement 93 101 92.0
branch 26 36 72.2
condition 10 24 41.6
subroutine 21 22 95.4
pod 0 5 0.0
total 150 188 79.7


line stmt bran cond sub pod time code
1 21     21   373 use 5.008;
  21         77  
2 21     21   131 use strict;
  21         44  
  21         454  
3 21     21   134 use warnings;
  21         58  
  21         1324  
4              
5             package Sub::HandlesVia::Toolkit::Mouse;
6              
7             our $AUTHORITY = 'cpan:TOBYINK';
8             our $VERSION = '0.050000';
9              
10 21     21   9734 use Sub::HandlesVia::Mite;
  21         78  
  21         138  
11             extends 'Sub::HandlesVia::Toolkit';
12              
13             sub setup_for {
14 88     88 0 250 my $me = shift;
15 88         259 my ($target) = @_;
16            
17 88         411 require Mouse::Util;
18 88         446 my $meta = Mouse::Util::find_meta($target);
19 88         1557 $me->meta_hack( $meta );
20             }
21              
22             sub meta_hack {
23 90     90 0 303 my ( $me, $meta ) = ( shift, @_ );
24            
25 90         9603 require Mouse::Util::MetaRole;
26            
27 90 100       20373 if ( $meta->isa('Mouse::Meta::Role') ) {
28            
29 3         19 return Mouse::Util::MetaRole::apply_metaroles(
30             for => $meta,
31             role_metaroles => { role => [ $me->package_trait, $me->role_trait ] },
32             );
33             }
34             else {
35            
36 87         468 return Mouse::Util::MetaRole::apply_metaroles(
37             for => $meta,
38             class_metaroles => { class => [ $me->package_trait ] },
39             );
40             }
41             }
42              
43             sub package_trait {
44 90     90 0 620 __PACKAGE__ . "::PackageTrait";
45             }
46              
47             sub role_trait {
48 3     3 0 15 __PACKAGE__ . "::RoleTrait";
49             }
50              
51             sub code_generator_for_attribute {
52 101     101 0 405 my ($me, $target, $attrname) = (shift, @_);
53              
54 101 50       436 if (ref $attrname) {
55 101 50       393 @$attrname==1 or die;
56 101         306 ($attrname) = @$attrname;
57             }
58            
59 101         218 my $meta;
60 101 50       339 if (ref $target) {
61 0         0 $meta = $target;
62 0         0 $target = $meta->name;
63             }
64             else {
65 101         655 require Mouse::Util;
66 101         451 $meta = Mouse::Util::find_meta($target);
67             }
68            
69 101         1801 my $attr = $meta->get_attribute($attrname);
70 101         1393 my $spec = +{%$attr};
71            
72 101         358 my $captures = {};
73            
74 101         332 my ($get, $set, $get_is_lvalue, $set_checks_isa);
75 101 100 33     1038 if (!$spec->{lazy} and !$spec->{traits} and !$spec->{auto_deref}) {
    100          
76 78         361 require B;
77 78         454 my $slot = B::perlstring($attrname);
78             $get = sub {
79 1541     1541   3981 my $self = shift->generate_self;
80 1541         10220 "$self\->{$slot}";
81 78         559 };
82 78         246 ++$get_is_lvalue;
83             }
84             elsif ($attr->has_read_method) {
85 17   66     296 my $read_method = $attr->reader || $attr->accessor;
86             $get = sub {
87 293     293   813 my $self = shift->generate_self;
88 293         2303 "scalar($self\->$read_method)";
89 17         136 };
90             }
91             else {
92 6         53 my $read_method = $attr->get_read_method_ref;
93 6         249 $captures->{'$shv_read_method'} = \$read_method;
94             $get = sub {
95 12     12   43 my $self = shift->generate_self;
96 12         104 "scalar($self\->\$shv_read_method)";
97 6         41 };
98             }
99 101 100       549 if ($attr->has_write_method) {
100 77   66     1159 my $write_method = $attr->writer || $attr->accessor;
101             $set = sub {
102 616     616   2320 my ($gen, $val) = @_;
103 616         1673 $gen->generate_self . "->$write_method\($val)"
104 77         420 };
105 77         198 ++$set_checks_isa;
106             }
107             else {
108 24         224 my $write_method = $attr->get_write_method_ref;
109 24         853 $captures->{'$shv_write_method'} = \$write_method;
110             $set = sub {
111 5     5   23 my ($gen, $val) = @_;
112 5         29 $gen->generate_self . '->$shv_write_method('.$val.')';
113 24         127 };
114 24         55 ++$set_checks_isa;
115             }
116              
117 101         229 my $default;
118 101 100       454 if (exists $spec->{default}) {
    100          
119 80         302 $default = [ default => $spec->{default} ];
120             }
121             elsif (exists $spec->{builder}) {
122 9         36 $default = [ builder => $spec->{builder} ];
123             }
124              
125 101 100       452 if (ref $default->[1] eq 'CODE') {
126 39         152 $captures->{'$shv_default_for_reset'} = \$default->[1];
127             }
128              
129 101         11662 require Sub::HandlesVia::CodeGenerator;
130             return 'Sub::HandlesVia::CodeGenerator'->new(
131             toolkit => $me,
132             target => $target,
133             attribute => $attrname,
134             attribute_spec => $spec,
135             env => $captures,
136             isa => Types::TypeTiny::to_TypeTiny($attr->type_constraint),
137             coerce => !!$spec->{coerce},
138 0     0   0 generator_for_slot => sub { shift->generate_self.'->{'.B::perlstring($attrname).'}' }, # icky
139             generator_for_get => $get,
140             generator_for_set => $set,
141             get_is_lvalue => $get_is_lvalue,
142             set_checks_isa => $set_checks_isa,
143             set_strictly => !!0,
144 1292     1292   15539 method_installer => sub { $meta->add_method(@_) },
145             generator_for_default => sub {
146 15 50   15   58 my ( $gen, $handler ) = @_ or die;
147 15 50 33     160 if ( !$default and $handler ) {
    100 33        
    50 33        
    50 33        
    50          
148 0         0 return $handler->default_for_reset->();
149             }
150             elsif ( $default->[0] eq 'builder' ) {
151 4         16 return sprintf(
152             '(%s)->%s',
153             $gen->generate_self,
154             $default->[1],
155             );
156             }
157             elsif ( $default->[0] eq 'default' and ref $default->[1] eq 'CODE' ) {
158 0         0 return sprintf(
159             '(%s)->$shv_default_for_reset',
160             $gen->generate_self,
161             );
162             }
163             elsif ( $default->[0] eq 'default' and !defined $default->[1] ) {
164 0         0 return 'undef';
165             }
166             elsif ( $default->[0] eq 'default' and !ref $default->[1] ) {
167 11         62 require B;
168 11         73 return B::perlstring( $default->[1] );
169             }
170 0         0 return;
171             },
172 101         945 );
173             }
174              
175             package Sub::HandlesVia::Toolkit::Mouse::PackageTrait;
176              
177             our $AUTHORITY = 'cpan:TOBYINK';
178             our $VERSION = '0.050000';
179              
180 21     21   33879 use Mouse::Role;
  21         23265  
  21         173  
181              
182             sub _shv_toolkit {
183 203     203   1312 'Sub::HandlesVia::Toolkit::Mouse',
184             }
185              
186             around add_attribute => sub {
187             my ($next, $self, @args) = (shift, shift, @_);
188             my ($spec, $attrobj, $attrname);
189             if (@args == 1) {
190             $spec = $attrobj = $_[0];
191             $attrname = $attrobj->name;
192             }
193             elsif (@args == 2) {
194             ($attrname, $spec) = @args;
195             }
196             else {
197             my %spec;
198             ($attrname, %spec) = @args;
199             $spec = \%spec;
200             }
201             ( my $real_attrname = $attrname ) =~ s/^[+]//;
202             $spec->{provides}{shv} = $self->_shv_toolkit->clean_spec($self->name, $real_attrname, $spec)
203             unless $spec->{provides}{shv};
204             my $attr = $self->$next($attrobj ? $attrobj : ($attrname, %$spec));
205             if ($spec->{provides}{shv} and $self->isa('Mouse::Meta::Class')) {
206             $self->_shv_toolkit->install_delegations(+{
207             %{ $spec->{provides}{shv} },
208             target => $self->name,
209             });
210             }
211             return $attr;
212             };
213              
214             package Sub::HandlesVia::Toolkit::Mouse::RoleTrait;
215              
216             our $AUTHORITY = 'cpan:TOBYINK';
217             our $VERSION = '0.050000';
218              
219 21     21   16041 use Mouse::Role;
  21         181  
  21         122  
220             requires '_shv_toolkit';
221              
222             around apply => sub {
223             my ($next, $self, $other, %args) = (shift, shift, @_);
224             $other = $self->_shv_toolkit->meta_hack( $other );
225             $self->$next( $other, %args );
226             };
227              
228             # This is a horrible hack.
229             do {
230 21     21   8184 no warnings 'redefine';
  21         61  
  21         4936  
231             require Mouse::Meta::Role;
232             require Scalar::Util;
233             my $next = \&Mouse::Meta::Role::combine;
234             *Mouse::Meta::Role::combine = sub {
235 4     4   2648 my ( $class, @roles ) = ( shift, @_ );
236 4         19 my $combined = $class->$next( @roles );
237             my ($hack) = map {
238 4 50 33     17643 ( ref $_ and blessed $_->[0] and $_->[0]->can( '_shv_toolkit' ) )
  8         129  
239             ? $_->[0]->_shv_toolkit
240             : ();
241             } @roles;
242 4 50       44 if ($hack) {
243 0         0 $combined = $hack->meta_hack( $combined );
244             }
245 4         23 return $combined;
246             };
247             };
248              
249             1;