File Coverage

blib/lib/Devel/Spy/Util.pm
Criterion Covered Total %
statement 33 53 62.2
branch 5 14 35.7
condition 0 3 0.0
subroutine 9 11 81.8
pod 4 4 100.0
total 51 85 60.0


line stmt bran cond sub pod time code
1             package Devel::Spy::Util;
2 1     1   12 use strict;
  1         2  
  1         38  
3 1     1   6 use warnings;
  1         1  
  1         26  
4              
5 1     1   1885 use overload ();
  1         1223  
  1         24  
6 1     1   7 use Scalar::Util ();
  1         2  
  1         14  
7 1     1   5 use Carp ();
  1         2  
  1         14  
8 1     1   893 use Symbol ();
  1         1042  
  1         670  
9              
10             sub Y { ## no critic (Prototype)
11             # The Y combinator.
12 3     3 1 9 my ( undef, $curried_rec ) = @_;
13             my $p = sub {
14 11     11   18 my $f = shift @_;
15 11         92 return $curried_rec->( sub { $f->($f)->(@_) } );
  8         17  
16 3         15 };
17 3         43 return $p->($p);
18             }
19              
20             sub compile_this {
21              
22             # Accepts some source code and expects to return a true
23             # value. Devel::Spy::_obj uses this to compile a bunch of subs but
24             # without having to repeat the "eval or croak" stuff all over the
25             # place.
26             #
27             # Example:
28             # my $sub = Devel::Spy::Util::compile_this( <<"SRC" );
29             # sub ... {
30             # ...
31             # };
32             # 1;
33             # SRC
34 0     0 1 0 my ( undef, $src ) = @_;
35 0         0 my ( $package, $filename, $line ) = caller;
36              
37             # Add some sugar to make the code appear in the proper location.
38 0         0 $src = <<"CODE";
39 0         0 #line @{[$line]} "@{[$filename]}"
  0         0  
40             package $package;
41             $src
42             CODE
43              
44             ## no critic (Eval)
45 0 0       0 my $result = eval $src
46             or Carp::confess "$@ while compiling:\n$src";
47 0         0 return $result;
48             }
49              
50             my %class_rx_cache;
51              
52             sub comes_from {
53 0     0 1 0 my $class = shift @_;
54 0   0     0 my $class_rx = $class_rx_cache{$class} ||= qr/\A\Q$class\E(?:\z|::)/;
55              
56             # Returns a string showing the location of the non-Devel::Spy code
57             # that's higher in the call stack.
58 0         0 my $cx = 1;
59 0         0 while ( my ( $pkg, undef, $line ) = caller $cx++ ) {
60              
61             # Find !Devel::Spy
62 0 0       0 unless ( $pkg =~ $class_rx ) {
63 0         0 return "($pkg:$line)";
64             }
65             }
66              
67             # Huh? I suppose this only occurs if Devel::Spy is the *only*
68             # thing in the call stack and I'm not even sure how that happens.
69 0         0 return;
70             }
71              
72             sub wrap_thing {
73 18     18 1 34 my ( $class, $thing, $code ) = @_;
74              
75             # Use a tied proxy to $thing instead of $thing directly. But only
76             # if $thing is a reference.
77 18         43 my $reftype = Scalar::Util::reftype $thing;
78 18 100       77 return $thing unless defined $reftype;
79              
80             # This may be a really bad idea.
81 3         14 $class =~ s/::Util\z//;
82              
83             # Return a tied wrapper over $thing.
84 3 100       14 if ( 'HASH' eq $reftype ) {
    50          
    0          
    0          
85 2         13 tie my %pretend_self, "$class\::TieHash", $thing, $code;
86 2         8 return \%pretend_self;
87             }
88             elsif ( 'ARRAY' eq $reftype ) {
89 1         8 tie my @pretend_self, "$class\::TieArray", $thing, $code;
90 1         5 return \@pretend_self;
91             }
92             elsif ( $reftype =~ /^(?:SCALAR|REF|CODE|LVALUE|REGEXP|VSTRING|BIND)\z/ ) {
93 0           tie my $pretend_self, "$class\::TieScalar", $thing, $code;
94 0           return \$pretend_self;
95             }
96             elsif ( $reftype =~ /^(?:GLOB|FORMAT|IO)\z/ ) {
97 0           my $pretend_self = Symbol::gensym();
98 0           tie *$pretend_self, "$class\::TieHandle", $thing, $code;
99 0           return $pretend_self;
100             }
101              
102             # Missing implementations?
103 0           Carp::croak "Unsupported reftype: $reftype on "
104             . overload::StrVal($thing);
105             }
106              
107             1;
108              
109             __END__