File Coverage

blib/lib/Carp/Source.pm
Criterion Covered Total %
statement 42 97 43.3
branch 7 44 15.9
condition 0 8 0.0
subroutine 10 17 58.8
pod 9 9 100.0
total 68 175 38.8


line stmt bran cond sub pod time code
1 2     2   1515 use 5.008;
  2         6  
  2         98  
2 2     2   11 use strict;
  2         3  
  2         58  
3 2     2   10 use warnings;
  2         4  
  2         115  
4              
5             package Carp::Source;
6             BEGIN {
7 2     2   36 $Carp::Source::VERSION = '1.101420';
8             }
9             # ABSTRACT: Warn of errors with stack backtrace and source context
10 2     2   2332 use utf8;
  2         120  
  2         11  
11 2     2   2812 use Term::ANSIColor;
  2         21869  
  2         204  
12 2     2   20 use Exporter qw(import);
  2         5  
  2         1228  
13             our %EXPORT_TAGS = (util => [qw(source_cluck)],);
14             our @EXPORT_OK = @{ $EXPORT_TAGS{all} = [ map { @$_ } values %EXPORT_TAGS ] };
15             our ($MaxArgNums, $MaxEvalLen, $MaxArgLen, $Verbose);
16              
17             # If a string is too long, trims it with ...
18             sub str_len_trim {
19 0     0 1 0 my $str = shift;
20 0   0     0 my $max = shift || 0;
21 0 0 0     0 if (2 < $max and $max < length($str)) {
22 0         0 substr($str, $max - 3) = '...';
23             }
24 0         0 return $str;
25             }
26              
27             # Transform an argument to a function into a string.
28             sub format_arg {
29 0     0 1 0 my $arg = shift;
30 0 0       0 if (ref($arg)) {
    0          
31 0 0       0 $arg = defined($overload::VERSION) ? overload::StrVal($arg) : "$arg";
32             } elsif (not defined($arg)) {
33 0         0 $arg = 'undef';
34             }
35 0         0 $arg =~ s/'/\\'/g;
36 0         0 $arg = str_len_trim($arg, $MaxArgLen);
37              
38             # Quote it?
39 0 0       0 $arg = "'$arg'" unless $arg =~ /^-?[\d.]+\z/;
40              
41             # The following handling of "control chars" is direct from
42             # the original code - it is broken on Unicode though.
43             # Suggestions?
44 0 0       0 utf8::is_utf8($arg)
45              
46             # x{"."%x} is a kludge so we don't have a template start_tag in the code
47 0         0 or $arg =~ s/([[:cntrl:]]|[[:^ascii:]])/sprintf("\\x{"."%x}",ord($1))/eg;
48 0         0 return $arg;
49             }
50              
51             # Takes the info from caller() and figures out the name of
52             # the sub/require/eval
53             sub get_subname {
54 0     0 1 0 my $info = shift;
55 0 0       0 if (defined($info->{evaltext})) {
56 0         0 my $eval = $info->{evaltext};
57 0 0       0 if ($info->{is_require}) {
58 0         0 return "require $eval";
59             } else {
60 0         0 $eval =~ s/([\\\'])/\\$1/g;
61 0         0 return "eval '" . str_len_trim($eval, $MaxEvalLen) . "'";
62             }
63             }
64 0 0       0 return ($info->{sub} eq '(eval)') ? 'eval {...}' : $info->{sub};
65             }
66              
67             sub caller_info {
68 0     0 1 0 my $i = shift(@_) + 1;
69              
70             # FIXME Dist::Zilla's [PkgVersion] adds a BEGIN { $DB::VERSION = ... }
71             # here; should skip package DB
72             ## no critic (ProhibitNestedSubs)
73             package DB;
74             BEGIN {
75 2     2   2709 $DB::VERSION = '1.101420';
76             }
77 0         0 my %call_info;
78 0         0 @call_info{qw(pack file line sub has_args wantarray evaltext is_require)} =
79             caller($i);
80 0 0       0 unless (defined $call_info{pack}) {
81 0         0 return ();
82             }
83 0         0 my $sub_name = Carp::Source::get_subname(\%call_info);
84 0 0       0 if ($call_info{has_args}) {
85 0         0 my @args = map { Carp::Source::format_arg($_) } @DB::args;
  0         0  
86 0 0 0     0 if ($MaxArgNums and @args > $MaxArgNums) { # More than we want to show?
87 0         0 $#args = $MaxArgNums;
88 0         0 push @args, '...';
89             }
90              
91             # Push the args onto the subroutine
92 0         0 $sub_name .= '(' . join(', ', @args) . ')';
93             }
94 0         0 $call_info{sub_name} = $sub_name;
95 0 0       0 return wantarray() ? %call_info : \%call_info;
96             }
97              
98             sub longmess_heavy {
99 0 0   0 1 0 return @_ if ref($_[0]); # don't break references as exceptions
100 0         0 return ret_backtrace(0, @_);
101             }
102              
103             # Returns a full stack backtrace starting from where it is
104             # told.
105             sub ret_backtrace {
106 0     0 1 0 my ($i, $err, %options) = @_;
107 0         0 my $mess;
108 0         0 $i++;
109 0         0 my $tid_msg = '';
110 0 0       0 if (defined &Thread::tid) {
111 0         0 my $tid = Thread->self->tid;
112 0 0       0 $tid_msg = " thread $tid" if $tid;
113             }
114 0         0 my %i = caller_info($i);
115 0         0 $mess = "$err at $i{file} line $i{line}$tid_msg\n";
116 0         0 while (my %i = caller_info(++$i)) {
117 0         0 my $context = get_context($i{file}, $i{line}, %options);
118 0         0 print $context;
119 0         0 $mess .= "\t$i{sub_name} called at $i{file} line $i{line}$tid_msg\n";
120             }
121 0         0 return $mess;
122             }
123              
124             sub format_line {
125 18     18 1 153 my ($line_number, $text, %options) = @_;
126 18 100       71 return "$text\n" unless $options{number};
127 7         36 sprintf "%4d: %s\n", $line_number, $text;
128             }
129              
130             sub get_context {
131 2     2 1 26 my ($file, $line, %options) = @_;
132 2         17 %options = (
133             lines => 3,
134             number => 1,
135             color => 'black on_yellow',
136             %options,
137             );
138 2 50       749 open my $fh, '<', $file or die "can't open $file: $!\n";
139 2         105 chomp(my @lines = <$fh>);
140 2 50       30 close $fh or die "can't close $file: $!\n";
141              
142             # make calculations easier by having line 1 at element 1
143 2         12 unshift @lines => '';
144 2         10 my $min_line = $line - $options{lines};
145 2 50       16 $min_line = 0 if $min_line < 0;
146 2         8 my $max_line = $line + $options{lines};
147 2         10 my $source = "context for $file line $line:\n\n";
148 2         8 for my $c_line ($min_line .. $line - 1) {
149 8 50       21 next unless defined $lines[$c_line];
150 8         28 $source .= format_line($c_line, $lines[$c_line], %options);
151             }
152             $source .=
153 2         19 format_line($line, colored([ $options{color} ], $lines[$line]), %options);
154 2         9 for my $c_line ($line + 1 .. $max_line) {
155 8 50       21 next unless defined $lines[$c_line];
156 8         22 $source .= format_line($c_line, $lines[$c_line], %options);
157             }
158 2         7 $source .= ('=' x 75) . "\n";
159 2         19 $source;
160             }
161 0     0 1   sub source_cluck ($;@) { warn longmess_heavy(@_) }
162             1;
163              
164              
165             __END__