File: | local/lib/perl5/Devel/StackTrace/Frame.pm |
Coverage: | 17.0% |
line | stmt | bran | cond | sub | time | code |
---|---|---|---|---|---|---|
1 | package Devel::StackTrace::Frame; | |||||
2 | $Devel::StackTrace::Frame::VERSION = '1.32'; | |||||
3 | 6 6 6 | 19 4 108 | use strict; | |||
4 | 6 6 6 | 15 5 119 | use warnings; | |||
5 | ||||||
6 | # Create accessor routines | |||||
7 | BEGIN { | |||||
8 | 6 6 6 | 15 2 315 | no strict 'refs'; | |||
9 | 6 | 15 | foreach my $f ( | |||
10 | qw( package filename line subroutine hasargs | |||||
11 | wantarray evaltext is_require hints bitmask args ) | |||||
12 | ) { | |||||
13 | 66 | 2735 | next if $f eq 'args'; | |||
14 | 60 60 0 0 | 95 131 | *{$f} = sub { my $s = shift; return $s->{$f} }; | |||
15 | } | |||||
16 | } | |||||
17 | ||||||
18 | { | |||||
19 | my @fields = ( | |||||
20 | qw( package filename line subroutine hasargs wantarray | |||||
21 | evaltext is_require hints bitmask ) | |||||
22 | ); | |||||
23 | ||||||
24 | sub new { | |||||
25 | 0 | my $proto = shift; | ||||
26 | 0 | my $class = ref $proto || $proto; | ||||
27 | ||||||
28 | 0 | my $self = bless {}, $class; | ||||
29 | ||||||
30 | 0 0 0 | @{$self}{@fields} = @{ shift() }; | ||||
31 | ||||||
32 | # fixup unix-style paths on win32 | |||||
33 | 0 | $self->{filename} = File::Spec->canonpath( $self->{filename} ); | ||||
34 | ||||||
35 | 0 | $self->{args} = shift; | ||||
36 | ||||||
37 | 0 | $self->{respect_overload} = shift; | ||||
38 | ||||||
39 | 0 | $self->{max_arg_length} = shift; | ||||
40 | ||||||
41 | 0 | $self->{message} = shift; | ||||
42 | ||||||
43 | 0 | $self->{indent} = shift; | ||||
44 | ||||||
45 | 0 | return $self; | ||||
46 | } | |||||
47 | } | |||||
48 | ||||||
49 | sub args { | |||||
50 | 0 | my $self = shift; | ||||
51 | ||||||
52 | 0 0 | return @{ $self->{args} }; | ||||
53 | } | |||||
54 | ||||||
55 | sub as_string { | |||||
56 | 0 | my $self = shift; | ||||
57 | 0 | my $first = shift; | ||||
58 | 0 | my $p = shift; | ||||
59 | ||||||
60 | 0 | my $sub = $self->subroutine; | ||||
61 | ||||||
62 | # This code stolen straight from Carp.pm and then tweaked. All | |||||
63 | # errors are probably my fault -dave | |||||
64 | 0 | if ($first) { | ||||
65 | 0 | $sub | ||||
66 | = defined $self->{message} | |||||
67 | ? $self->{message} | |||||
68 | : 'Trace begun'; | |||||
69 | } | |||||
70 | else { | |||||
71 | ||||||
72 | # Build a string, $sub, which names the sub-routine called. | |||||
73 | # This may also be "require ...", "eval '...' or "eval {...}" | |||||
74 | 0 | if ( my $eval = $self->evaltext ) { | ||||
75 | 0 | if ( $self->is_require ) { | ||||
76 | 0 | $sub = "require $eval"; | ||||
77 | } | |||||
78 | else { | |||||
79 | 0 | $eval =~ s/([\\\'])/\\$1/g; | ||||
80 | 0 | $sub = "eval '$eval'"; | ||||
81 | } | |||||
82 | } | |||||
83 | elsif ( $sub eq '(eval)' ) { | |||||
84 | 0 | $sub = 'eval {...}'; | ||||
85 | } | |||||
86 | ||||||
87 | # if there are any arguments in the sub-routine call, format | |||||
88 | # them according to the format variables defined earlier in | |||||
89 | # this file and join them onto the $sub sub-routine string | |||||
90 | # | |||||
91 | # We copy them because they're going to be modified. | |||||
92 | # | |||||
93 | 0 | if ( my @a = $self->args ) { | ||||
94 | 0 | for (@a) { | ||||
95 | ||||||
96 | # set args to the string "undef" if undefined | |||||
97 | 0 | $_ = "undef", next unless defined $_; | ||||
98 | ||||||
99 | # hack! | |||||
100 | 0 | $_ = $self->Devel::StackTrace::_ref_to_string($_) | ||||
101 | if ref $_; | |||||
102 | ||||||
103 | 0 | local $SIG{__DIE__}; | ||||
104 | 0 | local $@; | ||||
105 | ||||||
106 | 0 | eval { | ||||
107 | 0 | my $max_arg_length | ||||
108 | = exists $p->{max_arg_length} | |||||
109 | ? $p->{max_arg_length} | |||||
110 | : $self->{max_arg_length}; | |||||
111 | ||||||
112 | 0 | if ( $max_arg_length | ||||
113 | && length $_ > $max_arg_length ) { | |||||
114 | 0 | substr( $_, $max_arg_length ) = '...'; | ||||
115 | } | |||||
116 | ||||||
117 | 0 | s/'/\\'/g; | ||||
118 | ||||||
119 | # 'quote' arg unless it looks like a number | |||||
120 | 0 | $_ = "'$_'" unless /^-?[\d.]+$/; | ||||
121 | ||||||
122 | # print control/high ASCII chars as 'M-<char>' or '^<char>' | |||||
123 | 0 0 | s/([\200-\377])/sprintf("M-%c",ord($1)&0177)/eg; | ||||
124 | 0 0 | s/([\0-\37\177])/sprintf("^%c",ord($1)^64)/eg; | ||||
125 | }; | |||||
126 | ||||||
127 | 0 | if ( my $e = $@ ) { | ||||
128 | 0 | $_ = $e =~ /malformed utf-8/i ? '(bad utf-8)' : '?'; | ||||
129 | } | |||||
130 | } | |||||
131 | ||||||
132 | # append ('all', 'the', 'arguments') to the $sub string | |||||
133 | 0 | $sub .= '(' . join( ', ', @a ) . ')'; | ||||
134 | 0 | $sub .= ' called'; | ||||
135 | } | |||||
136 | } | |||||
137 | ||||||
138 | # If the user opted into indentation (a la Carp::confess), pre-add a tab | |||||
139 | 0 | my $tab = $self->{indent} && !$first ? "\t" : q{}; | ||||
140 | ||||||
141 | 0 | return "${tab}$sub at " . $self->filename . ' line ' . $self->line; | ||||
142 | } | |||||
143 | ||||||
144 | 1; | |||||
145 | ||||||
146 | # ABSTRACT: A single frame in a stack trace | |||||
147 |