File Coverage

blib/lib/Trace/Mask/Carp.pm
Criterion Covered Total %
statement 141 142 99.3
branch 71 82 86.5
condition 41 60 68.3
subroutine 23 23 100.0
pod 6 6 100.0
total 282 313 90.1


line stmt bran cond sub pod time code
1             package Trace::Mask::Carp;
2 2     2   90050 use strict;
  2         3  
  2         44  
3 2     2   6 use warnings;
  2         2  
  2         44  
4              
5 2     2   11 use Carp 1.03 ();
  2         37  
  2         69  
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   309 use Trace::Mask::Util qw/get_mask mask_line/;
  2         2  
  2         133  
11              
12             BEGIN {
13 2 50   2   415 *carp_longmess = Carp->can('longmess') or die "Could not find Carp::longmess";
14             }
15              
16 32     32 1 6905 sub longmess { mask_trace(scalar(carp_longmess(@_)), 'Trace::Mask::Carp::longmess') }
17 26     26 1 4538 sub confess { die mask_trace(scalar(carp_longmess(@_)), 'Trace::Mask::Carp::confess') }
18 26     26 1 4481 sub cluck { warn mask_trace(scalar(carp_longmess(@_)), 'Trace::Mask::Carp::cluck') }
19              
20             sub _my_croak {
21 2     2   2 my $msg = shift;
22 2         15 my @caller = caller(1);
23 2         20 die "$msg at $caller[1] line $caller[2].\n";
24             }
25              
26             sub import {
27 8     8   13733 my $class = shift;
28              
29 8         14 my $caller = caller;
30              
31 8         9 my %flags;
32              
33 8         15 for my $arg (@_) {
34 14 100       45 if ($arg =~ m/^-(.+)$/) {
    50          
35 6         19 $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     46 my $sub = $class->can($arg) || _my_croak "'$arg' is not exported by $class";
42 2     2   10 no strict 'refs';
  2         6  
  2         594  
43 7         6 *{"$caller\::$arg"} = $sub;
  7         22  
44             }
45             }
46              
47 7 100       23 $class->_global_override if delete $flags{'global'};
48 7 100       23 $class->_wrap_carp if delete $flags{'wrap'};
49              
50 7         20 my @bad = sort keys %flags;
51 7 100       614 return unless @bad;
52 1         2 _my_croak "bad flag(s): " . join (", ", map { "-$_" } @bad);
  2         7  
53             }
54              
55             sub _global_override {
56 26   50 26   237 my $die = $SIG{__DIE__} || sub { CORE::die(@_) };
  3     3   25  
57 3   50 26   20 my $warn = $SIG{__WARN__} || sub { CORE::warn(@_) };
  26         268  
58              
59             $SIG{__DIE__} = sub {
60 26     26   16503 my $error = shift;
61 26         123 my @caller = caller(1);
62 26 50       145 $error = mask_trace($error, $caller[3]) if $caller[3] =~ m/^Carp::(confess|longmess|cluck)$/;
63 26         43 return $die->($error)
64 3         14 };
65              
66             $SIG{__WARN__} = sub {
67 26     26   16783 my $msg = shift;
68 26         123 my @caller = caller(1);
69 26 50       155 $msg = mask_trace($msg, $caller[3]) if $caller[3] =~ m/^Carp::(confess|longmess|cluck)$/;
70 26         52 $warn->($msg);
71 3         11 };
72             }
73              
74             sub _wrap_carp {
75 2     2   8 no warnings 'redefine';
  2         3  
  2         211  
76 2     2   9 *Carp::confess = \&confess;
77 2         6 *Carp::longmess = \&longmess;
78 2         7 *Carp::cluck = \&cluck;
79             }
80              
81             sub mask(&) {
82 1     1 1 2546 my ($code) = @_;
83 1         3 my $sigwarn = $SIG{__WARN__};
84 1         2 my $sigdie = $SIG{__DIE__};
85              
86 1         2 local $SIG{__WARN__};
87 1         2 local $SIG{__DIE__};
88              
89 1 50       4 $SIG{__WARN__} = $sigwarn if $sigwarn;
90 1 50       2 $SIG{__DIE__} = $sigdie if $sigdie;
91              
92 1         3 _global_override();
93              
94 2     2   8 BEGIN { mask_line({hide => 2}, 1) }
95 1         2 $code->();
96             }
97              
98             sub parse_carp_line {
99 3387     3387 1 19474 my ($line) = @_;
100 3387         4209 my %out = (orig => $line);
101              
102 3387 100       12246 if ($line =~ m/^(\s*)([^\(]+)\((.*)\) called at (.+) line (\d+)\.?$/) { # Long
    100          
    100          
103 2716         7616 @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 399         964 @out{qw/sub indent file line/} = ('eval', $1, $2, $3);
107             }
108             elsif ($line =~ m/^(\s*)(.*) at (.+) line (\d+)\.?$/) { # Short
109 268         882 @out{qw/indent msg file line/} = ($1, $2, $3, $4);
110             }
111              
112 3387 100       7334 return \%out if keys(%out) > 1;
113 4         8 return undef;
114             }
115              
116             sub _write_carp_line{
117 638     638   509 my ($fields) = @_;
118 638         489 my ($indent, $file, $line, $sub, $msg, $args) = @{$fields}{qw/indent file line sub msg args/};
  638         916  
119 638   100     1014 $indent ||= "";
120              
121 638 100 100     1630 if ($msg || !$sub) {
122 137   100     298 $msg ||= "";
123 137         324 return "$indent$msg at $file line $line.\n";
124             }
125              
126 501 100       562 if ($sub eq 'eval') {
127 2         6 return "$indent$sub {...} called at $file line $line\n";
128             }
129             else {
130 499   100     579 $args ||= "";
131 499         1042 return "$indent$sub\($args) called at $file line $line\n";
132             }
133             }
134              
135             sub mask_trace {
136 137     137 1 37685 my ($msg, $sub) = @_;
137 137 50       319 return $msg if $ENV{NO_TRACE_MASK};
138 137         2228 my @lines = split /[\n\r]+/, $msg;
139 137 50       248 return $msg unless @lines > 1;
140              
141 137         143 my $out = "";
142 137         114 my ($shift, $last);
143 137         121 my $skip = 0;
144              
145 137         86 my $num = 0;
146 137         101 my $error;
147 137         89 my $stopped = 0;
148 137         97 my $paused = 0;
149 137         158 for my $line (@lines) {
150 2763         2663 my $fields = parse_carp_line($line);
151              
152 2763 100       3234 unless($fields) {
153 3         4 $out .= "$line\n";
154 3         3 next;
155             }
156              
157 2760 100 33     3219 $fields->{sub} ||= $sub unless $num;
158 2760 100       3220 $error = $fields if exists $fields->{msg};
159 2760         1747 $num++;
160              
161 2760   50     1699 my $mask = get_mask(@{$fields}{qw/file line/}, $fields->{sub} || '*');
  2760         6495  
162              
163 2760 100 66     5942 next if $paused && !($mask->{restart} || $mask->{lock});
      100        
164 2248 100       2786 $paused = 0 if $mask->{restart};
165              
166 2248 100 66     5857 next if $stopped && !$mask->{lock};
167              
168 988 100 66     2476 $last = $fields unless $mask->{hide} || $mask->{shift} || $mask->{lock};
      66        
169              
170 988 100       1723 unless ($mask->{lock}) {
171 966 100       1140 $fields->{file} = $mask->{1} if $mask->{1};
172 966 100       1157 $fields->{line} = $mask->{2} if $mask->{2};
173 966 100       1192 $fields->{sub} = $mask->{3} if $mask->{3};
174             }
175              
176 988 100 100     2717 if ($mask->{shift}) {
    100 100        
    100          
177 50   33     128 $shift ||= $fields;
178 50 50 33     115 $skip = ($skip || $mask->{lock}) ? $skip + $mask->{shift} - 1 : $mask->{shift};
179             }
180             elsif ($mask->{hide}) {
181 146 100 66     369 $skip = ($skip || $mask->{lock}) ? $skip + $mask->{hide} - 1 : $mask->{hide};
182             }
183             elsif($skip && !(--$skip) && $shift) {
184 40 50       62 unless ($mask->{lock}) {
185 40         45 $fields->{msg} = $shift->{msg};
186 40         42 $fields->{indent} = $shift->{indent};
187 40         35 $fields->{sub} = $shift->{sub};
188 40         42 $fields->{args} = $shift->{args};
189             }
190 40         29 $shift = undef;
191             }
192              
193 988 100 66     1985 unless ($skip || ($mask->{no_start} && !$out)) {
      66        
194 628 100       712 if ($error) {
195 137         129 $fields->{msg} = $error->{msg};
196 137         87 $fields->{indent} = $error->{indent};
197 137         155 delete $fields->{sub};
198 137         106 $error = undef;
199             }
200 628         714 $out .= _write_carp_line($fields)
201             }
202              
203 988 100       1339 $stopped = 1 if $mask->{stop};
204 988 100       1794 $paused = 1 if $mask->{pause};
205             }
206              
207 137 100       200 if ($shift) {
208 10         17 $last->{msg} = $shift->{msg};
209 10         15 $last->{indent} = $shift->{indent};
210 10         15 $last->{sub} = $shift->{sub};
211 10         8 $last->{args} = $shift->{args};
212 10 50 33     104 $out .= _write_carp_line($last) unless $out && $out =~ m/at \Q$last->{file}\E line $last->{line}/;
213             }
214              
215 137         951 return $out;
216             }
217              
218             1;
219              
220             __END__