File Coverage

blib/lib/Devel/CodeObserver.pm
Criterion Covered Total %
statement 76 80 95.0
branch 11 18 61.1
condition 2 3 66.6
subroutine 18 19 94.7
pod 2 4 50.0
total 109 124 87.9


line stmt bran cond sub pod time code
1             package Devel::CodeObserver;
2 1     1   22928 use strict;
  1         2  
  1         43  
3 1     1   5 use warnings;
  1         3  
  1         24  
4 1     1   5 use utf8;
  1         1  
  1         6  
5 1     1   39 use 5.010_001;
  1         3  
  1         69  
6              
7             our $VERSION = "0.14";
8              
9             our @WARNINGS;
10              
11 1     1   4 use B qw(class ppname);
  1         2  
  1         170  
12 1     1   476 use B::Tap qw(tap);
  1         3  
  1         73  
13 1     1   947 use B::Tools qw(op_walk);
  1         488  
  1         62  
14 1     1   2910 use Data::Dumper ();
  1         11303  
  1         514  
15              
16             sub new {
17 3     3 1 5497 my $class = shift;
18 3 50       19 my %args = @_==1 ? %{$_[0]} : @_;
  0         0  
19 3         30 bless {%args}, $class;
20             }
21              
22             sub null {
23 3     3 0 5 my $op = shift;
24 3         44 return class($op) eq "NULL";
25             }
26              
27             sub call {
28 3     3 1 7 my ($class,$code) = @_;
29              
30 3         24 my $cv = B::svref_2object($code);
31              
32 3         6 my @tap_results;
33              
34 3         17 my $root = $cv->ROOT;
35             # local $B::overlay = {};
36 3 50       8 if (not null $root) {
37             op_walk {
38 24 100   24   144 if (need_hook($_)) {
39 2         4 my @buf = ($_);
40 2         13 tap($_, $cv->ROOT, \@buf);
41 2         20 push @tap_results, \@buf;
42             }
43 3         37 } $cv->ROOT;
44             }
45 3         38 if (0) {
46             require B::Concise;
47             my $walker = B::Concise::compile('', '', $code);
48             $walker->();
49             }
50              
51 3         9 my $retval = $code->();
52              
53             return (
54 2         9 $retval,
55             Devel::CallTrace::Result->new(
56             code => $code,
57 3         55 tap_results => [grep { @$_ > 1 } @tap_results],
58             )
59             );
60             }
61              
62             sub need_hook {
63 24     24 0 28 my $op = shift;
64 24 100       136 return 1 if $op->name eq 'entersub';
65 22 50       96 return 1 if $op->name eq 'padsv';
66 22 50       91 return 1 if $op->name eq 'aelem';
67 22 50       99 return 1 if $op->name eq 'helem';
68 22 50 66     131 return 1 if $op->name eq 'null' && ppname($op->targ) eq 'pp_rv2sv';
69 22         208 return 0;
70             }
71              
72             package Devel::CallTrace::Result;
73              
74 1     1   2082 use Try::Tiny;
  1         1664  
  1         62  
75 1     1   5 use constant { DEBUG => 0 };
  1         2  
  1         504  
76              
77             sub new {
78 3     3   6 my $class = shift;
79 3 50       17 my %args = @_==1 ? %{$_[0]} : @_;
  0         0  
80 3         24 bless {%args}, $class;
81             }
82              
83             sub dump_pairs {
84 1     1   621 my ($self) = @_;
85 1         7 my $tap_results = $self->{tap_results};
86 1         2 my $code = $self->{code};
87              
88             # We should load B::Deparse lazily. Because loading B::Deparse is really slow.
89             # It's really big module.
90             #
91             # And so, this module is mainly used for testing. And this part is only required if
92             # the test case was failed. I make faster the passed test case.
93 1         9 require B::Deparse;
94              
95 1         3 my @pairs;
96 1         2 local $Data::Dumper::Terse = 1;
97 1         3 local $Data::Dumper::Indent = 0;
98 1         3 for my $result (@$tap_results) {
99 2         171 my $op = shift @$result;
100 2         5 for my $value (@$result) {
101             # take first argument if the value is scalar.
102             try {
103             # Suppress warnings for: sub { expect(\@p)->to_be(['a']) }
104 2     2   82 local $SIG{__WARN__} = sub { };
  2         227  
105              
106 2         79 my $deparse = B::Deparse->new();
107 2         25 $deparse->{curcv} = B::svref_2object($code);
108 2         488 push @pairs, [
109             $deparse->deparse($op),
110             Data::Dumper::Dumper($value->[1])
111             ];
112             } catch {
113 0     0   0 DEBUG && warn "[Devel::CodeObserver] [BUG]: $_";
114 0         0 push @WARNINGS, "[Devel::CodeObserver] [BUG]: $_";
115 2         21 };
116             }
117             }
118 1         86 return \@pairs;
119             }
120              
121             1;
122             __END__