File Coverage

blib/lib/Devel/CodeObserver.pm
Criterion Covered Total %
statement 74 78 94.8
branch 11 18 61.1
condition 2 3 66.6
subroutine 18 19 94.7
pod 2 4 50.0
total 107 122 87.7


line stmt bran cond sub pod time code
1             package Devel::CodeObserver;
2 1     1   75369 use strict;
  1         12  
  1         31  
3 1     1   5 use warnings;
  1         2  
  1         24  
4 1     1   5 use utf8;
  1         2  
  1         6  
5 1     1   45 use 5.010_001;
  1         3  
6              
7             our $VERSION = "0.16";
8              
9             our @WARNINGS;
10              
11 1     1   8 use B qw(class ppname);
  1         1  
  1         89  
12 1     1   434 use B::Tap qw(tap);
  1         2  
  1         60  
13 1     1   484 use B::Tools qw(op_walk);
  1         579  
  1         60  
14 1     1   663 use Data::Dumper ();
  1         7258  
  1         432  
15              
16             sub new {
17 3     3 1 6508 my $class = shift;
18 3 50       26 my %args = @_==1 ? %{$_[0]} : @_;
  0         0  
19 3         25 bless {%args}, $class;
20             }
21              
22             sub null {
23 3     3 0 6 my $op = shift;
24 3         40 return class($op) eq "NULL";
25             }
26              
27             sub call {
28 3     3 1 8 my ($class,$code) = @_;
29              
30 3         15 my $cv = B::svref_2object($code);
31              
32 3         4 my @tap_results;
33              
34 3         13 my $root = $cv->ROOT;
35             # local $B::overlay = {};
36 3 50       17 if (not null $root) {
37             op_walk {
38 23 100   23   232 if (need_hook($_)) {
39 2         5 my @buf = ($_);
40 2         11 tap($_, $cv->ROOT, \@buf);
41 2         16 push @tap_results, \@buf;
42             }
43 3         25 } $cv->ROOT;
44             }
45 3         27 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             $retval,
55             Devel::CallTrace::Result->new(
56             code => $code,
57 3         40 tap_results => [grep { @$_ > 1 } @tap_results],
  2         7  
58             )
59             );
60             }
61              
62             sub need_hook {
63 23     23 0 33 my $op = shift;
64 23 100       104 return 1 if $op->name eq 'entersub';
65 21 50       63 return 1 if $op->name eq 'padsv';
66 21 50       70 return 1 if $op->name eq 'aelem';
67 21 50       69 return 1 if $op->name eq 'helem';
68 21 50 66     78 return 1 if $op->name eq 'null' && ppname($op->targ) eq 'pp_rv2sv';
69 21         117 return 0;
70             }
71              
72             package Devel::CallTrace::Result;
73              
74 1     1   599 use Try::Tiny;
  1         2657  
  1         67  
75 1     1   8 use constant { DEBUG => 0 };
  1         2  
  1         428  
76              
77             sub new {
78 3     3   5 my $class = shift;
79 3 50       15 my %args = @_==1 ? %{$_[0]} : @_;
  0         0  
80 3         21 bless {%args}, $class;
81             }
82              
83             sub dump_pairs {
84 1     1   362 my ($self) = @_;
85 1         5 my $tap_results = $self->{tap_results};
86 1         3 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         8 require B::Deparse;
94              
95 1         3 my @pairs;
96 1         2 local $Data::Dumper::Terse = 1;
97 1         4 local $Data::Dumper::Indent = 0;
98 1         3 for my $result (@$tap_results) {
99 2         179 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   137 local $SIG{__WARN__} = sub { };
105              
106 2         85 my $deparse = B::Deparse->new();
107 2         12 $deparse->{curcv} = B::svref_2object($code);
108 2         596 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         78 return \@pairs;
119             }
120              
121             1;
122             __END__