File: | local/lib/perl5/Devel/StackTrace.pm |
Coverage: | 12.2% |
line | stmt | bran | cond | sub | time | code |
---|---|---|---|---|---|---|
1 | package Devel::StackTrace; | |||||
2 | $Devel::StackTrace::VERSION = '1.32'; | |||||
3 | 6 6 | 64 10 | use 5.006; | |||
4 | ||||||
5 | 6 6 6 | 14 8 86 | use strict; | |||
6 | 6 6 6 | 13 5 86 | use warnings; | |||
7 | ||||||
8 | 6 6 6 | 1209 10 117 | use Devel::StackTrace::Frame; | |||
9 | 6 6 6 | 22 5 85 | use File::Spec; | |||
10 | 6 6 6 | 16 6 438 | use Scalar::Util qw( blessed ); | |||
11 | ||||||
12 | use overload | |||||
13 | 6 | 4025 | '""' => \&as_string, | |||
14 | 6 6 | 18 6 | fallback => 1; | |||
15 | ||||||
16 | sub new { | |||||
17 | 0 | my $class = shift; | ||||
18 | 0 | my %p = @_; | ||||
19 | ||||||
20 | # Backwards compatibility - this parameter was renamed to no_refs | |||||
21 | # ages ago. | |||||
22 | 0 | $p{no_refs} = delete $p{no_object_refs} | ||||
23 | if exists $p{no_object_refs}; | |||||
24 | ||||||
25 | 0 | my $self = bless { | ||||
26 | index => undef, | |||||
27 | frames => [], | |||||
28 | raw => [], | |||||
29 | %p, | |||||
30 | }, $class; | |||||
31 | ||||||
32 | 0 | $self->_record_caller_data(); | ||||
33 | ||||||
34 | 0 | return $self; | ||||
35 | } | |||||
36 | ||||||
37 | sub _record_caller_data { | |||||
38 | 0 | my $self = shift; | ||||
39 | ||||||
40 | 0 | my $filter = $self->{filter_frames_early} && $self->_make_frame_filter(); | ||||
41 | ||||||
42 | # We exclude this method by starting one frame back. | |||||
43 | 0 | my $x = 1; | ||||
44 | 0 | while ( | ||||
45 | my @c | |||||
46 | = $self->{no_args} | |||||
47 | ? caller( $x++ ) | |||||
48 | : do { | |||||
49 | package # the newline keeps dzil from adding a version here | |||||
50 | DB; | |||||
51 | 0 | @DB::args = (); | ||||
52 | 0 | caller( $x++ ); | ||||
53 | } | |||||
54 | ) { | |||||
55 | ||||||
56 | 0 | my @args; | ||||
57 | ||||||
58 | 0 | @args = $self->{no_args} ? () : @DB::args; | ||||
59 | ||||||
60 | 0 | my $raw = { | ||||
61 | caller => \@c, | |||||
62 | args => \@args, | |||||
63 | }; | |||||
64 | ||||||
65 | 0 | next if $filter && !$filter->($raw); | ||||
66 | ||||||
67 | 0 | if ( $self->{no_refs} ) { | ||||
68 | 0 0 0 | $raw->{args} = [ map { ref $_ ? $self->_ref_to_string($_) : $_ } @{$raw->{args}} ]; | ||||
69 | } | |||||
70 | ||||||
71 | 0 0 | push @{ $self->{raw} }, $raw; | ||||
72 | } | |||||
73 | } | |||||
74 | ||||||
75 | sub _ref_to_string { | |||||
76 | 0 | my $self = shift; | ||||
77 | 0 | my $ref = shift; | ||||
78 | ||||||
79 | 0 | return overload::AddrRef($ref) | ||||
80 | if blessed $ref && $ref->isa('Exception::Class::Base'); | |||||
81 | ||||||
82 | 0 | return overload::AddrRef($ref) unless $self->{respect_overload}; | ||||
83 | ||||||
84 | 0 | local $@; | ||||
85 | 0 | local $SIG{__DIE__}; | ||||
86 | ||||||
87 | 0 0 | my $str = eval { $ref . '' }; | ||||
88 | ||||||
89 | 0 | return $@ ? overload::AddrRef($ref) : $str; | ||||
90 | } | |||||
91 | ||||||
92 | sub _make_frames { | |||||
93 | 0 | my $self = shift; | ||||
94 | ||||||
95 | 0 | my $filter = !$self->{filter_frames_early} && $self->_make_frame_filter(); | ||||
96 | ||||||
97 | 0 | my $raw = delete $self->{raw}; | ||||
98 | 0 0 | for my $r ( @{$raw} ) { | ||||
99 | 0 | next if $filter && ! $filter->($r); | ||||
100 | ||||||
101 | 0 | $self->_add_frame( $r->{caller}, $r->{args} ); | ||||
102 | } | |||||
103 | } | |||||
104 | ||||||
105 | my $default_filter = sub { 1 }; | |||||
106 | ||||||
107 | sub _make_frame_filter { | |||||
108 | 0 | my $self = shift; | ||||
109 | ||||||
110 | 0 | my ( @i_pack_re, %i_class ); | ||||
111 | 0 | if ( $self->{ignore_package} ) { | ||||
112 | 0 | local $@; | ||||
113 | 0 | local $SIG{__DIE__}; | ||||
114 | ||||||
115 | $self->{ignore_package} = [ $self->{ignore_package} ] | |||||
116 | 0 0 0 | unless eval { @{ $self->{ignore_package} } }; | ||||
117 | ||||||
118 | @i_pack_re | |||||
119 | 0 0 0 | = map { ref $_ ? $_ : qr/^\Q$_\E$/ } @{ $self->{ignore_package} }; | ||||
120 | } | |||||
121 | ||||||
122 | 0 | my $p = __PACKAGE__; | ||||
123 | 0 | push @i_pack_re, qr/^\Q$p\E$/; | ||||
124 | ||||||
125 | 0 | if ( $self->{ignore_class} ) { | ||||
126 | 0 | $self->{ignore_class} = [ $self->{ignore_class} ] | ||||
127 | unless ref $self->{ignore_class}; | |||||
128 | 0 0 0 | %i_class = map { $_ => 1 } @{ $self->{ignore_class} }; | ||||
129 | } | |||||
130 | ||||||
131 | 0 | my $user_filter = $self->{frame_filter}; | ||||
132 | ||||||
133 | return sub { | |||||
134 | 0 0 | return 0 if grep { $_[0]{caller}[0] =~ /$_/ } @i_pack_re; | ||||
135 | 0 0 | return 0 if grep { $_[0]{caller}[0]->isa($_) } keys %i_class; | ||||
136 | ||||||
137 | 0 | if ($user_filter) { | ||||
138 | 0 | return $user_filter->( $_[0] ); | ||||
139 | } | |||||
140 | ||||||
141 | 0 | return 1; | ||||
142 | 0 | }; | ||||
143 | } | |||||
144 | ||||||
145 | sub _add_frame { | |||||
146 | 0 | my $self = shift; | ||||
147 | 0 | my $c = shift; | ||||
148 | 0 | my $p = shift; | ||||
149 | ||||||
150 | # eval and is_require are only returned when applicable under 5.00503. | |||||
151 | 0 | push @$c, ( undef, undef ) if scalar @$c == 6; | ||||
152 | ||||||
153 | 0 0 | push @{ $self->{frames} }, | ||||
154 | Devel::StackTrace::Frame->new( | |||||
155 | $c, | |||||
156 | $p, | |||||
157 | $self->{respect_overload}, | |||||
158 | $self->{max_arg_length}, | |||||
159 | $self->{message}, | |||||
160 | $self->{indent} | |||||
161 | ); | |||||
162 | } | |||||
163 | ||||||
164 | sub next_frame { | |||||
165 | 0 | my $self = shift; | ||||
166 | ||||||
167 | # reset to top if necessary. | |||||
168 | 0 | $self->{index} = -1 unless defined $self->{index}; | ||||
169 | ||||||
170 | 0 | my @f = $self->frames(); | ||||
171 | 0 | if ( defined $f[ $self->{index} + 1 ] ) { | ||||
172 | 0 | return $f[ ++$self->{index} ]; | ||||
173 | } | |||||
174 | else { | |||||
175 | 0 | $self->{index} = undef; | ||||
176 | 0 | return undef; | ||||
177 | } | |||||
178 | } | |||||
179 | ||||||
180 | sub prev_frame { | |||||
181 | 0 | my $self = shift; | ||||
182 | ||||||
183 | 0 | my @f = $self->frames(); | ||||
184 | ||||||
185 | # reset to top if necessary. | |||||
186 | 0 | $self->{index} = scalar @f unless defined $self->{index}; | ||||
187 | ||||||
188 | 0 | if ( defined $f[ $self->{index} - 1 ] && $self->{index} >= 1 ) { | ||||
189 | 0 | return $f[ --$self->{index} ]; | ||||
190 | } | |||||
191 | else { | |||||
192 | 0 | $self->{index} = undef; | ||||
193 | 0 | return undef; | ||||
194 | } | |||||
195 | } | |||||
196 | ||||||
197 | sub reset_pointer { | |||||
198 | 0 | my $self = shift; | ||||
199 | ||||||
200 | 0 | $self->{index} = undef; | ||||
201 | } | |||||
202 | ||||||
203 | sub frames { | |||||
204 | 0 | my $self = shift; | ||||
205 | ||||||
206 | 0 | if (@_) { | ||||
207 | 0 | die | ||||
208 | "Devel::StackTrace->frames() can only take Devel::StackTrace::Frame args\n" | |||||
209 | 0 | if grep { !$_->isa('Devel::StackTrace::Frame') } @_; | ||||
210 | ||||||
211 | 0 | $self->{frames} = \@_; | ||||
212 | } | |||||
213 | else { | |||||
214 | 0 | $self->_make_frames() if $self->{raw}; | ||||
215 | } | |||||
216 | ||||||
217 | 0 0 | return @{ $self->{frames} }; | ||||
218 | } | |||||
219 | ||||||
220 | sub frame { | |||||
221 | 0 | my $self = shift; | ||||
222 | 0 | my $i = shift; | ||||
223 | ||||||
224 | 0 | return unless defined $i; | ||||
225 | ||||||
226 | 0 | return ( $self->frames() )[$i]; | ||||
227 | } | |||||
228 | ||||||
229 | sub frame_count { | |||||
230 | 0 | my $self = shift; | ||||
231 | ||||||
232 | 0 | return scalar( $self->frames() ); | ||||
233 | } | |||||
234 | ||||||
235 | sub as_string { | |||||
236 | 0 | my $self = shift; | ||||
237 | 0 | my $p = shift; | ||||
238 | ||||||
239 | 0 | my $st = ''; | ||||
240 | 0 | my $first = 1; | ||||
241 | 0 | foreach my $f ( $self->frames() ) { | ||||
242 | 0 | $st .= $f->as_string( $first, $p ) . "\n"; | ||||
243 | 0 | $first = 0; | ||||
244 | } | |||||
245 | ||||||
246 | 0 | return $st; | ||||
247 | } | |||||
248 | ||||||
249 | { | |||||
250 | package | |||||
251 | Devel::StackTraceFrame; | |||||
252 | ||||||
253 | our @ISA = 'Devel::StackTrace::Frame'; | |||||
254 | } | |||||
255 | ||||||
256 | 1; | |||||
257 | ||||||
258 | # ABSTRACT: An object representing a stack trace | |||||
259 |