File Coverage

blib/lib/Parse/StackTrace/Thread.pm
Criterion Covered Total %
statement 1 3 33.3
branch n/a
condition n/a
subroutine 1 1 100.0
pod n/a
total 2 4 50.0


line stmt bran cond sub pod time code
1             package Parse::StackTrace::Thread;
2 1     1   9313 use Moose;
  0            
  0            
3             use Moose::Util::TypeConstraints;
4             use MooseX::AttributeHelpers;
5              
6             subtype 'Parse::StackTrace::BigInt' => as class_type('Math::BigInt');
7              
8             has 'frames' => (
9             is => 'ro',
10             isa => 'ArrayRef[Parse::StackTrace::Frame]',
11             default => sub { [] },
12             metaclass => 'Collection::Array',
13             provides => {
14             push => 'add_frame',
15             unshift => '_unshift_frame',
16             },
17             );
18              
19             has 'number' => (is => 'ro', isa => 'Int|Parse::StackTrace::BigInt',
20             predicate => 'has_number');
21             has 'description' => (is => 'ro', isa => 'Str', default => '');
22              
23             has 'starting_line' => (is => 'rw', isa => 'Int',
24             predicate => 'has_starting_line');
25             has 'ending_line' => (is => 'rw', isa => 'Int');
26              
27             sub frame_number {
28             my ($self, $number) = @_;
29             # First check if the frame at that array position is the frame
30             # we want, as an optimization.
31             my $try = $self->frames->[$number];
32             if ($try and $try->number and $try->number == $number) {
33             return $try;
34             }
35             my ($frame) = grep { defined $_->number and $_->number == $number }
36             @{ $self->frames };
37             return $frame;
38             }
39              
40             sub frames_with_function {
41             my ($self, $func) = @_;
42             my @frames = grep { $_->function eq $func } @{ $self->frames };
43             return wantarray ? @frames : $frames[0];
44             }
45              
46             sub frame_with_crash {
47             my ($self) = @_;
48             my ($frame) = grep { $_->is_crash } @{ $self->frames };
49             return $frame;
50             }
51              
52             __PACKAGE__->meta->make_immutable;
53              
54             1;
55              
56             __END__
57              
58             =head1 NAME
59              
60             Parse::StackTrace::Thread - A single thread (or the only thread) of a stack
61             trace.
62              
63             =head1 SYNOPSIS
64              
65             my $thread = $trace->thread_number(1);
66            
67             my $frames = $thread->frames;
68             my $thread_number = $thread->number;
69             my $thread_description = $thread->description;
70            
71             my $first_frame = $thread->frame_number(0);
72             my @print_frames = $thread->frames_with_function('print');
73             my $print_frame = $thread->frames_with_function('print');
74             my $crash_frame = $thread->frame_with_crash;
75              
76             =head1 DESCRIPTION
77              
78             Represents a single thread of a stack trace (or, for traces that have only
79             one thread, the one thread of a stack trace). Generally, you access a thread
80             by calling L<Parse::StackTrace/threads> or L<Parse::StackTrace/thread_number>.
81              
82             =head1 SIMPLE ACCESSOR METHODS
83              
84             These are methods that take no arguments and just return information
85             about the thread.
86              
87             =head2 C<frames>
88              
89             An arrayref of L<Parse::StackTrace::Frame> objects. All the frames of
90             this thread. There should always be at least one frame.
91              
92             Frames are always ordered from most recent to oldest. So the I<last>
93             function that was called is always I<first>, in this array.
94              
95             =head2 C<number>
96              
97             Some stack traces number their threads. If this particular stack trace
98             has numbered threads, then this is an integer representing the number of
99             the thread. If this stack trace doesn't have numbered threads, then
100             this is C<undef>.
101              
102             =head2 C<description>
103              
104             Some stack traces give their threads descriptions--some more information
105             about the thread--sometimes including a unique identifier. If this
106             stack trace has thread descriptions, then this is a string representing
107             the description of the thread. If this stack trace doesn't have
108             thread descriptions, then this is C<undef>
109              
110             =head2 C<frame_with_crash>
111              
112             In some types of traces, the frame where we crashed may not be the
113             most recent frame. In fact, this thread may not contain the crash
114             at all.
115              
116             This method returns the L<Parse::StackTrace::Frame> where we crashed,
117             or C<undef> if there is no crash in this thread.
118              
119             =head1 ACCESSOR METHODS THAT TAKE ARGUMENTS
120              
121             These are methods that take arguments and return information about
122             this thread.
123              
124             =head2 C<frame_number>
125              
126             Takes a single integer argument. Returns the frame with the specified
127             number. If you are working with a particular type stack trace that
128             doesn't have numbered frames (like Python), this just returns the
129             nth frame from L</frames>.
130              
131             If you are looking for a frame with a particular number, it is more reliable
132             to use this method than to directly dereference L</frames>, because
133             theoretically a trace could have a partial stack, missing some frames,
134             and the 1st item in L</frames> could be frame 4, or something like that.
135             (There are no known ways of producing a stack like that, but it's still
136             theoretically possible.)
137              
138             Frames are numbered from 0 (because that's how GDB does it, and GDB was
139             our first implementation).
140              
141             =head2 C<frames_with_function>
142              
143             Takes a single string argument. Returns all the frames where the named
144             function is called. The search is case-sensitive.
145              
146             When called in array context, this returns an the array of
147             L<Parse::StackTrace::Frame> objects, or an empty array if no frames
148             were found.
149              
150             In scalar context, this returns the first frame found (as a
151             L<Parse::StackTrace::Frame> object), or C<undef> if no frames were found.
152              
153             =head1 SEE ALSO
154              
155             You may also want to read the documentation for the specific implementations
156             of Thread for the various types of traces, which may have more methods than
157             the basic Thread:
158              
159             =over
160              
161             =item L<Parse::StackTrace::Type::GDB::Thread>
162              
163             =item L<Parse::StackTrace::Type::Python::Thread>
164              
165             =back