File Coverage

blib/lib/Data/Thunk/Code.pm
Criterion Covered Total %
statement 72 83 86.7
branch 11 14 78.5
condition 3 5 60.0
subroutine 23 25 92.0
pod 0 5 0.0
total 109 132 82.5


line stmt bran cond sub pod time code
1             #!/usr/bin/perl
2              
3              
4             package Data::Thunk::Code;
5             BEGIN {
6 1     1   183 $Data::Thunk::Code::AUTHORITY = 'cpan:NUFFIN';
7             }
8             BEGIN {
9 1     1   21 $Data::Thunk::Code::VERSION = '0.07';
10             }
11              
12 1     1   6 use strict;
  1         2  
  1         28  
13 1     1   5 use warnings;
  1         2  
  1         28  
14              
15 1     1   955 use Try::Tiny;
  1         1826  
  1         61  
16 1     1   992 use Data::Swap;
  1         30881  
  1         111  
17 1     1   13 use Scalar::Util qw(reftype blessed);
  1         3  
  1         106  
18 1     1   894 use Check::ISA;
  1         16755  
  1         7  
19 1     1   1618 use Devel::Refcount qw(refcount);
  1         1140  
  1         200  
20 1     1   8 use Carp;
  1         33  
  1         68  
21              
22 1     1   949 use namespace::clean;
  1         18578  
  1         9  
23              
24 1     1   1685 use UNIVERSAL::ref;
  1         120707  
  1         10  
25              
26             BEGIN {
27             our $vivify_code = sub {
28 11     11   1229 bless $_[0], "Data::Thunk::NoOverload";
29              
30 11         46 my $scalar = reftype($_[0]) eq "REF";
31 11 100       31 my $code = $scalar ? ${ $_[0] } : $_[0]->{code};
  10         27  
32 11         40 my $tmp = $_[0]->$code();
33              
34 11 100 100     117 if ( CORE::ref($tmp) and refcount($tmp) == 1 ) {
35 7         252 my $ref = \$_[0]; # try doesn't get $_[0]
36              
37             try {
38 7     7   248 swap $$ref, $tmp;
39             } catch {
40             # try to figure out where the thunk was defined
41             my $lazy_ctx = try {
42             require B;
43             my $cv = B::svref_2object($_[0]->{code});
44             my $file = $cv->FILE;
45             my $line = $cv->START->line;
46             "in thunk defined at $file line $line";
47 0   0 0   0 } || "at <>";
48              
49 0         0 my $file = __FILE__;
50 0         0 s/ at \Q$file\E line \d+.\n$/ $lazy_ctx, vivified/; # becomes "vivified at foo line blah"..
51              
52 0         0 croak($_);
53 7         69 };
54              
55 7         132 return $_[0];
56             } else {
57 4 50       57 unless ( $scalar ) {
58 0         0 Data::Swap::swap $_[0], do { my $o; \$o };
  0         0  
  0         0  
59             }
60              
61             # set up the Scalar Value overload thingy
62 4         8 ${ $_[0] } = $tmp;
  4         11  
63 4         13 bless $_[0], "Data::Thunk::ScalarValue";
64              
65 4         30 return $tmp;
66             }
67 1     1   755 };
68             }
69              
70             our $vivify_code;
71              
72 1     1   13 use overload ( fallback => 1, map { $_ => $vivify_code } qw( bool "" 0+ ${} @{} %{} &{} *{} ) );
  1         2  
  1         2  
  8         21  
73              
74             our $call_method = sub {
75             my $method = shift;
76              
77             if ( inv($_[0]) ) {
78             if ( my $code = $_[0]->can($method) ) {
79             goto &$code;
80             } else {
81             return $_[0]->$method(@_[1 .. $#_]);
82             }
83             } elsif ( defined $_[0] ) {
84             croak qq{Can't call method "$method" without a package or object reference};
85             } else {
86             croak qq{Can't call method "$method" on an undefined value};
87             }
88             };
89              
90             our $vivify_and_call = sub {
91             $_[1]->$vivify_code();
92             goto $call_method;
93             };
94              
95             sub ref {
96 2     2 0 16 CORE::ref($_[0]->$vivify_code);
97             }
98              
99             foreach my $sym (keys %UNIVERSAL::) {
100 1     1   504 no strict 'refs';
  1         3  
  1         257  
101              
102             next if $sym eq 'ref::';
103             next if defined &$sym;
104              
105             local $@;
106              
107 15 50   15 0 535 eval "sub $sym {
  0 50   1 0 0  
  0 100   11 0 0  
  15 100   14 0 390  
  1         8  
  1         4  
  1         3  
  0         0  
  11         15089  
  1         4  
  1         6  
  10         173  
  14         49  
  1         5  
  1         5  
  13         122  
108             if ( Scalar::Util::blessed(\$_[0]) ) {
109             unshift \@_, '$sym';
110             goto \$vivify_and_call;
111             } else {
112             shift->SUPER::$sym(\@_);
113             }
114             }; 1" || warn $@;
115             }
116              
117             sub AUTOLOAD {
118 2     2   29 my ( $method ) = ( our $AUTOLOAD =~ /([^:]+)$/ );
119 2         9 unshift @_, $method;
120 2         10 goto $vivify_and_call;
121             }
122              
123 0     0     sub DESTROY {
124             # don't create the value just to destroy it
125             }
126              
127             1;
128              
129             __END__