File Coverage

blib/lib/Method/Generate/Accessor.pm
Criterion Covered Total %
statement 309 309 100.0
branch 194 194 100.0
condition 90 104 86.5
subroutine 52 52 100.0
pod 0 16 0.0
total 645 675 95.5


line stmt bran cond sub pod time code
1             package Method::Generate::Accessor;
2 188     188   163195 use strict;
  188         393  
  188         5954  
3 188     188   983 use warnings;
  188         347  
  188         6130  
4              
5 188     188   1841 use Moo::_Utils qw(_maybe_load_module _install_coderef _module_name_rx);
  188         401  
  188         10381  
6 188     188   10598 use Moo::Object ();
  188         408  
  188         6436  
7 188     188   8942 BEGIN { our @ISA = qw(Moo::Object) }
8 188     188   14615 use Sub::Quote qw(quote_sub quoted_from_sub quotify sanitize_identifier);
  188         182023  
  188         11831  
9 188     188   1329 use Scalar::Util 'blessed';
  188         365  
  188         8514  
10 188     188   1209 use Carp qw(croak);
  188         443  
  188         11021  
11             BEGIN {
12 188     188   29469 our @CARP_NOT = qw(
13             Moo::_Utils
14             Moo::Object
15             Moo::Role
16             );
17             }
18             BEGIN {
19             *_CAN_WEAKEN_READONLY = (
20             "$]" < 5.008_003 or $ENV{MOO_TEST_PRE_583}
21 188 100 66 188   3086 ) ? sub(){0} : sub(){1};
22             our $CAN_HAZ_XS =
23             !$ENV{MOO_XS_DISABLE}
24             &&
25             _maybe_load_module('Class::XSAccessor')
26             &&
27 188   66     1724 (eval { Class::XSAccessor->VERSION('1.07') })
28             ;
29             our $CAN_HAZ_XS_PRED =
30             $CAN_HAZ_XS &&
31 188   66     4876 (eval { Class::XSAccessor->VERSION('1.17') })
32             ;
33             }
34             BEGIN {
35             package
36             Method::Generate::Accessor::_Generated;
37 188     188   864255 $Carp::Internal{+__PACKAGE__} = 1;
38             }
39              
40             sub _die_overwrite {
41 18     18   48 my ($pkg, $method, $type) = @_;
42 18   50     4166 croak "You cannot overwrite a locally defined method ($method) with "
43             . ( $type || 'an accessor' );
44             }
45              
46             sub generate_method {
47 696     696 0 32994 my ($self, $into, $name, $spec, $quote_opts) = @_;
48             $quote_opts = {
49             no_defer => 1,
50             package => 'Method::Generate::Accessor::_Generated',
51 696 100       1327 %{ $quote_opts||{} },
  696         4394  
52             };
53 696 100       2877 $spec->{allow_overwrite}++ if $name =~ s/^\+//;
54 696 100       3144 croak "Must have an is" unless my $is = $spec->{is};
55 690 100       2375 if ($is eq 'ro') {
    100          
    100          
    100          
    100          
56 460 100       1556 $spec->{reader} = $name unless exists $spec->{reader};
57             } elsif ($is eq 'rw') {
58             $spec->{accessor} = $name unless exists $spec->{accessor}
59 184 100 100     1007 or ( $spec->{reader} and $spec->{writer} );
      100        
60             } elsif ($is eq 'lazy') {
61 28 100       106 $spec->{reader} = $name unless exists $spec->{reader};
62 28         76 $spec->{lazy} = 1;
63 28 100 66     129 $spec->{builder} ||= '_build_'.$name unless exists $spec->{default};
64             } elsif ($is eq 'rwp') {
65 12 100       61 $spec->{reader} = $name unless exists $spec->{reader};
66 12 100       53 $spec->{writer} = "_set_${name}" unless exists $spec->{writer};
67             } elsif ($is ne 'bare') {
68 2         246 croak "Unknown is ${is}";
69             }
70 688 100       1848 if (exists $spec->{builder}) {
71 46 100       127 if(ref $spec->{builder}) {
72             $self->_validate_codulatable('builder', $spec->{builder},
73 10         52 "$into->$name", 'or a method name');
74 10         21 $spec->{builder_sub} = $spec->{builder};
75 10         21 $spec->{builder} = 1;
76             }
77 46 100 50     197 $spec->{builder} = '_build_'.$name if ($spec->{builder}||0) eq 1;
78             croak "Invalid builder for $into->$name - not a valid method name"
79 46 100       643 if $spec->{builder} !~ _module_name_rx;
80             }
81 686 100 100     3287 if (($spec->{predicate}||0) eq 1) {
82 8 100       60 $spec->{predicate} = $name =~ /^_/ ? "_has${name}" : "has_${name}";
83             }
84 686 100 100     3089 if (($spec->{clearer}||0) eq 1) {
85 4 100       18 $spec->{clearer} = $name =~ /^_/ ? "_clear${name}" : "clear_${name}";
86             }
87 686 100 100     3220 if (($spec->{trigger}||0) eq 1) {
88 2         13 $spec->{trigger} = quote_sub('shift->_trigger_'.$name.'(@_)');
89             }
90 686 100 100     3399 if (($spec->{coerce}||0) eq 1) {
91 10         19 my $isa = $spec->{isa};
92 10 100 100     100 if (blessed $isa and $isa->can('coercion')) {
    100 100        
93 4         98 $spec->{coerce} = $isa->coercion;
94             } elsif (blessed $isa and $isa->can('coerce')) {
95 2     2   10 $spec->{coerce} = sub { $isa->coerce(@_) };
  2         270  
96             } else {
97 4         731 croak "Invalid coercion for $into->$name - no appropriate type constraint";
98             }
99             }
100              
101 682         1603 foreach my $setting (qw( isa coerce )) {
102 1364 100       3521 next if !exists $spec->{$setting};
103 182         941 $self->_validate_codulatable($setting, $spec->{$setting}, "$into->$name");
104             }
105              
106 672 100       1847 if (exists $spec->{default}) {
107 188 100       623 if (ref $spec->{default}) {
108 152         796 $self->_validate_codulatable('default', $spec->{default}, "$into->$name",
109             'or a non-ref');
110             }
111             }
112              
113 664 100       2433 if (exists $spec->{moosify}) {
114 8 100       23 if (ref $spec->{moosify} ne 'ARRAY') {
115 2         6 $spec->{moosify} = [$spec->{moosify}];
116             }
117              
118 8         13 foreach my $spec (@{$spec->{moosify}}) {
  8         20  
119 12         34 $self->_validate_codulatable('moosify', $spec, "$into->$name");
120             }
121             }
122              
123 664         1507 my %methods;
124 664 100       1900 if (my $reader = $spec->{reader}) {
125             _die_overwrite($into, $reader, 'a reader')
126 488 100 100     1548 if !$spec->{allow_overwrite} && defined &{"${into}::${reader}"};
  452         3541  
127 482 100 100     2077 if (our $CAN_HAZ_XS && $self->is_simple_get($name, $spec)) {
128 218         763 $methods{$reader} = $self->_generate_xs(
129             getters => $into, $reader, $name, $spec
130             );
131             } else {
132 264         686 $self->{captures} = {};
133             $methods{$reader} =
134             quote_sub "${into}::${reader}"
135             => ' Carp::croak("'.$reader.' is a read-only accessor") if @_ > 1;'."\n"
136             .$self->_generate_get($name, $spec)
137             => delete $self->{captures}
138 264         1380 => $quote_opts
139             ;
140             }
141             }
142 658 100       150925 if (my $accessor = $spec->{accessor}) {
143             _die_overwrite($into, $accessor, 'an accessor')
144 186 100 100     586 if !$spec->{allow_overwrite} && defined &{"${into}::${accessor}"};
  176         1255  
145 184 100 100     866 if (
      100        
146             our $CAN_HAZ_XS
147             && $self->is_simple_get($name, $spec)
148             && $self->is_simple_set($name, $spec)
149             ) {
150 31         91 $methods{$accessor} = $self->_generate_xs(
151             accessors => $into, $accessor, $name, $spec
152             );
153             } else {
154 153         410 $self->{captures} = {};
155             $methods{$accessor} =
156             quote_sub "${into}::${accessor}"
157             => $self->_generate_getset($name, $spec)
158             => delete $self->{captures}
159 153         610 => $quote_opts
160             ;
161             }
162             }
163 656 100       105399 if (my $writer = $spec->{writer}) {
164             _die_overwrite($into, $writer, 'a writer')
165 22 100 66     105 if !$spec->{allow_overwrite} && defined &{"${into}::${writer}"};
  22         178  
166 20 100 100     125 if (
167             our $CAN_HAZ_XS
168             && $self->is_simple_set($name, $spec)
169             ) {
170 5         16 $methods{$writer} = $self->_generate_xs(
171             setters => $into, $writer, $name, $spec
172             );
173             } else {
174 15         47 $self->{captures} = {};
175             $methods{$writer} =
176             quote_sub "${into}::${writer}"
177             => $self->_generate_set($name, $spec)
178             => delete $self->{captures}
179 15         83 => $quote_opts
180             ;
181             }
182             }
183 654 100       10622 if (my $pred = $spec->{predicate}) {
184             _die_overwrite($into, $pred, 'a predicate')
185 14 100 66     65 if !$spec->{allow_overwrite} && defined &{"${into}::${pred}"};
  14         121  
186 12 100 66     74 if (our $CAN_HAZ_XS && our $CAN_HAZ_XS_PRED) {
187 6         33 $methods{$pred} = $self->_generate_xs(
188             exists_predicates => $into, $pred, $name, $spec
189             );
190             } else {
191 6         17 $self->{captures} = {};
192             $methods{$pred} =
193             quote_sub "${into}::${pred}"
194             => $self->_generate_simple_has('$_[0]', $name, $spec)."\n"
195             => delete $self->{captures}
196 6         28 => $quote_opts
197             ;
198             }
199             }
200 652 100       4774 if (my $builder = delete $spec->{builder_sub}) {
201 10         94 _install_coderef( "${into}::$spec->{builder}" => $builder );
202             }
203 652 100       2011 if (my $cl = $spec->{clearer}) {
204             _die_overwrite($into, $cl, 'a clearer')
205 16 100 66     73 if !$spec->{allow_overwrite} && defined &{"${into}::${cl}"};
  16         139  
206 14         43 $self->{captures} = {};
207             $methods{$cl} =
208             quote_sub "${into}::${cl}"
209             => $self->_generate_simple_clear('$_[0]', $name, $spec)."\n"
210             => delete $self->{captures}
211 14         72 => $quote_opts
212             ;
213             }
214 650 100       9037 if (my $hspec = $spec->{handles}) {
215 42   66     230 my $asserter = $spec->{asserter} ||= '_assert_'.$name;
216 42         71 my @specs = do {
217 42 100       171 if (ref($hspec) eq 'ARRAY') {
    100          
    100          
218 10         53 map [ $_ => $_ ], @$hspec;
219             } elsif (ref($hspec) eq 'HASH') {
220 16 100       98 map [ $_ => ref($hspec->{$_}) ? @{$hspec->{$_}} : $hspec->{$_} ],
  2         11  
221             keys %$hspec;
222             } elsif (!ref($hspec)) {
223 14         1061 require Moo::Role;
224 14         81 map [ $_ => $_ ], Moo::Role->methods_provided_by($hspec)
225             } else {
226 2         439 croak "You gave me a handles of ${hspec} and I have no idea why";
227             }
228             };
229 36         430 foreach my $delegation_spec (@specs) {
230 38         1143 my ($proxy, $target, @args) = @$delegation_spec;
231             _die_overwrite($into, $proxy, 'a delegation')
232 38 100 100     116 if !$spec->{allow_overwrite} && defined &{"${into}::${proxy}"};
  34         238  
233 36         95 $self->{captures} = {};
234             $methods{$proxy} =
235             quote_sub "${into}::${proxy}"
236             => $self->_generate_delegation($asserter, $target, \@args)
237             => delete $self->{captures}
238 36         151 => $quote_opts
239             ;
240             }
241             }
242 642 100       19471 if (my $asserter = $spec->{asserter}) {
243             _die_overwrite($into, $asserter, 'an asserter')
244 44 100 100     174 if !$spec->{allow_overwrite} && defined &{"${into}::${asserter}"};
  36         270  
245 42         128 local $self->{captures} = {};
246             $methods{$asserter} =
247             quote_sub "${into}::${asserter}"
248             => $self->_generate_asserter($name, $spec)
249             => delete $self->{captures}
250 42         173 => $quote_opts
251             ;
252             }
253 640         25813 \%methods;
254             }
255              
256             sub merge_specs {
257 26     26 0 79 my ($self, @specs) = @_;
258 26         50 my $spec = shift @specs;
259 26         70 for my $old_spec (@specs) {
260 26         89 foreach my $key (keys %$old_spec) {
261 122 100 100     564 if ($key eq 'handles') {
    100          
    100          
    100          
262             }
263             elsif ($key eq 'moosify') {
264             $spec->{$key} = [
265 4 100       18 map { ref $_ eq 'ARRAY' ? @$_ : $_ }
266             grep defined,
267 2         11 ($old_spec->{$key}, $spec->{$key})
268             ];
269             }
270             elsif ($key eq 'builder' || $key eq 'default') {
271             $spec->{$key} = $old_spec->{$key}
272 24 100 100     144 if !(exists $spec->{builder} || exists $spec->{default});
273             }
274             elsif (!exists $spec->{$key}) {
275 74         159 $spec->{$key} = $old_spec->{$key};
276             }
277             }
278             }
279 26         88 $spec;
280             }
281              
282             sub is_simple_attribute {
283 4     4 0 777 my ($self, $name, $spec) = @_;
284             # clearer doesn't have to be listed because it doesn't
285             # affect whether defined/exists makes a difference
286 4         35 !grep $spec->{$_},
287             qw(lazy default builder coerce isa trigger predicate weak_ref);
288             }
289              
290             sub is_simple_get {
291 792     792 0 1803 my ($self, $name, $spec) = @_;
292 792   100     4028 !($spec->{lazy} and (exists $spec->{default} or $spec->{builder}));
293             }
294              
295             sub is_simple_set {
296 259     259 0 496 my ($self, $name, $spec) = @_;
297 259         1541 !grep $spec->{$_}, qw(coerce isa trigger weak_ref);
298             }
299              
300             sub has_default {
301 56     56 0 142 my ($self, $name, $spec) = @_;
302 56 100 50     983 $spec->{builder} or exists $spec->{default} or (($spec->{is}||'') eq 'lazy');
      100        
303             }
304              
305             sub has_eager_default {
306 1596     1596 0 2838 my ($self, $name, $spec) = @_;
307 1596 100 66     7237 (!$spec->{lazy} and (exists $spec->{default} or $spec->{builder}));
308             }
309              
310             sub _generate_get {
311 459     459   1162 my ($self, $name, $spec) = @_;
312 459         1295 my $simple = $self->_generate_simple_get('$_[0]', $name, $spec);
313 459 100       1411 if ($self->is_simple_get($name, $spec)) {
314 389         2166 $simple;
315             } else {
316 70         267 $self->_generate_use_default(
317             '$_[0]', $name, $spec,
318             $self->_generate_simple_has('$_[0]', $name, $spec),
319             );
320             }
321             }
322              
323             sub generate_simple_has {
324 14     14 0 24 my $self = shift;
325 14         29 $self->{captures} = {};
326 14         38 my $code = $self->_generate_simple_has(@_);
327 14         176 ($code, delete $self->{captures});
328             }
329              
330             sub _generate_simple_has {
331 132     132   323 my ($self, $me, $name) = @_;
332 132         285 "exists ${me}->{${\quotify $name}}";
  132         348  
333             }
334              
335             sub _generate_simple_clear {
336 14     14   45 my ($self, $me, $name) = @_;
337 14         36 " delete ${me}->{${\quotify $name}}\n"
  14         60  
338             }
339              
340             sub generate_get_default {
341 2     2 0 6 my $self = shift;
342 2         6 $self->{captures} = {};
343 2         7 my $code = $self->_generate_get_default(@_);
344 2         40 ($code, delete $self->{captures});
345             }
346              
347             sub generate_use_default {
348 14     14 0 23 my $self = shift;
349 14         27 $self->{captures} = {};
350 14         36 my $code = $self->_generate_use_default(@_);
351 14         47 ($code, delete $self->{captures});
352             }
353              
354             sub _generate_use_default {
355 84     84   871 my ($self, $me, $name, $spec, $test) = @_;
356 84         277 my $get_value = $self->_generate_get_default($me, $name, $spec);
357 84 100       649 if ($spec->{coerce}) {
358             $get_value = $self->_generate_coerce(
359             $name, $get_value,
360             $spec->{coerce}
361             )
362 6         18 }
363             $test." ? \n"
364             .$self->_generate_simple_get($me, $name, $spec)."\n:"
365             .($spec->{isa} ?
366             " do {\n my \$value = ".$get_value.";\n"
367 84 100       415 ." ".$self->_generate_isa_check($name, '$value', $spec->{isa}).";\n"
368             ." ".$self->_generate_simple_set($me, $name, $spec, '$value')."\n"
369             ." }\n"
370             : ' ('.$self->_generate_simple_set($me, $name, $spec, $get_value).")\n"
371             );
372             }
373              
374             sub _generate_get_default {
375 210     210   473 my ($self, $me, $name, $spec) = @_;
376 210 100       553 if (exists $spec->{default}) {
377             ref $spec->{default}
378             ? $self->_generate_call_code($name, 'default', $me, $spec->{default})
379 172 100       692 : quotify $spec->{default};
380             }
381             else {
382 38         79 "${me}->${\$spec->{builder}}"
  38         127  
383             }
384             }
385              
386             sub generate_simple_get {
387 2     2 0 2660 my ($self, @args) = @_;
388 2         7 $self->{captures} = {};
389 2         10 my $code = $self->_generate_simple_get(@args);
390 2         10 ($code, delete $self->{captures});
391             }
392              
393             sub _generate_simple_get {
394 676     676   1730 my ($self, $me, $name) = @_;
395 676         1702 my $name_str = quotify $name;
396 676         7150 "${me}->{${name_str}}";
397             }
398              
399             sub _generate_set {
400 168     168   335 my ($self, $name, $spec) = @_;
401 168         336 my ($me, $source) = ('$_[0]', '$_[1]');
402 168 100       503 if ($self->is_simple_set($name, $spec)) {
403 42         151 return $self->_generate_simple_set($me, $name, $spec, $source);
404             }
405              
406 126         277 my ($coerce, $trigger, $isa_check) = @{$spec}{qw(coerce trigger isa)};
  126         356  
407 126 100       315 if ($coerce) {
408 46         120 $source = $self->_generate_coerce($name, $source, $coerce);
409             }
410 126 100       1264 if ($isa_check) {
    100          
411 48 100       253 'scalar do { my $value = '.$source.";\n"
412             .' ('.$self->_generate_isa_check($name, '$value', $isa_check)."),\n"
413             .' ('.$self->_generate_simple_set($me, $name, $spec, '$value')."),\n"
414             .($trigger
415             ? '('.$self->_generate_trigger($name, $me, '$value', $trigger)."),\n"
416             : '')
417             .' ('.$self->_generate_simple_get($me, $name, $spec)."),\n"
418             ."}";
419             }
420             elsif ($trigger) {
421 20         51 my $set = $self->_generate_simple_set($me, $name, $spec, $source);
422 20         83 "scalar (\n"
423             . ' ('.$self->_generate_trigger($name, $me, "($set)", $trigger)."),\n"
424             . ' ('.$self->_generate_simple_get($me, $name, $spec)."),\n"
425             . ")";
426             }
427             else {
428 58         173 '('.$self->_generate_simple_set($me, $name, $spec, $source).')';
429             }
430             }
431              
432             sub generate_coerce {
433 2     2 0 2655 my $self = shift;
434 2         7 $self->{captures} = {};
435 2         11 my $code = $self->_generate_coerce(@_);
436 2         113 ($code, delete $self->{captures});
437             }
438              
439             sub _attr_desc {
440 268     268   540 my ($name, $init_arg) = @_;
441 268 100 100     1388 return quotify($name) if !defined($init_arg) or $init_arg eq $name;
442 10         25 return quotify($name).' (constructor argument: '.quotify($init_arg).')';
443             }
444              
445             sub _generate_coerce {
446 122     122   312 my ($self, $name, $value, $coerce, $init_arg) = @_;
447 122         478 $self->_wrap_attr_exception(
448             $name,
449             "coercion",
450             $init_arg,
451             $self->_generate_call_code($name, 'coerce', "${value}", $coerce),
452             1,
453             );
454             }
455              
456             sub generate_trigger {
457 2     2 0 3201 my $self = shift;
458 2         7 $self->{captures} = {};
459 2         9 my $code = $self->_generate_trigger(@_);
460 2         50 ($code, delete $self->{captures});
461             }
462              
463             sub _generate_trigger {
464 62     62   136 my ($self, $name, $obj, $value, $trigger) = @_;
465 62         185 $self->_generate_call_code($name, 'trigger', "${obj}, ${value}", $trigger);
466             }
467              
468             sub generate_isa_check {
469 2     2 0 2915 my ($self, @args) = @_;
470 2         7 $self->{captures} = {};
471 2         11 my $code = $self->_generate_isa_check(@args);
472 2         54 ($code, delete $self->{captures});
473             }
474              
475             sub _wrap_attr_exception {
476 268     268   3305 my ($self, $name, $step, $arg, $code, $want_return) = @_;
477 268         744 my $prefix = quotify("${step} for "._attr_desc($name, $arg).' failed: ');
478 268 100       4273 "do {\n"
    100          
    100          
479             .' local $Method::Generate::Accessor::CurrentAttribute = {'."\n"
480             .' init_arg => '.quotify($arg).",\n"
481             .' name => '.quotify($name).",\n"
482             .' step => '.quotify($step).",\n"
483             ." };\n"
484             .($want_return ? ' (my $_return),'."\n" : '')
485             .' (my $_error), (my $_old_error = $@);'."\n"
486             ." (eval {\n"
487             .' ($@ = $_old_error),'."\n"
488             .' ('
489             .($want_return ? '$_return ='."\n" : '')
490             .$code."),\n"
491             ." 1\n"
492             ." } or\n"
493             .' $_error = CORE::ref $@ ? $@ : '.$prefix.'.$@);'."\n"
494             .' ($@ = $_old_error),'."\n"
495             .' (defined $_error and CORE::die $_error);'."\n"
496             .($want_return ? ' $_return;'."\n" : '')
497             ."}\n"
498             }
499              
500             sub _generate_isa_check {
501 146     146   476 my ($self, $name, $value, $check, $init_arg) = @_;
502 146         445 $self->_wrap_attr_exception(
503             $name,
504             "isa check",
505             $init_arg,
506             $self->_generate_call_code($name, 'isa_check', $value, $check)
507             );
508             }
509              
510             sub _generate_call_code {
511 458     458   998 my ($self, $name, $type, $values, $sub) = @_;
512 458 100       1363 $sub = \&{$sub} if blessed($sub); # coderef if blessed
  22         63  
513 458 100       3246 if (my $quoted = quoted_from_sub($sub)) {
514 104         5298 my $local = 1;
515 104 100 66     546 if ($values eq '@_' || $values eq '$_[0]') {
516 4         10 $local = 0;
517 4         13 $values = '@_';
518             }
519 104         199 my $code = $quoted->[1];
520 104 100       254 if (my $captures = $quoted->[2]) {
521 38         206 my $cap_name = qq{\$${type}_captures_for_}.sanitize_identifier($name);
522 38         520 $self->{captures}->{$cap_name} = \$captures;
523 38         122 Sub::Quote::inlinify($code, $values,
524             Sub::Quote::capture_unroll($cap_name, $captures, 6), $local);
525             } else {
526 66         201 Sub::Quote::inlinify($code, $values, undef, $local);
527             }
528             } else {
529 354         3209 my $cap_name = qq{\$${type}_for_}.sanitize_identifier($name);
530 354         4232 $self->{captures}->{$cap_name} = \$sub;
531 354         1382 "${cap_name}->(${values})";
532             }
533             }
534              
535 2     2   10430 sub _sanitize_name { sanitize_identifier($_[1]) }
536              
537             sub generate_populate_set {
538 1560     1560 0 5514 my $self = shift;
539 1560         3015 $self->{captures} = {};
540 1560         3513 my $code = $self->_generate_populate_set(@_);
541 1560         7141 ($code, delete $self->{captures});
542             }
543              
544             sub _generate_populate_set {
545 1560     1560   3557 my ($self, $me, $name, $spec, $source, $test, $init_arg) = @_;
546              
547 1560         3364 my $has_default = $self->has_eager_default($name, $spec);
548 1560 100 100     5603 if (!($has_default || $test)) {
549 2         6 return '';
550             }
551 1558 100       3127 if ($has_default) {
552 124         358 my $get_default = $self->_generate_get_default($me, $name, $spec);
553 124 100       929 $source =
554             $test
555             ? "(\n ${test}\n"
556             ." ? ${source}\n : "
557             .$get_default
558             .")"
559             : $get_default;
560             }
561 1558 100       3299 if ($spec->{coerce}) {
562             $source = $self->_generate_coerce(
563             $name, $source,
564 68         214 $spec->{coerce}, $init_arg
565             )
566             }
567 1558 100       4599 if ($spec->{isa}) {
568             $source = 'scalar do { my $value = '.$source.";\n"
569             .' ('.$self->_generate_isa_check(
570 84         379 $name, '$value', $spec->{isa}, $init_arg
571             )."),\n"
572             ." \$value\n"
573             ."}\n";
574             }
575 1558         5821 my $set = $self->_generate_simple_set($me, $name, $spec, $source);
576             my $trigger = $spec->{trigger} ? $self->_generate_trigger(
577             $name, $me, $self->_generate_simple_get($me, $name, $spec),
578             $spec->{trigger}
579 1558 100       3273 ) : undef;
580 1558 100       3101 if ($has_default) {
581 124 100 100     737 "($set)," . ($trigger && $test ? "($test and $trigger)," : '') . "\n";
582             }
583             else {
584 1434 100       6154 "($test and ($set)" . ($trigger ? ", ($trigger)" : '') . "),\n";
585             }
586             }
587              
588             sub _generate_core_set {
589 1772     1772   3440 my ($self, $me, $name, $spec, $value) = @_;
590 1772         3298 my $name_str = quotify $name;
591 1772         13419 "${me}->{${name_str}} = ${value}";
592             }
593              
594             sub _generate_simple_set {
595 1810     1810   5156 my ($self, $me, $name, $spec, $value) = @_;
596 1810         3845 my $name_str = quotify $name;
597 1810         14636 my $simple = $self->_generate_core_set($me, $name, $spec, $value);
598              
599 1810 100       4329 if ($spec->{weak_ref}) {
600 44         237 require Scalar::Util;
601 44         104 my $get = $self->_generate_simple_get($me, $name, $spec);
602              
603             # Perl < 5.8.3 can't weaken refs to readonly vars
604             # (e.g. string constants). This *can* be solved by:
605             #
606             # &Internals::SvREADONLY($foo, 0);
607             # Scalar::Util::weaken($foo);
608             # &Internals::SvREADONLY($foo, 1);
609             #
610             # but requires Internal functions and is just too damn crazy
611             # so simply throw a better exception
612 44         266 my $weak_simple = _CAN_WEAKEN_READONLY
613             ? "do { Scalar::Util::weaken(${simple}); no warnings 'void'; $get }"
614             : <<"EOC"
615             ( eval { Scalar::Util::weaken($simple); 1 }
616             ? do { no warnings 'void'; $get }
617             : do {
618             if( \$@ =~ /Modification of a read-only value attempted/) {
619             require Carp;
620             Carp::croak( sprintf (
621             'Reference to readonly value in "%s" can not be weakened on Perl < 5.8.3',
622             $name_str,
623             ) );
624             } else {
625             die \$@;
626             }
627             }
628             )
629             EOC
630             } else {
631 1766         4514 $simple;
632             }
633             }
634              
635             sub _generate_getset {
636 153     153   391 my ($self, $name, $spec) = @_;
637 153         500 q{(@_ > 1}."\n ? ".$self->_generate_set($name, $spec)
638             ."\n : ".$self->_generate_get($name, $spec)."\n )";
639             }
640              
641             sub _generate_asserter {
642 42     42   106 my ($self, $name, $spec) = @_;
643 42         145 my $name_str = quotify($name);
644 42         476 "do {\n"
645             ." my \$val = ".$self->_generate_get($name, $spec).";\n"
646             ." ".$self->_generate_simple_has('$_[0]', $name, $spec)."\n"
647             ." or Carp::croak(q{Attempted to access '}.${name_str}.q{' but it is not set});\n"
648             ." \$val;\n"
649             ."}\n";
650             }
651             sub _generate_delegation {
652 36     36   93 my ($self, $asserter, $target, $args) = @_;
653 36         55 my $arg_string = do {
654 36 100       86 if (@$args) {
655             # I could, I reckon, linearise out non-refs here using quotify
656             # plus something to check for numbers but I'm unsure if it's worth it
657 2         5 $self->{captures}{'@curries'} = $args;
658 2         4 '@curries, @_';
659             } else {
660 34         114 '@_';
661             }
662             };
663 36         224 "shift->${asserter}->${target}(${arg_string});";
664             }
665              
666             sub _generate_xs {
667 249     249   636 my ($self, $type, $into, $name, $slot) = @_;
668 249         1682 Class::XSAccessor->import(
669             class => $into,
670             $type => { $name => $slot },
671             replace => 1,
672             );
673 249         36689 $into->can($name);
674             }
675              
676 426     426 0 2843 sub default_construction_string { '{}' }
677              
678             sub _validate_codulatable {
679 356     356   878 my ($self, $setting, $value, $into, $appended) = @_;
680              
681 356         852 my $error;
682              
683 356 100       1624 if (blessed $value) {
    100          
684 34         63 local $@;
685 188     188   2646 no warnings 'void';
  188         544  
  188         35507  
686 34 100       58 eval { \&$value; 1 }
  34         333  
  24         2341  
687             and return 1;
688 10         30 $error = "could not be converted to a coderef: $@";
689             }
690             elsif (ref $value eq 'CODE') {
691 314         856 return 1;
692             }
693             else {
694 8         16 $error = 'is not a coderef or code-convertible object';
695             }
696              
697             croak "Invalid $setting '"
698 18 100       625 . ($INC{'overload.pm'} ? overload::StrVal($value) : $value)
    100          
699             . "' for $into " . $error
700             . ($appended ? " $appended" : '');
701             }
702              
703             1;