File Coverage

blib/lib/Class/Std.pm
Criterion Covered Total %
statement 408 433 94.2
branch 102 128 79.6
condition 34 45 75.5
subroutine 65 68 95.5
pod 2 3 66.6
total 611 677 90.2


line stmt bran cond sub pod time code
1             package Class::Std;
2              
3             our $VERSION = '0.011';
4 16     16   236384 use strict;
  16         37  
  16         580  
5 16     16   90 use warnings;
  16         35  
  16         401  
6 16     16   87 use Carp;
  16         134  
  16         1307  
7 16     16   89 use Scalar::Util;
  16         44  
  16         2301  
8              
9 16     16   26381 use overload;
  16         16520  
  16         92  
10              
11 16     16   2410 BEGIN { *ID = \&Scalar::Util::refaddr; }
12              
13             my (%attribute, %cumulative, %anticumulative, %restricted, %private, %overload);
14              
15             my @exported_subs = qw(
16             new
17             DESTROY
18             AUTOLOAD
19             _DUMP
20             );
21              
22             my @exported_extension_subs = qw(
23             MODIFY_HASH_ATTRIBUTES
24             MODIFY_CODE_ATTRIBUTES
25             );
26              
27             sub import {
28 32     31   3056 my $caller = caller;
29              
30 16     16   106 no strict 'refs';
  16         36  
  16         2201  
31 32         71 *{ $caller . '::ident' } = \&Scalar::Util::refaddr;
  32         657  
32 32         78 for my $sub ( @exported_subs ) {
33 125         143 *{ $caller . '::' . $sub } = \&{$sub};
  125         724  
  125         796  
34             }
35 32         75 for my $sub ( @exported_extension_subs ) {
36 63         126 my $target = $caller . '::' . $sub;
37 63   100 0   107 my $real_sub = *{ $target }{CODE} || sub { return @_[2..$#_] };
  0         0  
38 16     16   670 no warnings 'redefine';
  16         32  
  16         2533  
39 62         5463 *{ $target } = sub {
40 99     99   1901 my ($package, $referent, @unhandled) = @_;
41 99         179 for my $handler ($sub, $real_sub) {
42 198 100       528 next if !@unhandled;
43 100         279 @unhandled = $handler->($package, $referent, @unhandled);
44             }
45 99         343 return @unhandled;
46 63         869 };
47             }
48             }
49              
50             sub _find_sub {
51 63     63   91 my ($package, $sub_ref) = @_;
52 16     16   97 no strict 'refs';
  16         555  
  16         14845  
53 63         67 for my $name (keys %{$package.'::'}) {
  63         282  
54 636         999 my $candidate = *{$package.'::'.$name}{CODE};
  636         1331  
55 636 100 100     2600 return $name if $candidate && $candidate == $sub_ref;
56             }
57 0         0 croak q{Can't make anonymous subroutine cumulative};
58             }
59              
60             sub _raw_str {
61 15     15   28 my ($pat) = @_;
62 15         805 return qr{ ('$pat') | ("$pat")
63             | qq? (?:
64             /($pat)/ | \{($pat)\} | \(($pat)\) | \[($pat)\] | <($pat)>
65             )
66             }xms;
67             }
68              
69             sub _str {
70 135     135   170 my ($pat) = @_;
71 135         6756 return qr{ '($pat)' | "($pat)"
72             | qq? (?:
73             /($pat)/ | \{($pat)\} | \(($pat)\) | \[($pat)\] | <($pat)>
74             )
75             }xms;
76             }
77              
78             sub _extractor_for_pair_named {
79 75     75   139 my ($key, $raw) = @_;
80              
81 75         976 $key = qr{\Q$key\E};
82 75         176 my $str_key = _str($key);
83              
84 75         192 my $LDAB = "(?:\x{AB})";
85 75         86 my $RDAB = "(?:\x{BB})";
86              
87 75 100       331 my $STR = $raw ? _raw_str( qr{.*?} ) : _str( qr{.*?} );
88 75         349 my $NUM = qr{ ( [-+]? (?:\d+\.?\d*|\.\d+) (?:[eE]\d+)? ) }xms;
89              
90 75         14432 my $matcher = qr{ :$key< \s* ([^>]*) \s* >
91             | :$key$LDAB \s* ([^$RDAB]*) \s* $RDAB
92             | :$key\( \s* (?:$STR | $NUM ) \s* \)
93             | (?: $key | $str_key ) \s* => \s* (?: $STR | $NUM )
94             }xms;
95              
96 75 100   305   4879 return sub { return $_[0] =~ $matcher ? $+ : undef };
  305         3440  
97             }
98              
99             BEGIN {
100 16     16   59 *_extract_default = _extractor_for_pair_named('default','raw');
101 16         66 *_extract_init_arg = _extractor_for_pair_named('init_arg');
102 16         672 *_extract_get = _extractor_for_pair_named('get');
103 16         80 *_extract_set = _extractor_for_pair_named('set');
104 16         564 *_extract_name = _extractor_for_pair_named('name');
105             }
106              
107             sub MODIFY_HASH_ATTRIBUTES {
108 66     66   574 my ($package, $referent, @attrs) = @_;
109 66         118 for my $attr (@attrs) {
110 67 100       408 next if $attr !~ m/\A ATTRS? \s* (?: \( (.*) \) )? \z/xms;
111 66         91 my ($default, $init_arg, $getter, $setter, $name);
112 66 100       245 if (my $config = $1) {
113 61         141 $default = _extract_default($config);
114 61         144 $name = _extract_name($config);
115 61   100     152 $init_arg = _extract_init_arg($config) || $name;
116              
117 61 100 100     161 if ($getter = _extract_get($config) || $name) {
118 16     16   127 no strict 'refs';
  18         1691  
  16         1349  
119 23         151 *{$package.'::get_'.$getter} = sub {
120 19     19   142 return $referent->{ID($_[0])};
121             }
122 23         90 }
123 61 100 100     151 if ($setter = _extract_set($config) || $name) {
124 16     16   73 no strict 'refs';
  16         41  
  18         12823  
125 9         49 *{$package.'::set_'.$setter} = sub {
126 4 50   4   21 croak "Missing new value in call to 'set_$setter' method"
127             unless @_ == 2;
128 4         9 my ($self, $new_val) = @_;
129 4         20 my $old_val = $referent->{ID($self)};
130 4         14 $referent->{ID($self)} = $new_val;
131 4         10 return $old_val;
132             }
133 9         83 }
134             }
135 66         119 undef $attr;
136 66   100     102 push @{$attribute{$package}}, {
  66         788  
137             ref => $referent,
138             default => $default,
139             init_arg => $init_arg,
140             name => $name || $init_arg || $getter || $setter || '????',
141             };
142             }
143 66         133 return grep {defined} @attrs;
  67         241  
144             }
145              
146             sub _DUMP {
147 1     1   2 my ($self) = @_;
148 1         3 my $id = ID($self);
149              
150 1         2 my %dump;
151 1         4 for my $package (keys %attribute) {
152 3         5 my $attr_list_ref = $attribute{$package};
153 3         4 for my $attr_ref ( @{$attr_list_ref} ) {
  3         7  
154 6 100       21 next if !exists $attr_ref->{ref}{$id};
155 4         17 $dump{$package}{$attr_ref->{name}} = $attr_ref->{ref}{$id};
156             }
157             }
158              
159 1         1604 require Data::Dumper;
160 1         5656 my $dump = Data::Dumper::Dumper(\%dump);
161 1         105 $dump =~ s/^.{8}//gxms;
162 1         5 return $dump;
163             }
164              
165             my $STD_OVERLOADER
166             = q{ package %%s;
167             use overload (
168             q{%s} => sub { $_[0]->%%s($_[0]->ident()) },
169             fallback => 1
170             );
171             };
172              
173             my %OVERLOADER_FOR = (
174             STRINGIFY => sprintf( $STD_OVERLOADER, q{""} ),
175             NUMERIFY => sprintf( $STD_OVERLOADER, q{0+} ),
176             BOOLIFY => sprintf( $STD_OVERLOADER, q{bool} ),
177             SCALARIFY => sprintf( $STD_OVERLOADER, q{${}} ),
178             ARRAYIFY => sprintf( $STD_OVERLOADER, q{@{}} ),
179             HASHIFY => sprintf( $STD_OVERLOADER, q{%%{}} ), # %% to survive sprintf
180             GLOBIFY => sprintf( $STD_OVERLOADER, q{*{}} ),
181             CODIFY => sprintf( $STD_OVERLOADER, q{&{}} ),
182             );
183              
184             sub MODIFY_CODE_ATTRIBUTES {
185 63     63   110 my ($package, $referent, @attrs) = @_;
186 63         91 for my $attr (@attrs) {
187 63 100       307 if ($attr eq 'CUMULATIVE') {
    100          
    100          
    100          
    50          
188 18         21 push @{$cumulative{$package}}, $referent;
  18         44  
189             }
190             elsif ($attr =~ m/\A CUMULATIVE \s* [(] \s* BASE \s* FIRST \s* [)] \z/xms) {
191 6         8 push @{$anticumulative{$package}}, $referent;
  6         34  
192             }
193             elsif ($attr =~ m/\A RESTRICTED \z/xms) {
194 4         6 push @{$restricted{$package}}, $referent;
  4         25  
195             }
196             elsif ($attr =~ m/\A PRIVATE \z/xms) {
197 2         3 push @{$private{$package}}, $referent;
  2         7  
198             }
199             elsif (exists $OVERLOADER_FOR{$attr}) {
200 33         36 push @{$overload{$package}}, [$referent, $attr];
  33         118  
201             }
202 63         182 undef $attr;
203             }
204 63         120 return grep {defined} @attrs;
  63         220  
205             }
206              
207             my %_hierarchy_of;
208              
209             sub _hierarchy_of {
210 13932     13932   16643 my ($class) = @_;
211              
212 13932 100       40862 return @{$_hierarchy_of{$class}} if exists $_hierarchy_of{$class};
  13865         39380  
213              
214 16     16   95 no strict 'refs';
  16         28  
  16         6689  
215              
216 67         171 my @hierarchy = $class;
217 67         108 my @parents = @{$class.'::ISA'};
  67         457  
218              
219 67         269 while (defined (my $parent = shift @parents)) {
220 99         189 push @hierarchy, $parent;
221 99         124 push @parents, @{$parent.'::ISA'};
  99         536  
222             }
223              
224 67         109 my %seen;
225 67 100       428 return @{$_hierarchy_of{$class}}
  127 100       1635  
226 67         516 = sort { $a->isa($b) ? -1
227             : $b->isa($a) ? +1
228             : 0
229             } grep !$seen{$_}++, @hierarchy;
230             }
231              
232             my %_reverse_hierarchy_of;
233              
234             sub _reverse_hierarchy_of {
235 48     48   87 my ($class) = @_;
236              
237 48 100       139 return @{$_reverse_hierarchy_of{$class}}
  28         109  
238             if exists $_reverse_hierarchy_of{$class};
239              
240 18     16   306 no strict 'refs';
  16         44  
  16         2502  
241              
242 20         50 my @hierarchy = $class;
243 20         35 my @parents = reverse @{$class.'::ISA'};
  20         115  
244              
245 20         90 while (defined (my $parent = shift @parents)) {
246 24         48 push @hierarchy, $parent;
247 24         35 push @parents, reverse @{$parent.'::ISA'};
  24         163  
248             }
249              
250 20         31 my %seen;
251 20 100       121 return @{$_reverse_hierarchy_of{$class}}
  23 100       235  
252 20         186 = reverse sort { $a->isa($b) ? -1
253             : $b->isa($a) ? +1
254             : 0
255             } grep !$seen{$_}++, @hierarchy;
256             }
257              
258             {
259 16     16   101 no warnings qw( void );
  18         1581  
  16         2233  
260 15     14   111447 CHECK { initialize() }
261             }
262              
263             sub initialize {
264             # Short-circuit if nothing to do...
265 37 100   37 1 8764 return if keys(%restricted) + keys(%private)
266             + keys(%cumulative) + keys(%anticumulative)
267             + keys(%overload)
268             == 0;
269              
270 8         17 my (%cumulative_named, %anticumulative_named);
271              
272             # Implement restricted methods (only callable within hierarchy)...
273 8         30 for my $package (keys %restricted) {
274 4         7 for my $sub_ref (@{$restricted{$package}}) {
  4         14  
275 4         51 my $name = _find_sub($package, $sub_ref);
276 16     16   95 no warnings 'redefine';
  16         32  
  18         2026  
277 16     16   80 no strict 'refs';
  16         32  
  16         4657  
278 4         21 my $sub_name = $package.'::'.$name;
279 4 50       6 my $original = *{$sub_name}{CODE}
  4         21  
280             or croak "Restricted method ${package}::$name() declared ",
281             'but not defined';
282 4         40 *{$sub_name} = sub {
283 11     11   5499 my $caller;
284 11         19 my $level = 0;
285 11         38 while ($caller = caller($level++)) {
286 16 100       64 last if $caller !~ /^(?: Class::Std | attributes )$/xms;
287             }
288 11 100 66     207 goto &{$original} if !$caller || $caller->isa($package)
  7   100     39  
289             || $package->isa($caller);
290 4         533 croak "Can't call restricted method $sub_name() from class $caller";
291             }
292 4         31 }
293             }
294              
295             # Implement private methods (only callable from class itself)...
296 8         28 for my $package (keys %private) {
297 2         3 for my $sub_ref (@{$private{$package}}) {
  2         6  
298 2         5 my $name = _find_sub($package, $sub_ref);
299 18     16   2058 no warnings 'redefine';
  16         35  
  16         936  
300 16     16   74 no strict 'refs';
  18         1593  
  16         3081  
301 2         8 my $sub_name = $package.'::'.$name;
302 2 50       3 my $original = *{$sub_name}{CODE}
  2         8  
303             or croak "Private method ${package}::$name() declared ",
304             'but not defined';
305 2         13 *{$sub_name} = sub {
306 4     4   2108 my $caller = caller;
307 4 100       14 goto &{$original} if $caller eq $package;
  1         5  
308 3         344 croak "Can't call private method $sub_name() from class $caller";
309             }
310 2         9 }
311             }
312              
313 8         29 for my $package (keys %cumulative) {
314 12         14 for my $sub_ref (@{$cumulative{$package}}) {
  12         28  
315 18         34 my $name = _find_sub($package, $sub_ref);
316 18         50 $cumulative_named{$name}{$package} = $sub_ref;
317 16     16   81 no warnings 'redefine';
  16         35  
  18         2037  
318 16     16   88 no strict 'refs';
  16         23  
  16         7066  
319 18         113 *{$package.'::'.$name} = sub {
320 10     10   88 my @args = @_;
321 10   33     40 my $class = ref($_[0]) || $_[0];
322 10         22 my $list_context = wantarray;
323 10         15 my (@results, @classes);
324 10         28 for my $parent (_hierarchy_of($class)) {
325 37 100       166 my $sub_ref = $cumulative_named{$name}{$parent} or next;
326 33 50       71 ${$parent.'::AUTOLOAD'} = our $AUTOLOAD if $name eq 'AUTOLOAD';
  0         0  
327 33 100       63 if (!defined $list_context) {
328 9         58 $sub_ref->(@args);
329 9         22137 next;
330             }
331 24         39 push @classes, $parent;
332 24 50       36 if ($list_context) {
333 0         0 push @results, $sub_ref->(@args);
334             }
335             else {
336 24         75 push @results, scalar $sub_ref->(@args);
337             }
338             }
339 10 100       62 return if !defined $list_context;
340 4 50       15 return @results if $list_context;
341 4         29 return Class::Std::SCR->new({
342             values => \@results,
343             classes => \@classes,
344             });
345 18         82 };
346             }
347             }
348              
349 8         28 for my $package (keys %anticumulative) {
350 6         7 for my $sub_ref (@{$anticumulative{$package}}) {
  6         14  
351 6         9 my $name = _find_sub($package, $sub_ref);
352 6 50       18 if ($cumulative_named{$name}) {
353 0         0 for my $other_package (keys %{$cumulative_named{$name}}) {
  0         0  
354 0 0 0     0 next unless $other_package->isa($package)
355             || $package->isa($other_package);
356 0         0 print STDERR
357             "Conflicting definitions for cumulative method",
358             " '$name'\n",
359             "(specified as :CUMULATIVE in class '$other_package'\n",
360             " but declared :CUMULATIVE(BASE FIRST) in class ",
361             " '$package')\n";
362 0         0 exit(1);
363             }
364             }
365 6         11 $anticumulative_named{$name}{$package} = $sub_ref;
366 16     16   671 no warnings 'redefine';
  16         35  
  16         558  
367 16     16   625 no strict 'refs';
  16         71  
  16         7505  
368 6         36 *{$package.'::'.$name} = sub {
369 2   33 2   19 my $class = ref($_[0]) || $_[0];
370 2         6 my $list_context = wantarray;
371 2         4 my (@results, @classes);
372 2         16 for my $parent (_reverse_hierarchy_of($class)) {
373 14 100       65 my $sub_ref = $anticumulative_named{$name}{$parent} or next;
374 12 50       25 if (!defined $list_context) {
375 0         0 &{$sub_ref};
  0         0  
376 0         0 next;
377             }
378 12         17 push @classes, $parent;
379 12 50       21 if ($list_context) {
380 0         0 push @results, &{$sub_ref};
  0         0  
381             }
382             else {
383 12         10 push @results, scalar &{$sub_ref};
  12         28  
384             }
385             }
386 2 50       14 return if !defined $list_context;
387 2 50       6 return @results if $list_context;
388 2         17 return Class::Std::SCR->new({
389             values => \@results,
390             classes => \@classes,
391             });
392 6         508 };
393             }
394             }
395              
396 8         32 for my $package (keys %overload) {
397 5         1064 foreach my $operation (@{ $overload{$package} }) {
  5         21  
398 33         72 my ($referent, $attr) = @$operation;
399 33         495 local $^W;
400 33         63 my $method = _find_sub($package, $referent);
401 33     2   4017 eval sprintf $OVERLOADER_FOR{$attr}, $package, $method;
  2         12  
  2         14  
  2         19  
  3         776  
402 33 50       1623 die "Internal error: $@" if $@;
403             }
404             }
405              
406             # Remove initialization data to prevent re-initializations...
407 8         25 %restricted = ();
408 8         19 %private = ();
409 8         19 %cumulative = ();
410 8         20 %anticumulative = ();
411 8         7232 %overload = ();
412             }
413              
414             sub new {
415 23     26 1 5215 my ($class, $arg_ref) = @_;
416              
417 23         198 Class::Std::initialize(); # Ensure run-time (and mod_perl) setup is done
418              
419 16     16   81 no strict 'refs';
  16         32  
  16         2584  
420 23 50       33 croak "Can't find class $class" if ! keys %{$class.'::'};
  23         111  
421              
422 23 50 66     165 croak "Argument to $class->new() must be hash reference"
423             if @_ > 1 && ref $arg_ref ne 'HASH';
424              
425 23         80 my $new_obj = bless \my($anon_scalar), $class;
426 23         92 my $new_obj_id = ID($new_obj);
427 23         38 my (@missing_inits, @suss_keys);
428              
429 23   100     115 $arg_ref ||= {};
430 23         33 my %arg_set;
431 23         91 BUILD: for my $base_class (_reverse_hierarchy_of($class)) {
432 44         104 my $arg_set = $arg_set{$base_class}
433 44 100       70 = { %{$arg_ref}, %{$arg_ref->{$base_class}||{}} };
  44         367  
434              
435             # Apply BUILD() methods...
436             {
437 16     16   93 no warnings 'once';
  16         34  
  16         4087  
  44         84  
438 44 100       55 if (my $build_ref = *{$base_class.'::BUILD'}{CODE}) {
  44         339  
439 16         114 $build_ref->($new_obj, $new_obj_id, $arg_set);
440             }
441             }
442              
443             # Apply init_arg and default for attributes still undefined...
444             INITIALIZATION:
445 44         16504 for my $attr_ref ( @{$attribute{$base_class}} ) {
  44         171  
446 79 100       223 next INITIALIZATION if defined $attr_ref->{ref}{$new_obj_id};
447              
448             # Get arg from initializer list...
449 65 100 100     316 if (defined $attr_ref->{init_arg}
    100          
450             && exists $arg_set->{$attr_ref->{init_arg}}) {
451 49         112 $attr_ref->{ref}{$new_obj_id} = $arg_set->{$attr_ref->{init_arg}};
452              
453 49         111 next INITIALIZATION;
454             }
455             elsif (defined $attr_ref->{default}) {
456             # Or use default value specified...
457 15         708 $attr_ref->{ref}{$new_obj_id} = eval $attr_ref->{default};
458              
459 15 100       60 if ($@) {
460 8         23 $attr_ref->{ref}{$new_obj_id} = $attr_ref->{default};
461             }
462              
463 15         45 next INITIALIZATION;
464             }
465              
466 1 50       6 if (defined $attr_ref->{init_arg}) {
467             # Record missing init_arg...
468 0         0 push @missing_inits,
469             "Missing initializer label for $base_class: "
470             . "'$attr_ref->{init_arg}'.\n";
471 0         0 push @suss_keys, keys %{$arg_set};
  0         0  
472             }
473             }
474             }
475              
476 23 50       88 croak @missing_inits, _mislabelled(@suss_keys),
477             'Fatal error in constructor call'
478             if @missing_inits;
479              
480             # START methods run after all BUILD methods complete...
481 23         95 for my $base_class (_reverse_hierarchy_of($class)) {
482 44         81 my $arg_set = $arg_set{$base_class};
483              
484             # Apply START() methods...
485             {
486 16     16   657 no warnings 'once';
  16         50  
  16         5416  
  44         88  
487 44 100       52 if (my $init_ref = *{$base_class.'::START'}{CODE}) {
  44         298  
488 2         7 $init_ref->($new_obj, $new_obj_id, $arg_set);
489             }
490             }
491             }
492              
493 23         134 return $new_obj;
494             }
495              
496             sub uniq (@) {
497 0     0 0 0 my %seen;
498 0         0 return grep { $seen{$_}++ } @_;
  0         0  
499             }
500              
501              
502             sub _mislabelled {
503 0     0   0 my (@names) = map { qq{'$_'} } uniq @_;
  0         0  
504              
505 0 0       0 return q{} if @names == 0;
506              
507 0 0       0 my $arglist
    0          
508             = @names == 1 ? $names[0]
509             : @names == 2 ? join q{ or }, @names
510             : join(q{, }, @names[0..$#names-1]) . ", or $names[-1]"
511             ;
512 0         0 return "(Did you mislabel one of the args you passed: $arglist?)\n";
513             }
514              
515             sub DESTROY {
516 27     27   10597 my ($self) = @_;
517 27         81 my $id = ID($self);
518 27         58 push @_, $id;
519              
520 27         93 for my $base_class (_hierarchy_of(ref $_[0])) {
521 16     16   330 no strict 'refs';
  16         612  
  16         3120  
522 53 100       69 if (my $demolish_ref = *{$base_class.'::DEMOLISH'}{CODE}) {
  53         283  
523 10         12 &{$demolish_ref};
  10         89  
524             }
525              
526 53         5059 for my $attr_ref ( @{$attribute{$base_class}} ) {
  53         646  
527 91         865 delete $attr_ref->{ref}{$id};
528             }
529             }
530             }
531              
532             sub AUTOLOAD {
533 20     20   4534 my ($invocant) = @_;
534 20   66     85 my $invocant_class = ref $invocant || $invocant;
535 20         163 my ($package_name, $method_name) = our $AUTOLOAD =~ m/ (.*) :: (.*) /xms;
536              
537 20         65 my $ident = ID($invocant);
538 20 100       52 if (!defined $ident) { $ident = $invocant }
  12         16  
539              
540 20         54 for my $parent_class ( _hierarchy_of($invocant_class) ) {
541 16     16   74 no strict 'refs';
  16         29  
  16         3253  
542 37 100       60 if (my $automethod_ref = *{$parent_class.'::AUTOMETHOD'}{CODE}) {
  37         163  
543 20         48 local $CALLER::_ = $_;
544 20         28 local $_ = $method_name;
545 20 100       66 if (my $method_impl
546             = $automethod_ref->($invocant, $ident, @_[1..$#_])) {
547 15         168 goto &$method_impl;
548             }
549             }
550             }
551              
552 4 50       21 my $type = ref $invocant ? 'object' : 'class';
553 4         478 croak qq{Can't locate $type method "$method_name" via package "$package_name"};
554             }
555              
556             {
557             my $real_can = \&UNIVERSAL::can;
558 16     16   1358 no warnings 'redefine', 'once';
  16         32  
  16         1631  
559             *UNIVERSAL::can = sub {
560 90254     90254   214454 my ($invocant, $method_name) = @_;
561              
562 90254 100       167019 if ( defined $invocant ) {
563 90253 100       309369 if (my $sub_ref = $real_can->(@_)) {
564 76378         1401074 return $sub_ref;
565             }
566              
567 13875   66     54461 for my $parent_class ( _hierarchy_of(ref $invocant || $invocant) ) {
568 16     16   683 no strict 'refs';
  16         38  
  16         2473  
569 41589 100       46031 if (my $automethod_ref = *{$parent_class.'::AUTOMETHOD'}{CODE}) {
  41589         161203  
570 9         12 local $CALLER::_ = $_;
571 9         12 local $_ = $method_name;
572 9 100       39 if (my $method_impl = $automethod_ref->(@_)) {
573 6     6   3046 return sub { my $inv = shift; $inv->$method_name(@_) }
  6         33  
574 6         65 }
575             }
576             }
577             }
578              
579 13869         507675 return;
580             };
581             }
582              
583             package Class::Std::SCR;
584 16     16   115 use base qw( Class::Std );
  16         559  
  16         2153  
585              
586 16     15   464 BEGIN { *ID = \&Scalar::Util::refaddr; }
587              
588 16     15   18816 my %values_of : ATTR( :init_arg );
  16         22789  
  16         4916  
589             my %classes_of : ATTR( :init_arg );
590              
591             sub new {
592 6     6   9 my ($class, $opt_ref) = @_;
593 6         9 my $new_obj = bless \do{my $scalar}, $class;
  6         17  
594 6         16 my $new_obj_id = ID($new_obj);
595 6         16 $values_of{$new_obj_id} = $opt_ref->{values};
596 6         12 $classes_of{$new_obj_id} = $opt_ref->{classes};
597 6         23 return $new_obj;
598             }
599              
600             use overload (
601 5     4   12 q{""} => sub { return join q{}, grep { defined $_ } @{$values_of{ID($_[0])}}; },
  25         54  
  5         22  
602 5     4   192 q{0+} => sub { return scalar @{$values_of{ID($_[0])}}; },
  5         34  
603 7     6   1005 q{@{}} => sub { return $values_of{ID($_[0])}; },
604             q{%{}} => sub {
605 29     28   18989 my ($self) = @_;
606 29         533 my %hash;
607 29         37 @hash{@{$classes_of{ID($self)}}} = @{$values_of{ID($self)}};
  29         168  
  29         94  
608 29         662 return \%hash;
609             },
610 16         293 fallback => 1,
611 16     15   99 );
  16         38  
612              
613             1; # Magic true value required at end of module
614             __END__