File Coverage

blib/lib/Contextual/Diag/Value.pm
Criterion Covered Total %
statement 55 55 100.0
branch 8 8 100.0
condition n/a
subroutine 12 12 100.0
pod 3 3 100.0
total 78 78 100.0


line stmt bran cond sub pod time code
1             package Contextual::Diag::Value;
2 2     2   28 use 5.010;
  2         6  
3 2     2   9 use strict;
  2         5  
  2         32  
4 2     2   8 use warnings;
  2         3  
  2         58  
5              
6             our $VERSION = "0.03";
7              
8 2     2   9 use Scalar::Util ();
  2         11  
  2         451  
9              
10             my %DATA;
11             my %OVERLOAD;
12              
13             sub new {
14 28     28 1 202 my ($class, $value, %overload) = @_;
15              
16             # Use inside-out to prevent infinite recursion
17 28         63 my $self = bless \my $scalar => $class;
18 28         68 my $id = Scalar::Util::refaddr $self;
19 28         89 $DATA{$id} = {
20             value => $value,
21             overload => \%overload,
22             };
23 28         131 return $self;
24             }
25              
26             BEGIN {
27 2     2   19 my %CONTEXT_MAP = (
28             q{""} => 'STR',
29             '0+' => 'NUM',
30             'bool' => 'BOOL',
31             '${}' => 'SCALARREF',
32             '@{}' => 'ARRAYREF',
33             '&{}' => 'CODEREF',
34             '%{}' => 'HASHREF',
35             '*{}' => 'GLOBREF',
36             );
37              
38             %OVERLOAD = map {
39 2         9 my $context = $CONTEXT_MAP{$_};
  16         24  
40              
41             $_ => sub {
42 18     18   58 my $self = shift;
43              
44 18         37 my $id = Scalar::Util::refaddr $self;
45 18         30 my $data = $DATA{$id};
46 18         29 my $code = $data->{overload}->{$context};
47 18         24 my $value = $data->{value};
48 18         39 return $code->($value);
49             }
50 16         128 } keys %CONTEXT_MAP,
51             }
52              
53 2     2   14 use overload %OVERLOAD, fallback => 1;
  2         2  
  2         23  
54              
55             sub can {
56 5     5 1 3690 my ($invocant) = @_;
57 5 100       16 if (ref $invocant) {
58 3         7 our $AUTOLOAD = 'can';
59 3         8 goto &AUTOLOAD;
60             }
61 2         31 return $invocant->SUPER::can(@_[1..$#_]);
62             }
63              
64             sub isa {
65 6     6 1 14 my ($invocant) = @_;
66 6 100       17 if (ref $invocant) {
67 3         5 our $AUTOLOAD = 'isa';
68 3         9 goto &AUTOLOAD;
69             }
70 3         22 return $invocant->SUPER::isa(@_[1..$#_]);
71             }
72              
73             sub AUTOLOAD {
74 8     8   29 my $self = shift;
75 8         10 our $AUTOLOAD;
76              
77 8 100       18 unless (ref $self) {
78 1         13 die "cannot AUTOLOAD in class call"
79             }
80              
81 7         9 my $obj = do {
82 7         13 my $id = Scalar::Util::refaddr $self;
83 7         13 my $data = $DATA{$id};
84 7         10 my $code = $data->{overload}->{OBJREF};
85 7         9 my $value = $data->{value};
86 7         15 $code->($value);
87             };
88              
89 7 100       34 my ($method) = $AUTOLOAD =~ m{ .* :: (.*) }xms ? $1 : $AUTOLOAD;
90 7         64 return $obj->$method(@_);
91             }
92              
93             sub DESTROY {
94 28     28   2749 my $self = shift;
95 28         56 my $id = Scalar::Util::refaddr $self;
96 28         329 delete $DATA{$id};
97 28         226 return;
98             }
99              
100             1;
101             __END__