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   262636 use strict;
  2         4  
  2         65  
3 2     2   12 use warnings;
  2         5  
  2         75  
4              
5 2     2   21 use Carp 1.03 ();
  2         59  
  2         194  
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   558 use Trace::Mask::Util qw/get_mask mask_line/;
  2         9  
  2         217  
11              
12             BEGIN {
13 2 50   2   815 *carp_longmess = Carp->can('longmess') or die "Could not find Carp::longmess";
14             }
15              
16 32     32 1 10564 sub longmess { mask_trace(scalar(carp_longmess(@_)), 'Trace::Mask::Carp::longmess') }
17 26     26 1 7946 sub confess { die mask_trace(scalar(carp_longmess(@_)), 'Trace::Mask::Carp::confess') }
18 26     26 1 7562 sub cluck { warn mask_trace(scalar(carp_longmess(@_)), 'Trace::Mask::Carp::cluck') }
19              
20             sub _my_croak {
21 2     2   5 my $msg = shift;
22 2         14 my @caller = caller(1);
23 2         20 die "$msg at $caller[1] line $caller[2].\n";
24             }
25              
26             sub import {
27 8     8   21553 my $class = shift;
28              
29 8         18 my $caller = caller;
30              
31 8         14 my %flags;
32              
33 8         18 for my $arg (@_) {
34 14 100       54 if ($arg =~ m/^-(.+)$/) {
    50          
35 6         28 $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     59 my $sub = $class->can($arg) || _my_croak "'$arg' is not exported by $class";
42 2     2   12 no strict 'refs';
  2         8  
  2         840  
43 7         9 *{"$caller\::$arg"} = $sub;
  7         34  
44             }
45             }
46              
47 7 100       33 $class->_global_override if delete $flags{'global'};
48 7 100       30 $class->_wrap_carp if delete $flags{'wrap'};
49              
50 7         22 my @bad = sort keys %flags;
51 7 100       833 return unless @bad;
52 1         4 _my_croak "bad flag(s): " . join (", ", map { "-$_" } @bad);
  2         8  
53             }
54              
55             sub _global_override {
56 26   50 26   415 my $die = $SIG{__DIE__} || sub { CORE::die(@_) };
  3     3   29  
57 3   50 26   24 my $warn = $SIG{__WARN__} || sub { CORE::warn(@_) };
  26         458  
58              
59             $SIG{__DIE__} = sub {
60 26     26   65148 my $error = shift;
61 26         185 my @caller = caller(1);
62 26 50       224 $error = mask_trace($error, $caller[3]) if $caller[3] =~ m/^Carp::(confess|longmess|cluck)$/;
63 26         74 return $die->($error)
64 3         14 };
65              
66             $SIG{__WARN__} = sub {
67 26     26   65592 my $msg = shift;
68 26         195 my @caller = caller(1);
69 26 50       249 $msg = mask_trace($msg, $caller[3]) if $caller[3] =~ m/^Carp::(confess|longmess|cluck)$/;
70 26         84 $warn->($msg);
71 3         15 };
72             }
73              
74             sub _wrap_carp {
75 2     2   11 no warnings 'redefine';
  2         4  
  2         343  
76 2     2   9 *Carp::confess = \&confess;
77 2         7 *Carp::longmess = \&longmess;
78 2         6 *Carp::cluck = \&cluck;
79             }
80              
81             sub mask(&) {
82 1     1 1 3939 my ($code) = @_;
83 1         3 my $sigwarn = $SIG{__WARN__};
84 1         5 my $sigdie = $SIG{__DIE__};
85              
86 1         4 local $SIG{__WARN__};
87 1         4 local $SIG{__DIE__};
88              
89 1 50       4 $SIG{__WARN__} = $sigwarn if $sigwarn;
90 1 50       5 $SIG{__DIE__} = $sigdie if $sigdie;
91              
92 1         4 _global_override();
93              
94 2     2   10 BEGIN { mask_line({hide => 2}, 1) }
95 1         4 $code->();
96             }
97              
98             sub parse_carp_line {
99 7949     7949 1 42266 my ($line) = @_;
100 7949         18409 my %out = (orig => $line);
101              
102 7949 100       44765 if ($line =~ m/^(\s*)([^\(]+)\((.*)\) called at (.+) line (\d+)\.?$/) { # Long
    100          
    100          
103 6623         33416 @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         4383 @out{qw/sub indent file line/} = ('eval', $1, $2, $3);
107             }
108             elsif ($line =~ m/^(\s*)(.*) at (.+) line (\d+)\.?$/) { # Short
109 268         1532 @out{qw/indent msg file line/} = ($1, $2, $3, $4);
110             }
111              
112 7949 100       27812 return \%out if keys(%out) > 1;
113 4         11 return undef;
114             }
115              
116             sub _write_carp_line{
117 743     743   1083 my ($fields) = @_;
118 743         1158 my ($indent, $file, $line, $sub, $msg, $args) = @{$fields}{qw/indent file line sub msg args/};
  743         2160  
119 743   100     1814 $indent ||= "";
120              
121 743 100 100     3104 if ($msg || !$sub) {
122 137   100     413 $msg ||= "";
123 137         561 return "$indent$msg at $file line $line.\n";
124             }
125              
126 606 100       1253 if ($sub eq 'eval') {
127 1         6 return "$indent$sub {...} called at $file line $line\n";
128             }
129             else {
130 605   100     1384 $args ||= "";
131 605         2180 return "$indent$sub\($args) called at $file line $line\n";
132             }
133             }
134              
135             sub mask_trace {
136 137     137 1 175861 my ($msg, $sub) = @_;
137 137 50       450 return $msg if $ENV{NO_TRACE_MASK};
138 137         9780 my @lines = split /[\n\r]+/, $msg;
139 137 50       354 return $msg unless @lines > 1;
140              
141 137         232 my $out = "";
142 137         191 my ($shift, $last);
143 137         295 my $skip = 0;
144              
145 137         180 my $num = 0;
146 137         161 my $error;
147 137         198 my $stopped = 0;
148 137         267 for my $line (@lines) {
149 7215         13776 my $fields = parse_carp_line($line);
150              
151 7215 100       15068 unless($fields) {
152 3         7 $out .= "$line\n";
153 3         5 next;
154             }
155              
156 7212 100 33     13588 $fields->{sub} ||= $sub unless $num;
157 7212 100       15578 $error = $fields if exists $fields->{msg};
158 7212         9214 $num++;
159              
160 7212   50     10163 my $mask = get_mask(@{$fields}{qw/file line/}, $fields->{sub} || '*');
  7212         29847  
161 7212 100 66     48553 next if $stopped && !($mask->{restart} || $mask->{lock});
      100        
162 1114 100       2520 $stopped = 0 if $mask->{restart};
163 1114 100 66     4930 $last = $fields unless $mask->{hide} || $mask->{shift} || $mask->{lock};
      66        
164              
165 1114 100       3644 unless ($mask->{lock}) {
166 1092 100       2279 $fields->{file} = $mask->{1} if $mask->{1};
167 1092 100       2081 $fields->{line} = $mask->{2} if $mask->{2};
168 1092 100       2456 $fields->{sub} = $mask->{3} if $mask->{3};
169             }
170              
171 1114 100 100     5368 if ($mask->{shift}) {
    100 100        
    100          
172 50   33     189 $shift ||= $fields;
173 50 50 33     209 $skip = ($skip || $mask->{lock}) ? $skip + $mask->{shift} - 1 : $mask->{shift};
174             }
175             elsif ($mask->{hide}) {
176 147 100 66     576 $skip = ($skip || $mask->{lock}) ? $skip + $mask->{hide} - 1 : $mask->{hide};
177             }
178             elsif($skip && !(--$skip) && $shift) {
179 40 50       142 unless ($mask->{lock}) {
180 40         91 $fields->{msg} = $shift->{msg};
181 40         84 $fields->{indent} = $shift->{indent};
182 40         73 $fields->{sub} = $shift->{sub};
183 40         75 $fields->{args} = $shift->{args};
184             }
185 40         51 $shift = undef;
186             }
187              
188 1114 100 66     3716 unless ($skip || ($mask->{no_start} && !$out)) {
      66        
189 733 100       1341 if ($error) {
190 137         280 $fields->{msg} = $error->{msg};
191 137         224 $fields->{indent} = $error->{indent};
192 137         269 delete $fields->{sub};
193 137         227 $error = undef;
194             }
195 733         1526 $out .= _write_carp_line($fields)
196             }
197              
198 1114 100       3762 $stopped = 1 if $mask->{stop};
199             }
200              
201 137 100       297 if ($shift) {
202 10         24 $last->{msg} = $shift->{msg};
203 10         21 $last->{indent} = $shift->{indent};
204 10         20 $last->{sub} = $shift->{sub};
205 10         21 $last->{args} = $shift->{args};
206 10 50 33     148 $out .= _write_carp_line($last) unless $out && $out =~ m/at \Q$last->{file}\E line $last->{line}/;
207             }
208              
209 137         1925 return $out;
210             }
211              
212             1;
213              
214             __END__