File Coverage

blib/lib/Sub/Accessor/Small.pm
Criterion Covered Total %
statement 191 271 70.4
branch 76 162 46.9
condition 21 98 21.4
subroutine 45 53 84.9
pod 0 35 0.0
total 333 619 53.8


line stmt bran cond sub pod time code
1 8     8   70964 use 5.008003;
  8         74  
2 8     8   51 use strict;
  8         16  
  8         166  
3 8     8   37 use warnings;
  8         14  
  8         255  
4 8     8   43 no warnings qw( void once uninitialized );
  8         23  
  8         444  
5              
6             package Sub::Accessor::Small;
7              
8 8     8   62 use Carp qw( carp croak );
  8         15  
  8         413  
9 8     8   1606 use Eval::TypeTiny qw();
  8         5881  
  8         192  
10 8     8   1524 use Exporter::Tiny qw();
  8         10734  
  8         225  
11 8     8   60 use Scalar::Util qw( blessed reftype );
  8         21  
  8         1340  
12              
13             BEGIN {
14 8         1579 *HAS_SUB_UTIL = eval { require Sub::Util }
15             ? sub(){1}
16 8 50   8   34 : sub(){0};
17             *HAS_SUB_NAME = !HAS_SUB_UTIL() && eval { require Sub::Name }
18             ? sub(){1}
19 8 50 33     1739 : sub(){0};
20             };
21              
22             BEGIN {
23             *fieldhash =
24             eval { require Hash::FieldHash; \&Hash::FieldHash::fieldhash } ||
25             eval { require Hash::Util::FieldHash; \&Hash::Util::FieldHash::fieldhash } ||
26 8   33 8   28 do { require Hash::Util::FieldHash::Compat; \&Hash::Util::FieldHash::Compat::fieldhash } ;;
27             };
28              
29             our $AUTHORITY = 'cpan:TOBYINK';
30             our $VERSION = '0.013';
31             our @ISA = qw/ Exporter::Tiny /;
32              
33             fieldhash( our %FIELDS );
34              
35             sub _generate_has : method
36             {
37 8     8   196 my $me = shift;
38 8         16 my (undef, undef, $export_opts) = @_;
39            
40             my $code = sub
41             {
42 24     24   3643 my $attr = $me->new_from_has($export_opts, @_);
        24      
43 24         85 $attr->install_accessors;
44 8         42 };
45            
46 8         94 HAS_SUB_UTIL ? ($code = Sub::Util::set_subname("$me\::has", $code)) :
47             HAS_SUB_NAME ? ($code = Sub::Name::subname("$me\::has", $code)) :
48             ();
49 8         88 return $code;
50             }
51              
52             {
53             my $uniq = 0;
54             sub new_from_has : method
55             {
56 24     24 0 50 my $me = shift;
57 24 50       81 my $export_opts = ref($_[0]) eq 'HASH' ? shift(@_) : {};
58 24 50       177 my ($name, %opts) = (@_%2) ? @_ : (undef, @_);
59            
60 24         43 my $package;
61             $package = $export_opts->{into}
62 24 50 33     145 if defined($export_opts->{into}) && !ref($export_opts->{into});
63            
64 24 50       137 $me->new(
65             slot => $name,
66             id => $uniq++,
67             _export => $export_opts,
68             ($package ? (package => $package) : ()),
69             %opts,
70             );
71             }
72             }
73              
74             sub has : method
75             {
76 0     0 0 0 my $me = shift;
77 0         0 my $attr = $me->new_from_has(@_);
78 0         0 $attr->install_accessors;
79             }
80              
81             sub new : method
82             {
83 24     24 0 51 my $me = shift;
84 24         109 my (%opts) = @_;
85 24         54 my $self = bless(\%opts, $me);
86 24         91 $self->canonicalize_opts;
87 24         86 return $self;
88             }
89              
90             sub install_accessors : method
91             {
92 24     24 0 38 my $me = shift;
93            
94 24         54 for my $type (qw( accessor reader writer predicate clearer ))
95             {
96 120 100       305 next unless defined $me->{$type};
97 44         227 $me->install_coderef($me->{$type}, $me->$type);
98             }
99            
100 24 100       69 if (defined $me->{handles}) {
101 1         2 my $shv_data;
102 1 50 33     7 if ($me->{traits} or $me->{handles_via}) {
103 1         2 my $orig_handles = $me->{handles};
104 1         6 require Sub::HandlesVia::Toolkit::Plain;
105             $shv_data = 'Sub::HandlesVia::Toolkit::Plain'->clean_spec(
106             $me->{package},
107             $me->{slot},
108 1         17 +{%$me},
109             );
110 1 50       56 if ($shv_data) {
111             my @default =
112             ref($me->{default}) ? ( $me->{default} ) :
113 1 50       6 length($me->{builder}) ? ( $me->{builder} ) :
    50          
114             ();
115             my $callbacks = 'Sub::HandlesVia::Toolkit::Plain'->make_callbacks(
116             $me->{package},
117 1         7 [ $me->reader, $me->writer, @default ],
118             );
119 1         71 require Sub::HandlesVia::Handler;
120 1         3 $me->{handles} = $orig_handles;
121 1         4 my @pairs = $me->expand_handles;
122 1         4 while (@pairs) {
123 2         22 my ($target, $method) = splice(@pairs, 0, 2);
124 2         14 my $handler = 'Sub::HandlesVia::Handler'->lookup($method, $shv_data->{handles_via});
125             $me->install_coderef(
126             $target,
127             $handler->coderef(
128             %$callbacks,
129             target => $me->{package},
130 2 100       9066 method_name => ref($target) ? '__ANON__' : $target,
131             ),
132             );
133             }
134             }
135             }
136            
137 1 50       41 if (!$shv_data) {
138 0         0 my @pairs = $me->expand_handles;
139 0         0 while (@pairs) {
140 0         0 my ($target, $method) = splice(@pairs, 0, 2);
141 0         0 $me->install_coderef($target, $me->handles($method));
142             }
143             }
144             }
145            
146             my @return = map $$_,
147             $me->{is} eq 'ro' ? ($me->{reader}) :
148             $me->{is} eq 'rw' ? ($me->{accessor}) :
149             $me->{is} eq 'rwp' ? ($me->{reader}, $me->{writer}) :
150 24 100       185 $me->{is} eq 'lazy' ? ($me->{reader}) :
    100          
    100          
    100          
151             ();
152 24 100       3176 wantarray ? @return : $return[0];
153             }
154              
155             sub install_coderef
156             {
157 46     46 0 2699 my $me = shift;
158 46         121 my ($target, $coderef) = @_;
159            
160 46 50       135 return unless defined $target;
161            
162 46 100 66     168 if (!ref $target and $target =~ /\A[^\W0-9]\w+\z/)
163             {
164 3         13 my $name = "$me->{package}\::$target";
165 3         27 HAS_SUB_UTIL ? ($coderef = Sub::Util::set_subname($name, $coderef)) :
166             HAS_SUB_NAME ? ($coderef = Sub::Name::subname($name, $coderef)) :
167             ();
168 8     8   86 no strict qw(refs);
  8         19  
  8         24785  
169 3         13 *$name = $coderef;
170 3         13 return;
171             }
172            
173 43 50 33     211 if (ref($target) eq q(SCALAR) and not defined $$target)
174             {
175 43         70 $$target = $coderef;
176 43         119 return;
177             }
178            
179 0 0 0     0 if (!ref($target) and $target eq 1)
180             {
181 0         0 return;
182             }
183            
184 0         0 croak "Expected installation target to be a reference to an undefined scalar; got $target";
185             }
186              
187             sub expand_handles
188             {
189 0     0 0 0 my $me = shift;
190            
191 0 0       0 if (ref($me->{handles}) eq q(ARRAY))
    0          
192             {
193 0         0 return map ($_=>$_), @{$me->{handles}};
  0         0  
194             }
195             elsif (ref($me->{handles}) eq q(HASH))
196             {
197 0         0 return %{$me->{handles}};
  0         0  
198             }
199            
200 0         0 croak "Expected delegations to be a reference to an array or hash; got $me->{handles}";
201             }
202              
203             {
204             my %one = (
205             accessor => [qw/ %s %s /],
206             reader => [qw/ get_%s _get%s /],
207             writer => [qw/ set_%s _set%s /],
208             predicate => [qw/ has_%s _has%s /],
209             clearer => [qw/ clear_%s _clear%s /],
210             trigger => [qw/ _trigger_%s _trigger_%s /],
211             builder => [qw/ _builder_%s _builder_%s /],
212             );
213            
214             sub canonicalize_1 : method
215             {
216 24     24 0 40 my $me = shift;
217            
218 24 50       92 my $is_private = ($me->{slot} =~ /\A_/) ? 1 : 0;
219            
220 24         84 for my $type (keys %one)
221             {
222 168 100       326 next if !exists($me->{$type});
223 48 100       118 next if ref($me->{$type});
224 2 50       5 next if $me->{$type} ne 1;
225            
226             croak("Cannot interpret $type=>1 because attribute has no name defined")
227 0 0       0 if !defined $me->{slot};
228            
229 0         0 $me->{$type} = sprintf($one{$type}[$is_private], $me->{slot});
230             }
231             }
232            
233             sub canonicalize_builder : method
234             {
235 24     24 0 36 my $me = shift;
236 24         42 my $name = $me->{slot};
237            
238 24 50       62 if (ref $me->{builder} eq 'CODE')
239             {
240             HAS_SUB_UTIL or
241             HAS_SUB_NAME or
242 0         0 do { require Sub::Util };
243            
244 0         0 my $code = $me->{builder};
245             defined($name) && defined($me->{package})
246 0 0 0     0 or croak("Invalid builder; expected method name as string");
247            
248 0 0       0 my $is_private = ($name =~ /\A_/) ? 1 : 0;
249            
250 0         0 my $subname = sprintf($one{builder}[$is_private], $name);
251 0         0 my $fq_subname = "$me->{package}\::$name";
252             $me->_exporter_install_sub(
253             $subname,
254             {},
255             $me->{_export},
256 0         0 Sub::Name::subname($fq_subname, $code),
257             );
258             }
259             }
260             }
261              
262             sub canonicalize_is : method
263             {
264 2     2 0 3 my $me = shift;
265 2         4 my $name = $me->{slot};
266            
267 2 50       10 if ($me->{is} eq 'rw')
    50          
    50          
    50          
268             {
269             $me->{accessor} = $name
270 0 0 0     0 if !exists($me->{accessor}) and defined $name;
271             }
272             elsif ($me->{is} eq 'ro')
273             {
274             $me->{reader} = $name
275 0 0 0     0 if !exists($me->{reader}) and defined $name;
276             }
277             elsif ($me->{is} eq 'rwp')
278             {
279             $me->{reader} = $name
280 0 0 0     0 if !exists($me->{reader}) and defined $name;
281             $me->{writer} = "_set_$name"
282 0 0 0     0 if !exists($me->{writer}) and defined $name;
283             }
284             elsif ($me->{is} eq 'lazy')
285             {
286             $me->{reader} = $name
287 0 0 0     0 if !exists($me->{reader}) and defined $name;
288             $me->{lazy} = 1
289 0 0       0 if !exists($me->{lazy});
290             $me->{builder} = 1
291 0 0 0     0 unless $me->{builder} || $me->{default};
292             }
293             }
294              
295             sub canonicalize_default : method
296             {
297 24     24 0 39 my $me = shift;
298 24 100       75 return unless exists $me->{default};
299            
300 5 50       28 unless (ref $me->{default})
301             {
302 0         0 my $value = $me->{default};
303 0     0   0 $me->{default} = sub { $value };
  0         0  
304             }
305            
306             croak("Invalid default; expected a CODE ref")
307 5 50       22 unless ref $me->{default} eq 'CODE';
308             }
309              
310             sub canonicalize_isa : method
311             {
312 24     24 0 44 my $me = shift;
313            
314 24 50       78 if (my $does = $me->{does})
315             {
316 0 0 0 0   0 $me->{isa} ||= sub { blessed($_[0]) && $_[0]->DOES($does) };
  0         0  
317             }
318            
319 24 50 66     84 if (defined $me->{isa} and not ref $me->{isa})
320             {
321 0         0 my $type_name = $me->{isa};
322 0 0       0 eval { require Type::Utils }
  0         0  
323             or croak("Missing requirement; type constraint strings require Type::Utils");
324            
325             $me->{isa} = $me->{package}
326             ? Type::Utils::dwim_type($type_name, for => $me->{package})
327 0 0       0 : Type::Utils::dwim_type($type_name);
328             }
329             }
330              
331             sub canonicalize_trigger : method
332             {
333 24     24 0 40 my $me = shift;
334            
335 24 50 66     91 if (defined $me->{trigger} and not ref $me->{trigger})
336             {
337 0         0 my $method_name = $me->{trigger};
338 0     0   0 $me->{trigger} = sub { my $self = shift; $self->$method_name(@_) };
  0         0  
  0         0  
339             }
340             }
341              
342             sub canonicalize_opts : method
343             {
344 24     24 0 41 my $me = shift;
345            
346 24 50       104 croak("Initializers are not supported") if $me->{initializer};
347 24 50       82 croak("Traits are not supported") if $me->{traits};
348 24 50       60 croak("The lazy_build option is not supported") if $me->{lazy_build};
349            
350 24         79 $me->canonicalize_1;
351 24         105 $me->canonicalize_is;
352 24         115 $me->canonicalize_isa;
353 24         84 $me->canonicalize_default;
354 24         77 $me->canonicalize_builder;
355 24         68 $me->canonicalize_trigger;
356             }
357              
358             sub accessor_kind : method
359             {
360 2     2 0 5 return 'small';
361             }
362              
363             sub inline_to_coderef : method
364             {
365 46     46 0 80 my $me = shift;
366 46         82 my ($method_type, $code) = @_;
367              
368 46         108 my $kind = $me->accessor_kind;
369 46         137 my $src = sprintf(q[sub { %s }], $code);
370             my $desc = defined($me->{slot})
371             ? sprintf('%s %s for %s', $kind, $method_type, $me->{slot})
372 46 50       177 : sprintf('%s %s', $kind, $method_type);
373             # warn "#### $desc\n$src\n";
374            
375             return Eval::TypeTiny::eval_closure(
376             source => $src,
377             environment => $me->{inline_environment},
378 46         180 description => $desc,
379             );
380             }
381              
382             sub clearer : method
383             {
384 4     4 0 12 my $me = shift;
385            
386 4         25 $me->inline_to_coderef(
387             clearer => $me->inline_clearer,
388             );
389             }
390              
391             sub inline_clearer : method
392             {
393 4     4 0 10 my $me = shift;
394            
395 4         12 sprintf(
396             q[ delete(%s) ],
397             $me->inline_access,
398             );
399             }
400              
401             sub inline_access : method
402             {
403 88     88 0 125 my $me = shift;
404            
405             sprintf(
406             q[ $Sub::Accessor::Small::FIELDS{$_[0]}{%d} ],
407             $me->{id},
408 88         473 );
409             }
410              
411             sub inline_access_w : method
412             {
413 26     26 0 70 my $me = shift;
414 26         54 my ($expr) = @_;
415            
416 26         62 sprintf(
417             q[ %s = %s ],
418             $me->inline_access,
419             $expr,
420             );
421             }
422              
423             sub predicate : method
424             {
425 4     4 0 12 my $me = shift;
426            
427 4         22 $me->inline_to_coderef(
428             predicate => $me->inline_predicate,
429             );
430             }
431              
432             sub inline_predicate : method
433             {
434 9     9 0 19 my $me = shift;
435            
436 9         24 sprintf(
437             q[ exists(%s) ],
438             $me->inline_access,
439             );
440             }
441              
442             sub handles : method
443             {
444 0     0 0 0 my $me = shift;
445 0         0 my ($method) = @_;
446            
447 0         0 $me->inline_to_coderef(
448             'delegated method' => $me->inline_handles,
449             );
450             }
451              
452             my $handler_uniq = 0;
453             sub inline_handles : method
454             {
455 0     0 0 0 my $me = shift;
456 0         0 my ($method) = @_;
457            
458 0         0 my $get = $me->inline_access;
459            
460 0         0 my $varname = sprintf('$handler_%d', ++$handler_uniq);
461 0         0 $me->{inline_environment}{$varname} = \($method);
462            
463 0         0 my $death = 'Scalar::Util::blessed($h) or Carp::croak("Expected blessed object to delegate to; got $h")';
464            
465 0 0       0 if (ref $method eq 'ARRAY')
466             {
467 0         0 return sprintf(
468             q[ %s; my $h = %s; %s; shift; my ($m, @a) = @%s; $h->$m(@a, @_) ],
469             $me->inline_default,
470             $get,
471             $death,
472             $varname,
473             );
474             }
475             else
476             {
477 0         0 return sprintf(
478             q[ %s; my $h = %s; %s; shift; $h->%s(@_) ],
479             $me->inline_default,
480             $get,
481             $death,
482             $varname,
483             );
484             }
485             }
486              
487             sub inline_get : method
488             {
489 29     29 0 72 my $me = shift;
490            
491 29         65 my $get = $me->inline_access;
492            
493 29 50       99 if ($me->{auto_deref})
494             {
495 0         0 $get = sprintf(
496             q[ do { my $x = %s; wantarray ? (ref($x) eq 'ARRAY' ? @$x : ref($x) eq 'HASH' ? %$x : $x ) : $x } ],
497             $get,
498             );
499             }
500            
501 29         154 return $get;
502             }
503              
504             sub inline_default : method
505             {
506 22     22 0 39 my $me = shift;
507            
508 22 100       53 if ($me->{lazy})
509             {
510 5         15 my $get = $me->inline_access;
511            
512 5 50       24 if ($me->{default})
    0          
513             {
514 5         29 $me->{inline_environment}{'$default'} = \($me->{default});
515            
516 5         18 return sprintf(
517             q[ %s unless %s; ],
518             $me->inline_access_w( q[$default->($_[0])] ),
519             $me->inline_predicate,
520             );
521             }
522             elsif (defined $me->{builder})
523             {
524             return sprintf(
525             q[ %s unless %s; ],
526 0         0 $me->inline_access_w( q($_[0]->) . $me->{builder} ),
527             $me->inline_predicate,
528             );
529             }
530             }
531            
532 17         120 return '';
533             }
534              
535             sub reader : method
536             {
537 17     17 0 30 my $me = shift;
538            
539 17         39 $me->inline_to_coderef(
540             reader => $me->inline_reader,
541             );
542             }
543              
544             sub inline_reader : method
545             {
546 22     22 0 83 my $me = shift;
547            
548 22         64 join('',
549             $me->inline_default,
550             $me->inline_get,
551             );
552             }
553              
554             sub writer : method
555             {
556 9     9 0 21 my $me = shift;
557            
558 9         35 $me->inline_to_coderef(
559             writer => $me->inline_writer,
560             );
561             }
562              
563             sub inline_writer : method
564             {
565 9     9 0 15 my $me = shift;
566            
567 9         23 my $get = $me->inline_access;
568 9         38 my $coerce = $me->inline_type_coercion('$_[1]');
569            
570 9 100       967 if ($coerce eq '$_[1]') # i.e. no coercion
571             {
572 5 50 33     40 if (!$me->{trigger} and !$me->{weak_ref})
573             {
574 5         19 return $me->inline_access_w(
575             $me->inline_type_assertion('$_[1]'),
576             );
577             }
578            
579 0         0 return sprintf(
580             '%s; %s; %s; %s; %s',
581             $me->inline_type_assertion('$_[1]'),
582             $me->inline_trigger('$_[1]', $get),
583             $me->inline_access_w('$_[1]'),
584             $me->inline_weaken,
585             $me->inline_get,
586             );
587             }
588            
589             sprintf(
590 4         16 'my $val = %s; %s; %s; %s; %s; $val',
591             $coerce,
592             $me->inline_type_assertion('$val'),
593             $me->inline_trigger('$val', $get),
594             $me->inline_access_w('$val'),
595             $me->inline_weaken,
596             );
597             }
598              
599             sub accessor : method
600             {
601 12     12 0 27 my $me = shift;
602            
603 12         50 $me->inline_to_coderef(
604             accessor => $me->inline_accessor,
605             );
606             }
607              
608             sub inline_accessor : method
609             {
610 12     12 0 31 my $me = shift;
611              
612 12         57 my $get = $me->inline_access;
613 12         68 my $coerce = $me->inline_type_coercion('$_[1]');
614            
615 12 100       1182 if ($coerce eq '$_[1]') # i.e. no coercion
616             {
617 8 50 66     61 if (!$me->{lazy} and !$me->{trigger} and !$me->{weak_ref})
      33        
618             {
619 7         86 return sprintf(
620             '(@_ > 1) ? (%s) : %s',
621             $me->inline_access_w( $me->inline_type_assertion('$_[1]') ),
622             $me->inline_get,
623             );
624             }
625            
626 1         4 return sprintf(
627             'if (@_ > 1) { %s; %s; %s; %s }; %s',
628             $me->inline_type_assertion('$_[1]'),
629             $me->inline_trigger('$_[1]', $get),
630             $me->inline_access_w('$_[1]'),
631             $me->inline_weaken,
632             $me->inline_reader,
633             );
634             }
635            
636             sprintf(
637 4         53 'if (@_ > 1) { my $val = %s; %s; %s; %s; %s }; %s',
638             $coerce,
639             $me->inline_type_assertion('$val'),
640             $me->inline_trigger('$val', $get),
641             $me->inline_access_w('$val'),
642             $me->inline_weaken,
643             $me->inline_reader,
644             );
645             }
646              
647             sub inline_type_coercion : method
648             {
649 21     21 0 46 my $me = shift;
650 21         57 my ($var) = @_;
651            
652 21 100       92 my $coercion = $me->{coerce} or return $var;
653            
654 8 50       24 unless (ref $coercion)
655             {
656 8         18 my $type = $me->{isa};
657            
658 8 50 33     57 if (blessed($type) and $type->can('coercion'))
    0 0        
659             {
660 8         106 $coercion = $type->coercion;
661             }
662             elsif (blessed($type) and $type->can('coerce'))
663             {
664 0     0   0 $coercion = sub { $type->coerce(@_) };
  0         0  
665             }
666             else
667             {
668 0         0 croak("Invalid coerce; type constraint cannot be probed for coercion");
669             }
670            
671 8 50       104 unless (ref $coercion)
672             {
673 0         0 carp("Invalid coerce; type constraint has no coercion");
674 0         0 return $var;
675             }
676             }
677            
678 8 50 33     64 if ( blessed($coercion)
      33        
      33        
679             and $coercion->can('can_be_inlined')
680             and $coercion->can_be_inlined
681             and $coercion->can('inline_coercion') )
682             {
683 8         1015 return $coercion->inline_coercion($var);
684             }
685            
686             # Otherwise need to close over $coerce
687 0         0 $me->{inline_environment}{'$coercion'} = \$coercion;
688            
689 0 0 0     0 if ( blessed($coercion)
690             and $coercion->can('coerce') )
691             {
692 0         0 return sprintf('$coercion->coerce(%s)', $var);
693             }
694            
695 0         0 return sprintf('$coercion->(%s)', $var);
696             }
697              
698             sub inline_type_assertion : method
699             {
700 21     21 0 42 my $me = shift;
701 21         52 my ($var) = @_;
702            
703 21 100       141 my $type = $me->{isa} or return $var;
704            
705 10 50 33     138 if ( blessed($type)
      33        
706             and $type->isa('Type::Tiny')
707             and $type->can_be_inlined )
708             {
709 10         478 my $ass = $type->inline_assert($var);
710 10 50       1381 if ($ass =~ /\Ado \{(.+)\};\z/sm)
711             {
712 10         109 return "do { $1 }"; # i.e. drop trailing ";"
713             }
714             # otherwise protect expression from trailing ";"
715 0         0 return "do { $ass }"
716             }
717            
718             # Otherwise need to close over $type
719 0         0 $me->{inline_environment}{'$type'} = \$type;
720            
721             # non-Type::Tiny but still supports inlining
722 0 0 0     0 if ( blessed($type)
      0        
723             and $type->can('can_be_inlined')
724             and $type->can_be_inlined )
725             {
726 0   0     0 my $inliner = $type->can('inline_check') || $type->can('_inline_check');
727 0 0       0 if ($inliner)
728             {
729 0         0 return sprintf('do { %s } ? %s : Carp::croak($type->get_message(%s))', $type->$inliner($var), $var, $var);
730             }
731             }
732            
733 0 0 0     0 if ( blessed($type)
      0        
734             and $type->can('check')
735             and $type->can('get_message') )
736             {
737 0         0 return sprintf('$type->check(%s) ? %s : Carp::croak($type->get_message(%s))', $var, $var, $var);
738             }
739            
740 0         0 return sprintf('$type->(%s) ? %s : Carp::croak("Value %s failed type constraint check")', $var, $var, $var);
741             }
742              
743             sub inline_weaken : method
744             {
745 9     9 0 47 my $me = shift;
746            
747 9 50       70 return '' unless $me->{weak_ref};
748            
749 0         0 sprintf(
750             q[ Scalar::Util::weaken(%s) if ref(%s) ],
751             $me->inline_access,
752             $me->inline_access,
753             );
754             }
755              
756             sub inline_trigger : method
757             {
758 9     9 0 22 my $me = shift;
759 9         24 my ($new, $old) = @_;
760            
761 9 100       39 my $trigger = $me->{trigger} or return '';
762            
763 8         23 $me->{inline_environment}{'$trigger'} = \$trigger;
764 8         69 return sprintf('$trigger->($_[0], %s, %s)', $new, $old);
765             }
766              
767             1;
768              
769             __END__
770              
771             =pod
772              
773             =encoding utf-8
774              
775             =for stopwords benchmarking
776              
777             =head1 NAME
778              
779             Sub::Accessor::Small - small toolkit for generating getter/setter methods
780              
781             =head1 SYNOPSIS
782              
783             package MyClass;
784             use Sub::Accessor::Small;
785             use Types::Standard qw( Int );
786            
787             sub new {
788             my $class = shift;
789             my $self = bless \$class, $class;
790             my %args = @_ == 1 ? %{ $_[0] } : @_;
791            
792             # Simple way to initialize each attribute
793             for my $key ( sort keys %args ) {
794             $self->$key( $args{$key} );
795             }
796            
797             return $self;
798             }
799            
800             'Sub::Accessor::Small'->new(
801             package => __PACKAGE__,
802             name => "foo",
803             is => "rw",
804             isa => Int,
805             )->install_accessors();
806            
807             package main;
808            
809             my $obj = MyClass->new( foo => 42 );
810              
811             =head1 DESCRIPTION
812              
813             This is a small toolkit for generating Moose-like attribute accessors.
814             B<< It does not generate a constructor. >>
815              
816             It stores attribute values inside-out, but it is designed for
817             Sub::Accessor::Small to be subclassed, making it easy to store attributes
818             in other ways.
819              
820             =head1 BUGS
821              
822             Please report any bugs to
823             L<http://rt.cpan.org/Dist/Display.html?Queue=Lexical-Accessor>.
824              
825             =head1 SEE ALSO
826              
827             L<Lexical::Accessor>.
828              
829             =head1 AUTHOR
830              
831             Toby Inkster E<lt>tobyink@cpan.orgE<gt>.
832              
833             =head1 COPYRIGHT AND LICENCE
834              
835             This software is copyright (c) 2013-2014, 2017, 2020 by Toby Inkster.
836              
837             This is free software; you can redistribute it and/or modify it under
838             the same terms as the Perl 5 programming language system itself.
839              
840             =head1 DISCLAIMER OF WARRANTIES
841              
842             THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
843             WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
844             MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
845