File Coverage

blib/lib/Trace/Mask/Carp.pm
Criterion Covered Total %
statement 138 139 99.2
branch 67 78 85.9
condition 39 57 68.4
subroutine 23 23 100.0
pod 6 6 100.0
total 273 303 90.1


line stmt bran cond sub pod time code
1             package Trace::Mask::Carp;
2 2     2   242088 use strict;
  2         5  
  2         47  
3 2     2   9 use warnings;
  2         4  
  2         60  
4              
5 2     2   20 use Carp 1.03 ();
  2         47  
  2         127  
6             $Carp::Internal{'Trace::Mask'} = 1;
7             $Carp::Internal{'Trace::Mask::Carp'} = 1;
8             $Carp::Internal{'Trace::Mask::Util'} = 1;
9             $Carp::Internal{'Trace::Mask::Reference'} = 1;
10 2     2   547 use Trace::Mask::Util qw/get_mask mask_line/;
  2         4  
  2         174  
11              
12             BEGIN {
13 2 50   2   579 *carp_longmess = Carp->can('longmess') or die "Could not find Carp::longmess";
14             }
15              
16 32     32 1 10739 sub longmess { mask_trace(scalar(carp_longmess(@_)), 'Trace::Mask::Carp::longmess') }
17 26     26 1 7370 sub confess { die mask_trace(scalar(carp_longmess(@_)), 'Trace::Mask::Carp::confess') }
18 26     26 1 7109 sub cluck { warn mask_trace(scalar(carp_longmess(@_)), 'Trace::Mask::Carp::cluck') }
19              
20             sub _my_croak {
21 2     2   4 my $msg = shift;
22 2         14 my @caller = caller(1);
23 2         19 die "$msg at $caller[1] line $caller[2].\n";
24             }
25              
26             sub import {
27 8     8   30692 my $class = shift;
28              
29 8         19 my $caller = caller;
30              
31 8         12 my %flags;
32              
33 8         19 for my $arg (@_) {
34 14 100       53 if ($arg =~ m/^-(.+)$/) {
    50          
35 6         23 $flags{$1} = 1;
36             }
37             elsif ($arg =~ m/^_/) {
38 0         0 _my_croak "'$arg' is not exported by $class"
39             }
40             else {
41 8   66     60 my $sub = $class->can($arg) || _my_croak "'$arg' is not exported by $class";
42 2     2   12 no strict 'refs';
  2         9  
  2         899  
43 7         9 *{"$caller\::$arg"} = $sub;
  7         66  
44             }
45             }
46              
47 7 100       31 $class->_global_override if delete $flags{'global'};
48 7 100       28 $class->_wrap_carp if delete $flags{'wrap'};
49              
50 7         21 my @bad = sort keys %flags;
51 7 100       849 return unless @bad;
52 1         3 _my_croak "bad flag(s): " . join (", ", map { "-$_" } @bad);
  2         8  
53             }
54              
55             sub _global_override {
56 26   50 26   357 my $die = $SIG{__DIE__} || sub { CORE::die(@_) };
  3     3   32  
57 3   50 26   25 my $warn = $SIG{__WARN__} || sub { CORE::warn(@_) };
  26         395  
58              
59             $SIG{__DIE__} = sub {
60 26     26   59220 my $error = shift;
61 26         182 my @caller = caller(1);
62 26 50       214 $error = mask_trace($error, $caller[3]) if $caller[3] =~ m/^Carp::(confess|longmess|cluck)$/;
63 26         84 return $die->($error)
64 3         16 };
65              
66             $SIG{__WARN__} = sub {
67 26     26   59550 my $msg = shift;
68 26         173 my @caller = caller(1);
69 26 50       205 $msg = mask_trace($msg, $caller[3]) if $caller[3] =~ m/^Carp::(confess|longmess|cluck)$/;
70 26         74 $warn->($msg);
71 3         14 };
72             }
73              
74             sub _wrap_carp {
75 2     2   12 no warnings 'redefine';
  2         3  
  2         306  
76 2     2   11 *Carp::confess = \&confess;
77 2         7 *Carp::longmess = \&longmess;
78 2         7 *Carp::cluck = \&cluck;
79             }
80              
81             sub mask(&) {
82 1     1 1 9443 my ($code) = @_;
83 1         3 my $sigwarn = $SIG{__WARN__};
84 1         3 my $sigdie = $SIG{__DIE__};
85              
86 1         5 local $SIG{__WARN__};
87 1         3 local $SIG{__DIE__};
88              
89 1 50       5 $SIG{__WARN__} = $sigwarn if $sigwarn;
90 1 50       4 $SIG{__DIE__} = $sigdie if $sigdie;
91              
92 1         5 _global_override();
93              
94 2     2   16 BEGIN { mask_line({hide => 2}, 1) }
95 1         4 $code->();
96             }
97              
98             sub parse_carp_line {
99 7446     7446 1 38597 my ($line) = @_;
100 7446         17165 my %out = (orig => $line);
101              
102 7446 100       41112 if ($line =~ m/^(\s*)([^\(]+)\((.*)\) called at (.+) line (\d+)\.?$/) { # Long
    100          
    100          
103 6120         30957 @out{qw/indent sub args file line/} = ($1, $2, $3, $4, $5);
104             }
105             elsif ($line =~ m/^(\s*)eval \Q{...}\E called at (.+) line (\d+)\.?$/) { # eval
106 1054         4298 @out{qw/sub indent file line/} = ('eval', $1, $2, $3);
107             }
108             elsif ($line =~ m/^(\s*)(.*) at (.+) line (\d+)\.?$/) { # Short
109 268         1394 @out{qw/indent msg file line/} = ($1, $2, $3, $4);
110             }
111              
112 7446 100       26240 return \%out if keys(%out) > 1;
113 4         12 return undef;
114             }
115              
116             sub _write_carp_line{
117 632     632   935 my ($fields) = @_;
118 632         808 my ($indent, $file, $line, $sub, $msg, $args) = @{$fields}{qw/indent file line sub msg args/};
  632         1844  
119 632   100     1542 $indent ||= "";
120              
121 632 100 100     2607 if ($msg || !$sub) {
122 137   100     503 $msg ||= "";
123 137         484 return "$indent$msg at $file line $line.\n";
124             }
125              
126 495 100       1059 if ($sub eq 'eval') {
127 1         6 return "$indent$sub {...} called at $file line $line\n";
128             }
129             else {
130 494   100     915 $args ||= "";
131 494         1672 return "$indent$sub\($args) called at $file line $line\n";
132             }
133             }
134              
135             sub mask_trace {
136 137     137 1 160080 my ($msg, $sub) = @_;
137 137 50       417 return $msg if $ENV{NO_TRACE_MASK};
138 137         9065 my @lines = split /[\n\r]+/, $msg;
139 137 50       399 return $msg unless @lines > 1;
140              
141 137         209 my $out = "";
142 137         167 my ($shift, $last);
143 137         205 my $skip = 0;
144              
145 137         214 my $num = 0;
146 137         140 my $error;
147 137         166 my $stopped = 0;
148 137         266 for my $line (@lines) {
149 6822         12474 my $fields = parse_carp_line($line);
150              
151 6822 100       13745 unless($fields) {
152 3         7 $out .= "$line\n";
153 3         6 next;
154             }
155              
156 6819 100 33     12693 $fields->{sub} ||= $sub unless $num;
157 6819 100       13972 $error = $fields if exists $fields->{msg};
158 6819         7638 $num++;
159              
160 6819   50     7688 my $mask = get_mask(@{$fields}{qw/file line/}, $fields->{sub} || '*');
  6819         26652  
161 6819 100 66     46982 next if $stopped && !($mask->{restart} || $mask->{lock});
      100        
162 983 100       2063 $stopped = 0 if $mask->{restart};
163 983 100 66     4059 $last = $fields unless $mask->{hide} || $mask->{shift} || $mask->{lock};
      66        
164              
165 983 100       2863 unless ($mask->{lock}) {
166 961 100       1798 $fields->{file} = $mask->{1} if $mask->{1};
167 961 100       1754 $fields->{line} = $mask->{2} if $mask->{2};
168 961 100       1955 $fields->{sub} = $mask->{3} if $mask->{3};
169             }
170              
171 983 100 100     4258 if ($mask->{shift}) {
    100 100        
    100          
172 50   33     196 $shift ||= $fields;
173 50 50 33     192 $skip = ($skip || $mask->{lock}) ? $skip + $mask->{shift} - 1 : $mask->{shift};
174             }
175             elsif ($mask->{hide}) {
176 147 100 66     573 $skip = ($skip || $mask->{lock}) ? $skip + $mask->{hide} - 1 : $mask->{hide};
177             }
178             elsif($skip && !(--$skip) && $shift) {
179 40 50       110 unless ($mask->{lock}) {
180 40         74 $fields->{msg} = $shift->{msg};
181 40         67 $fields->{indent} = $shift->{indent};
182 40         70 $fields->{sub} = $shift->{sub};
183 40         71 $fields->{args} = $shift->{args};
184             }
185 40         52 $shift = undef;
186             }
187              
188 983 100 66     3068 unless ($skip || ($mask->{no_start} && !$out)) {
      66        
189 622 100       1150 if ($error) {
190 137         235 $fields->{msg} = $error->{msg};
191 137         214 $fields->{indent} = $error->{indent};
192 137         286 delete $fields->{sub};
193 137         192 $error = undef;
194             }
195 622         1146 $out .= _write_carp_line($fields)
196             }
197              
198 983 100       3307 $stopped = 1 if $mask->{stop};
199             }
200              
201 137 100       312 if ($shift) {
202 10         23 $last->{msg} = $shift->{msg};
203 10         21 $last->{indent} = $shift->{indent};
204 10         23 $last->{sub} = $shift->{sub};
205 10         18 $last->{args} = $shift->{args};
206 10 50 33     143 $out .= _write_carp_line($last) unless $out && $out =~ m/at \Q$last->{file}\E line $last->{line}/;
207             }
208              
209 137         1782 return $out;
210             }
211              
212             1;
213              
214             __END__