File Coverage

blib/lib/Devel/StackTrace/Extract.pm
Criterion Covered Total %
statement 18 40 45.0
branch 0 14 0.0
condition n/a
subroutine 6 8 75.0
pod 1 1 100.0
total 25 63 39.6


line stmt bran cond sub pod time code
1             package Devel::StackTrace::Extract;
2 1     1   13946 use base qw(Exporter);
  1         2  
  1         83  
3              
4 1     1   4 use strict;
  1         2  
  1         17  
5 1     1   3 use warnings;
  1         1  
  1         36  
6              
7             our $VERSION = '1.000000';
8              
9 1     1   417 use Devel::StackTrace;
  1         3999  
  1         21  
10 1     1   4 use Devel::StackTrace::Frame;
  1         2  
  1         15  
11 1     1   3 use Scalar::Util qw(blessed);
  1         1  
  1         217  
12              
13             our @EXPORT_OK;
14              
15             sub extract_stack_trace {
16 0     0 1   my $ex = shift;
17              
18             # non objects do not contain stack frames
19 0 0         return undef unless blessed($ex);
20              
21             # anything that does StackTrace::Auto (including anything that does
22             # Throwable::Error) will implement this
23 0 0         return $ex->stack_trace if $ex->can('stack_trace');
24              
25 0 0         if ( $ex->isa('Mojo::Exception') ) {
26              
27             # make sure this is a modern version of Mojo using
28 0 0         return undef unless $ex->can('frames');
29              
30             # it's possible for Mojo exceptions not to have stack frames
31 0           my $frames = $ex->frames;
32 0 0         return undef unless @{ $frames || [] };
  0 0          
33              
34 0           return _build_devel_trace_from_mojo_exception($ex);
35             }
36              
37             # Exception::Class and Moose::Exception and friends use 'trace'. Note the
38             # importance of putting this *after* the Mojo::Exception check, as that
39             # module implements a 'trace' method that *sets* the current stack trace,
40             # not returns the current stack trace
41 0 0         return $ex->trace if $ex->can('trace');
42              
43             # dunno how to get the stack trace, give up and return undef
44 0           return undef;
45             }
46             push @EXPORT_OK, 'extract_stack_trace';
47              
48             sub _build_devel_trace_from_mojo_exception {
49 0     0     my $ex = shift;
50              
51 0           my $message = $ex->message;
52 0           my $frames = $ex->frames;
53              
54 0           my $trace = Devel::StackTrace->new(
55             message => $message,
56             skip_frames => ~0 - 1, # skip all frames, we're doing this by hand!
57             );
58              
59             # convert the Mojo::Exception frames into Devel::StackTrace::Frame frames
60 0           my @new_frames;
61 0           foreach my $old_frame ( @{$frames} ) {
  0            
62              
63             # right now this is a somewhat undocumented interface to
64             # Devel::StackFrame::Frame, but Dave Rolsky is at least aware
65             # that this code does this.
66 0           push @new_frames, Devel::StackTrace::Frame->new(
67             $old_frame,
68             [], # we don't know the parameters that were passed, ooops
69              
70             # these are all the default from Devel::StackTrace
71             undef, # respect_overload,
72             undef, # max_arg_length
73             $message, # message
74             undef, # indent
75             );
76             }
77              
78             # work around of bug in Devel::StackTrace 2.00 where it still tries to
79             # convert the raw frames into frames if you manually set them unless you've
80             # read the frames once
81 0           $trace->frames;
82              
83 0           $trace->frames(@new_frames);
84 0           return $trace;
85             }
86              
87             1;
88              
89             # ABSTRACT: Extract a stack trace from an exception object
90              
91             __END__