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.013';
4 15     15   153008 use strict;
  15         32  
  15         550  
5 17     15   795 use warnings;
  15         26  
  15         378  
6 15     15   65 use Carp;
  17         191  
  15         1083  
7 15     15   77 use Scalar::Util;
  15         28  
  17         1636  
8              
9 15     15   15400 use overload;
  15         12292  
  15         87  
10              
11 17     15   2537 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 31     30   2882 my $caller = caller;
29              
30 15     15   87 no strict 'refs';
  15         17  
  15         1903  
31 31         76 *{ $caller . '::ident' } = \&Scalar::Util::refaddr;
  31         457  
32 31         70 for my $sub ( @exported_subs ) {
33 121         98 *{ $caller . '::' . $sub } = \&{$sub};
  121         405  
  121         481  
34             }
35 31         64 for my $sub ( @exported_extension_subs ) {
36 61         103 my $target = $caller . '::' . $sub;
37 61   100 0   61 my $real_sub = *{ $target }{CODE} || sub { return @_[2..$#_] };
  0         0  
38 17     15   968 no warnings 'redefine';
  15         24  
  15         2059  
39 60         2729 *{ $target } = sub {
40 99     99   1678 my ($package, $referent, @unhandled) = @_;
41 99         155 for my $handler ($sub, $real_sub) {
42 198 100       432 next if !@unhandled;
43 100         249 @unhandled = $handler->($package, $referent, @unhandled);
44             }
45 99         303 return @unhandled;
46 61         493 };
47             }
48             }
49              
50             sub _find_sub {
51 63     63   73 my ($package, $sub_ref) = @_;
52 15     15   71 no strict 'refs';
  17         894  
  15         6093  
53 63         59 for my $name (keys %{$package.'::'}) {
  63         277  
54 545         411 my $candidate = *{$package.'::'.$name}{CODE};
  545         1028  
55 545 100 100     1913 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 14     14   20 my ($pat) = @_;
62 14         546 return qr{ ('$pat') | ("$pat")
63             | qq? (?:
64             /($pat)/ | \{($pat)\} | \(($pat)\) | \[($pat)\] | <($pat)>
65             )
66             }xms;
67             }
68              
69             sub _str {
70 126     126   126 my ($pat) = @_;
71 126         4855 return qr{ '($pat)' | "($pat)"
72             | qq? (?:
73             /($pat)/ | \{($pat)\} | \(($pat)\) | \[($pat)\] | <($pat)>
74             )
75             }xms;
76             }
77              
78             sub _extractor_for_pair_named {
79 70     70   118 my ($key, $raw) = @_;
80              
81 70         795 $key = qr{\Q$key\E};
82 70         143 my $str_key = _str($key);
83              
84 70         126 my $LDAB = "(?:\x{AB})";
85 70         70 my $RDAB = "(?:\x{BB})";
86              
87 70 100       245 my $STR = $raw ? _raw_str( qr{.*?} ) : _str( qr{.*?} );
88 70         205 my $NUM = qr{ ( [-+]? (?:\d+\.?\d*|\.\d+) (?:[eE]\d+)? ) }xms;
89              
90 70         8922 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 70 100   295   2623 return sub { return $_[0] =~ $matcher ? $+ : undef };
  295         2839  
97             }
98              
99             BEGIN {
100 15     15   41 *_extract_default = _extractor_for_pair_named('default','raw');
101 15         57 *_extract_init_arg = _extractor_for_pair_named('init_arg');
102 17         917 *_extract_get = _extractor_for_pair_named('get');
103 15         81 *_extract_set = _extractor_for_pair_named('set');
104 15         40 *_extract_name = _extractor_for_pair_named('name');
105             }
106              
107             sub MODIFY_HASH_ATTRIBUTES {
108 64     64   506 my ($package, $referent, @attrs) = @_;
109 64         107 for my $attr (@attrs) {
110 65 100       439 next if $attr !~ m/\A ATTRS? \s* (?: \( (.*) \) )? \z/xms;
111 64         64 my ($default, $init_arg, $getter, $setter, $name);
112 64 100       225 if (my $config = $1) {
113 59         135 $default = _extract_default($config);
114 59         125 $name = _extract_name($config);
115 59   100     111 $init_arg = _extract_init_arg($config) || $name;
116              
117 59 100 100     126 if ($getter = _extract_get($config) || $name) {
118 15     15   120 no strict 'refs';
  15         360  
  15         1250  
119 23         154 *{$package.'::get_'.$getter} = sub {
120 19     19   135 return $referent->{ID($_[0])};
121             }
122 23         153 }
123 59 100 100     116 if ($setter = _extract_set($config) || $name) {
124 15     15   70 no strict 'refs';
  15         119  
  15         8862  
125 9         36 *{$package.'::set_'.$setter} = sub {
126 4 50   4   19 croak "Missing new value in call to 'set_$setter' method"
127             unless @_ == 2;
128 4         7 my ($self, $new_val) = @_;
129 4         12 my $old_val = $referent->{ID($self)};
130 4         12 $referent->{ID($self)} = $new_val;
131 4         5 return $old_val;
132             }
133 9         29 }
134             }
135 64         85 undef $attr;
136 64   100     63 push @{$attribute{$package}}, {
  64         761  
137             ref => $referent,
138             default => $default,
139             init_arg => $init_arg,
140             name => $name || $init_arg || $getter || $setter || '????',
141             };
142             }
143 64         116 return grep {defined} @attrs;
  65         229  
144             }
145              
146             sub _DUMP {
147 1     1   2 my ($self) = @_;
148 1         8 my $id = ID($self);
149              
150 1         2 my %dump;
151 1         3 for my $package (keys %attribute) {
152 3         4 my $attr_list_ref = $attribute{$package};
153 3         4 for my $attr_ref ( @{$attr_list_ref} ) {
  3         5  
154 6 100       18 next if !exists $attr_ref->{ref}{$id};
155 4         13 $dump{$package}{$attr_ref->{name}} = $attr_ref->{ref}{$id};
156             }
157             }
158              
159 1         817 require Data::Dumper;
160 1         6621 my $dump = Data::Dumper::Dumper(\%dump);
161 1         157 $dump =~ s/^.{8}//gxms;
162 1         10 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   95 my ($package, $referent, @attrs) = @_;
186 63         85 for my $attr (@attrs) {
187 63 100       293 if ($attr eq 'CUMULATIVE') {
    100          
    100          
    100          
    50          
188 18         18 push @{$cumulative{$package}}, $referent;
  18         45  
189             }
190             elsif ($attr =~ m/\A CUMULATIVE \s* [(] \s* BASE \s* FIRST \s* [)] \z/xms) {
191 6         10 push @{$anticumulative{$package}}, $referent;
  6         21  
192             }
193             elsif ($attr =~ m/\A RESTRICTED \z/xms) {
194 4         5 push @{$restricted{$package}}, $referent;
  4         11  
195             }
196             elsif ($attr =~ m/\A PRIVATE \z/xms) {
197 2         3 push @{$private{$package}}, $referent;
  2         4  
198             }
199             elsif (exists $OVERLOADER_FOR{$attr}) {
200 33         30 push @{$overload{$package}}, [$referent, $attr];
  33         109  
201             }
202 63         146 undef $attr;
203             }
204 63         91 return grep {defined} @attrs;
  63         187  
205             }
206              
207             my %_hierarchy_of;
208              
209             sub _hierarchy_of {
210 12943     12943   11576 my ($class) = @_;
211              
212 12943 100       20818 return @{$_hierarchy_of{$class}} if exists $_hierarchy_of{$class};
  12879         26373  
213              
214 15     15   86 no strict 'refs';
  15         21  
  15         2375  
215              
216 64         148 my @hierarchy = $class;
217 64         77 my @parents = @{$class.'::ISA'};
  64         366  
218              
219 64         316 while (defined (my $parent = shift @parents)) {
220 94         142 push @hierarchy, $parent;
221 94         121 push @parents, @{$parent.'::ISA'};
  94         465  
222             }
223              
224 64         98 my %seen;
225 64 100       401 return @{$_hierarchy_of{$class}}
  120 100       1100  
226 64         530 = 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   70 my ($class) = @_;
236              
237 48 100       110 return @{$_reverse_hierarchy_of{$class}}
  28         84  
238             if exists $_reverse_hierarchy_of{$class};
239              
240 15     15   145 no strict 'refs';
  15         25  
  15         1944  
241              
242 20         40 my @hierarchy = $class;
243 20         39 my @parents = reverse @{$class.'::ISA'};
  20         107  
244              
245 20         81 while (defined (my $parent = shift @parents)) {
246 24         38 push @hierarchy, $parent;
247 24         28 push @parents, reverse @{$parent.'::ISA'};
  24         105  
248             }
249              
250 20         60 my %seen;
251 20 100       105 return @{$_reverse_hierarchy_of{$class}}
  23 100       179  
252 20         149 = reverse sort { $a->isa($b) ? -1
253             : $b->isa($a) ? +1
254             : 0
255             } grep !$seen{$_}++, @hierarchy;
256             }
257              
258             {
259 15     15   73 no warnings qw( void );
  15         358  
  15         1834  
260 14     13   93909 CHECK { initialize() }
261             }
262              
263             sub initialize {
264             # Short-circuit if nothing to do...
265 36 100   36 1 5782 return if keys(%restricted) + keys(%private)
266             + keys(%cumulative) + keys(%anticumulative)
267             + keys(%overload)
268             == 0;
269              
270 8         15 my (%cumulative_named, %anticumulative_named);
271              
272             # Implement restricted methods (only callable within hierarchy)...
273 8         32 for my $package (keys %restricted) {
274 4         5 for my $sub_ref (@{$restricted{$package}}) {
  4         37  
275 4         12 my $name = _find_sub($package, $sub_ref);
276 15     15   76 no warnings 'redefine';
  15         26  
  15         762  
277 15     15   62 no strict 'refs';
  15         26  
  15         3676  
278 4         12 my $sub_name = $package.'::'.$name;
279 4 50       3 my $original = *{$sub_name}{CODE}
  4         19  
280             or croak "Restricted method ${package}::$name() declared ",
281             'but not defined';
282 4         22 *{$sub_name} = sub {
283 11     11   6449 my $caller;
284 11         16 my $level = 0;
285 11         40 while ($caller = caller($level++)) {
286 16 100       50 last if $caller !~ /^(?: Class::Std | attributes )$/xms;
287             }
288 11 100 66     128 goto &{$original} if !$caller || $caller->isa($package)
  7   100     32  
289             || $package->isa($caller);
290 4         427 croak "Can't call restricted method $sub_name() from class $caller";
291             }
292 4         18 }
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         3  
298 2         3 my $name = _find_sub($package, $sub_ref);
299 15     15   348 no warnings 'redefine';
  15         29  
  15         530  
300 15     15   65 no strict 'refs';
  15         315  
  15         2560  
301 2         6 my $sub_name = $package.'::'.$name;
302 2 50       2 my $original = *{$sub_name}{CODE}
  2         6  
303             or croak "Private method ${package}::$name() declared ",
304             'but not defined';
305 2         6 *{$sub_name} = sub {
306 4     4   3020 my $caller = caller;
307 4 100       13 goto &{$original} if $caller eq $package;
  1         3  
308 3         313 croak "Can't call private method $sub_name() from class $caller";
309             }
310 2         5 }
311             }
312              
313 8         26 for my $package (keys %cumulative) {
314 12         12 for my $sub_ref (@{$cumulative{$package}}) {
  12         27  
315 18         30 my $name = _find_sub($package, $sub_ref);
316 18         45 $cumulative_named{$name}{$package} = $sub_ref;
317 15     15   76 no warnings 'redefine';
  15         30  
  15         838  
318 15     15   61 no strict 'refs';
  15         20  
  15         5080  
319 18         90 *{$package.'::'.$name} = sub {
320 10     10   77 my @args = @_;
321 10   33     31 my $class = ref($_[0]) || $_[0];
322 10         15 my $list_context = wantarray;
323 10         16 my (@results, @classes);
324 10         23 for my $parent (_hierarchy_of($class)) {
325 37 100       126 my $sub_ref = $cumulative_named{$name}{$parent} or next;
326 33 50       52 ${$parent.'::AUTOLOAD'} = our $AUTOLOAD if $name eq 'AUTOLOAD';
  0         0  
327 33 100       49 if (!defined $list_context) {
328 9         61 $sub_ref->(@args);
329 9         10495 next;
330             }
331 24         23 push @classes, $parent;
332 24 50       25 if ($list_context) {
333 0         0 push @results, $sub_ref->(@args);
334             }
335             else {
336 24         56 push @results, scalar $sub_ref->(@args);
337             }
338             }
339 10 100       49 return if !defined $list_context;
340 4 50       7 return @results if $list_context;
341 4         21 return Class::Std::SCR->new({
342             values => \@results,
343             classes => \@classes,
344             });
345 18         73 };
346             }
347             }
348              
349 8         21 for my $package (keys %anticumulative) {
350 6         7 for my $sub_ref (@{$anticumulative{$package}}) {
  6         11  
351 6         18 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         22 $anticumulative_named{$name}{$package} = $sub_ref;
366 15     15   371 no warnings 'redefine';
  15         29  
  15         534  
367 15     15   66 no strict 'refs';
  15         25  
  15         5830  
368 6         35 *{$package.'::'.$name} = sub {
369 2   33 2   15 my $class = ref($_[0]) || $_[0];
370 2         3 my $list_context = wantarray;
371 2         9 my (@results, @classes);
372 2         5 for my $parent (_reverse_hierarchy_of($class)) {
373 14 100       46 my $sub_ref = $anticumulative_named{$name}{$parent} or next;
374 12 50       15 if (!defined $list_context) {
375 0         0 &{$sub_ref};
  0         0  
376 0         0 next;
377             }
378 12         14 push @classes, $parent;
379 12 50       13 if ($list_context) {
380 0         0 push @results, &{$sub_ref};
  0         0  
381             }
382             else {
383 12         9 push @results, scalar &{$sub_ref};
  12         23  
384             }
385             }
386 2 50       11 return if !defined $list_context;
387 2 50       4 return @results if $list_context;
388 2         9 return Class::Std::SCR->new({
389             values => \@results,
390             classes => \@classes,
391             });
392 6         31 };
393             }
394             }
395              
396 8         23 for my $package (keys %overload) {
397 5         9 foreach my $operation (@{ $overload{$package} }) {
  5         15  
398 33         85 my ($referent, $attr) = @$operation;
399 33         92 local $^W;
400 33         67 my $method = _find_sub($package, $referent);
401 33     2   4061 eval sprintf $OVERLOADER_FOR{$attr}, $package, $method;
  2         21  
  2         4  
  2         16  
  5         1104  
402 33 50       1746 die "Internal error: $@" if $@;
403             }
404             }
405              
406             # Remove initialization data to prevent re-initializations...
407 8         28 %restricted = ();
408 8         16 %private = ();
409 8         17 %cumulative = ();
410 8         15 %anticumulative = ();
411 8         5203 %overload = ();
412             }
413              
414             sub new {
415 23     26 1 3344 my ($class, $arg_ref) = @_;
416              
417 23         82 Class::Std::initialize(); # Ensure run-time (and mod_perl) setup is done
418              
419 15     15   66 no strict 'refs';
  15         29  
  15         2270  
420 23 50       23 croak "Can't find class $class" if ! keys %{$class.'::'};
  23         107  
421              
422 23 50 66     146 croak "Argument to $class->new() must be hash reference"
423             if @_ > 1 && ref $arg_ref ne 'HASH';
424              
425 23         59 my $new_obj = bless \my($anon_scalar), $class;
426 23         79 my $new_obj_id = ID($new_obj);
427 23         28 my (@missing_inits, @suss_keys);
428              
429 23   100     91 $arg_ref ||= {};
430 23         29 my %arg_set;
431 23         82 BUILD: for my $base_class (_reverse_hierarchy_of($class)) {
432 44         162 my $arg_set = $arg_set{$base_class}
433 44 100       76 = { %{$arg_ref}, %{$arg_ref->{$base_class}||{}} };
  44         241  
434              
435             # Apply BUILD() methods...
436             {
437 15     15   85 no warnings 'once';
  15         22  
  15         3261  
  44         67  
438 44 100       45 if (my $build_ref = *{$base_class.'::BUILD'}{CODE}) {
  44         193  
439 16         111 $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         9691 for my $attr_ref ( @{$attribute{$base_class}} ) {
  44         132  
446 79 100       199 next INITIALIZATION if defined $attr_ref->{ref}{$new_obj_id};
447              
448             # Get arg from initializer list...
449 65 100 100     250 if (defined $attr_ref->{init_arg}
    100          
450             && exists $arg_set->{$attr_ref->{init_arg}}) {
451 49         98 $attr_ref->{ref}{$new_obj_id} = $arg_set->{$attr_ref->{init_arg}};
452              
453 49         83 next INITIALIZATION;
454             }
455             elsif (defined $attr_ref->{default}) {
456             # Or use default value specified...
457 15         590 $attr_ref->{ref}{$new_obj_id} = eval $attr_ref->{default};
458              
459 15 100       46 if ($@) {
460 8         15 $attr_ref->{ref}{$new_obj_id} = $attr_ref->{default};
461             }
462              
463 15         36 next INITIALIZATION;
464             }
465              
466 1 50       5 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       67 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         59 for my $base_class (_reverse_hierarchy_of($class)) {
482 44         63 my $arg_set = $arg_set{$base_class};
483              
484             # Apply START() methods...
485             {
486 15     15   382 no warnings 'once';
  15         30  
  15         4578  
  44         45  
487 44 100       42 if (my $init_ref = *{$base_class.'::START'}{CODE}) {
  44         235  
488 2         4 $init_ref->($new_obj, $new_obj_id, $arg_set);
489             }
490             }
491             }
492              
493 23         119 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   7761 my ($self) = @_;
517 27         71 my $id = ID($self);
518 27         49 push @_, $id;
519              
520 27         76 for my $base_class (_hierarchy_of(ref $_[0])) {
521 15     15   263 no strict 'refs';
  15         318  
  15         2834  
522 53 100       44 if (my $demolish_ref = *{$base_class.'::DEMOLISH'}{CODE}) {
  53         231  
523 10         11 &{$demolish_ref};
  10         107  
524             }
525              
526 53         3359 for my $attr_ref ( @{$attribute{$base_class}} ) {
  53         278  
527 91         413 delete $attr_ref->{ref}{$id};
528             }
529             }
530             }
531              
532             sub AUTOLOAD {
533 20     20   2861 my ($invocant) = @_;
534 20   66     123 my $invocant_class = ref $invocant || $invocant;
535 20         114 my ($package_name, $method_name) = our $AUTOLOAD =~ m/ (.*) :: (.*) /xms;
536              
537 20         60 my $ident = ID($invocant);
538 20 100       78 if (!defined $ident) { $ident = $invocant }
  12         16  
539              
540 20         44 for my $parent_class ( _hierarchy_of($invocant_class) ) {
541 15     15   70 no strict 'refs';
  15         24  
  15         2511  
542 37 100       52 if (my $automethod_ref = *{$parent_class.'::AUTOMETHOD'}{CODE}) {
  37         160  
543 20         26 local $CALLER::_ = $_;
544 20         27 local $_ = $method_name;
545 20 100       63 if (my $method_impl
546             = $automethod_ref->($invocant, $ident, @_[1..$#_])) {
547 15         172 goto &$method_impl;
548             }
549             }
550             }
551              
552 4 50       15 my $type = ref $invocant ? 'object' : 'class';
553 4         400 croak qq{Can't locate $type method "$method_name" via package "$package_name"};
554             }
555              
556             {
557             my $real_can = \&UNIVERSAL::can;
558 15     15   72 no warnings 'redefine', 'once';
  15         23  
  15         1171  
559             *UNIVERSAL::can = sub {
560 83851     83851   144431 my ($invocant, $method_name) = @_;
561              
562 83851 100       125110 if ( defined $invocant ) {
563 83850 100       187393 if (my $sub_ref = $real_can->(@_)) {
564 70964         921979 return $sub_ref;
565             }
566              
567 12886   66     29130 for my $parent_class ( _hierarchy_of(ref $invocant || $invocant) ) {
568 15     15   376 no strict 'refs';
  15         22  
  15         1901  
569 38623 100       27403 if (my $automethod_ref = *{$parent_class.'::AUTOMETHOD'}{CODE}) {
  38623         101503  
570 9         14 local $CALLER::_ = $_;
571 9         11 local $_ = $method_name;
572 9 100       32 if (my $method_impl = $automethod_ref->(@_)) {
573 6     6   2541 return sub { my $inv = shift; $inv->$method_name(@_) }
  6         39  
574 6         81 }
575             }
576             }
577             }
578              
579 12880         323928 return;
580             };
581             }
582              
583             package Class::Std::SCR;
584 15     15   91 use base qw( Class::Std );
  15         306  
  15         2250  
585              
586             our $VERSION = '0.013';
587              
588 15     14   379 BEGIN { *ID = \&Scalar::Util::refaddr; }
589              
590 15     14   10248 my %values_of : ATTR( :init_arg );
  15         18935  
  15         4035  
591             my %classes_of : ATTR( :init_arg );
592              
593             sub new {
594 6     6   6 my ($class, $opt_ref) = @_;
595 6         8 my $new_obj = bless \do{my $scalar}, $class;
  6         10  
596 6         11 my $new_obj_id = ID($new_obj);
597 6         11 $values_of{$new_obj_id} = $opt_ref->{values};
598 6         8 $classes_of{$new_obj_id} = $opt_ref->{classes};
599 6         12 return $new_obj;
600             }
601              
602             use overload (
603 5     4   11 q{""} => sub { return join q{}, grep { defined $_ } @{$values_of{ID($_[0])}}; },
  25         38  
  5         23  
604 5     4   141 q{0+} => sub { return scalar @{$values_of{ID($_[0])}}; },
  5         29  
605 7     6   744 q{@{}} => sub { return $values_of{ID($_[0])}; },
606             q{%{}} => sub {
607 29     28   10430 my ($self) = @_;
608 29         306 my %hash;
609 29         29 @hash{@{$classes_of{ID($self)}}} = @{$values_of{ID($self)}};
  29         124  
  29         90  
610 29         412 return \%hash;
611             },
612 15         245 fallback => 1,
613 15     14   99 );
  15         72  
614              
615             1; # Magic true value required at end of module
616             __END__