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   381 use 5.008;
  21         80  
2 21     21   128 use strict;
  21         45  
  21         461  
3 21     21   124 use warnings;
  21         44  
  21         1530  
4              
5             package Sub::HandlesVia::Toolkit::Mouse;
6              
7             our $AUTHORITY = 'cpan:TOBYINK';
8             our $VERSION = '0.046';
9              
10 21     21   10397 use Sub::HandlesVia::Mite;
  21         61  
  21         133  
11             extends 'Sub::HandlesVia::Toolkit';
12              
13             sub setup_for {
14 88     88 0 265 my $me = shift;
15 88         278 my ($target) = @_;
16            
17 88         424 require Mouse::Util;
18 88         432 my $meta = Mouse::Util::find_meta($target);
19 88         1608 $me->meta_hack( $meta );
20             }
21              
22             sub meta_hack {
23 90     90 0 343 my ( $me, $meta ) = ( shift, @_ );
24            
25 90         10217 require Mouse::Util::MetaRole;
26            
27 90 100       21442 if ( $meta->isa('Mouse::Meta::Role') ) {
28            
29 3         24 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         464 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 623 __PACKAGE__ . "::PackageTrait";
45             }
46              
47             sub role_trait {
48 3     3 0 16 __PACKAGE__ . "::RoleTrait";
49             }
50              
51             sub code_generator_for_attribute {
52 101     101 0 452 my ($me, $target, $attrname) = (shift, @_);
53              
54 101 50       432 if (ref $attrname) {
55 101 50       433 @$attrname==1 or die;
56 101         302 ($attrname) = @$attrname;
57             }
58            
59 101         239 my $meta;
60 101 50       359 if (ref $target) {
61 0         0 $meta = $target;
62 0         0 $target = $meta->name;
63             }
64             else {
65 101         696 require Mouse::Util;
66 101         458 $meta = Mouse::Util::find_meta($target);
67             }
68            
69 101         1790 my $attr = $meta->get_attribute($attrname);
70 101         1336 my $spec = +{%$attr};
71            
72 101         331 my $captures = {};
73            
74 101         270 my ($get, $set, $get_is_lvalue, $set_checks_isa);
75 101 100 33     1057 if (!$spec->{lazy} and !$spec->{traits} and !$spec->{auto_deref}) {
    100          
76 78         392 require B;
77 78         437 my $slot = B::perlstring($attrname);
78             $get = sub {
79 1541     1541   3951 my $self = shift->generate_self;
80 1541         10725 "$self\->{$slot}";
81 78         602 };
82 78         231 ++$get_is_lvalue;
83             }
84             elsif ($attr->has_read_method) {
85 17   66     335 my $read_method = $attr->reader || $attr->accessor;
86             $get = sub {
87 293     293   781 my $self = shift->generate_self;
88 293         2010 "scalar($self\->$read_method)";
89 17         145 };
90             }
91             else {
92 6         46 my $read_method = $attr->get_read_method_ref;
93 6         260 $captures->{'$shv_read_method'} = \$read_method;
94             $get = sub {
95 12     12   34 my $self = shift->generate_self;
96 12         74 "scalar($self\->\$shv_read_method)";
97 6         33 };
98             }
99 101 100       521 if ($attr->has_write_method) {
100 77   66     1073 my $write_method = $attr->writer || $attr->accessor;
101             $set = sub {
102 616     616   2316 my ($gen, $val) = @_;
103 616         1645 $gen->generate_self . "->$write_method\($val)"
104 77         403 };
105 77         214 ++$set_checks_isa;
106             }
107             else {
108 24         265 my $write_method = $attr->get_write_method_ref;
109 24         887 $captures->{'$shv_write_method'} = \$write_method;
110             $set = sub {
111 5     5   23 my ($gen, $val) = @_;
112 5         21 $gen->generate_self . '->$shv_write_method('.$val.')';
113 24         102 };
114 24         58 ++$set_checks_isa;
115             }
116              
117 101         238 my $default;
118 101 100       444 if (exists $spec->{default}) {
    100          
119 80         286 $default = [ default => $spec->{default} ];
120             }
121             elsif (exists $spec->{builder}) {
122 9         56 $default = [ builder => $spec->{builder} ];
123             }
124              
125 101 100       511 if (ref $default->[1] eq 'CODE') {
126 39         155 $captures->{'$shv_default_for_reset'} = \$default->[1];
127             }
128              
129 101         12533 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   16090 method_installer => sub { $meta->add_method(@_) },
145             generator_for_default => sub {
146 15 50   15   50 my ( $gen, $handler ) = @_ or die;
147 15 50 33     199 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         13 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         69 require B;
168 11         80 return B::perlstring( $default->[1] );
169             }
170 0         0 return;
171             },
172 101         1055 );
173             }
174              
175             package Sub::HandlesVia::Toolkit::Mouse::PackageTrait;
176              
177             our $AUTHORITY = 'cpan:TOBYINK';
178             our $VERSION = '0.046';
179              
180 21     21   35034 use Mouse::Role;
  21         25538  
  21         176  
181              
182             sub _shv_toolkit {
183 203     203   1411 '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.046';
218              
219 21     21   16775 use Mouse::Role;
  21         180  
  21         135  
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   8252 no warnings 'redefine';
  21         59  
  21         4793  
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   2580 my ( $class, @roles ) = ( shift, @_ );
236 4         22 my $combined = $class->$next( @roles );
237             my ($hack) = map {
238 4 50 33     17619 ( ref $_ and blessed $_->[0] and $_->[0]->can( '_shv_toolkit' ) )
  8         140  
239             ? $_->[0]->_shv_toolkit
240             : ();
241             } @roles;
242 4 50       45 if ($hack) {
243 0         0 $combined = $hack->meta_hack( $combined );
244             }
245 4         26 return $combined;
246             };
247             };
248              
249             1;