File Coverage

blib/lib/Exception/Class/Base.pm
Criterion Covered Total %
statement 115 124 92.7
branch 30 42 71.4
condition 7 17 41.1
subroutine 26 28 92.8
pod 10 13 76.9
total 188 224 83.9


line stmt bran cond sub pod time code
1             package Exception::Class::Base;
2              
3 6     6   64866 use strict;
  6         20  
  6         154  
4 6     6   24 use warnings;
  6         11  
  6         232  
5              
6             our $VERSION = '1.45';
7              
8 6     6   2534 use Class::Data::Inheritable 0.02;
  6         1690  
  6         155  
9 6     6   2487 use Devel::StackTrace 2.00;
  6         26987  
  6         181  
10 6     6   41 use Scalar::Util qw( blessed );
  6         9  
  6         277  
11              
12 6     6   31 use base qw(Class::Data::Inheritable);
  6         10  
  6         1354  
13              
14 0         0 BEGIN {
15 6     6   55 __PACKAGE__->mk_classdata('Trace');
16 6         175 __PACKAGE__->mk_classdata('UnsafeRefCapture');
17              
18 6         132 __PACKAGE__->mk_classdata('NoContextInfo');
19 6         145 __PACKAGE__->NoContextInfo(0);
20              
21 6         63 __PACKAGE__->mk_classdata('RespectOverload');
22 6         115 __PACKAGE__->RespectOverload(0);
23              
24 6         58 __PACKAGE__->mk_classdata('MaxArgLength');
25 6         124 __PACKAGE__->MaxArgLength(0);
26              
27             sub NoRefs {
28 1     1 0 478 my $self = shift;
29 1 50       4 if (@_) {
30 1         3 my $val = shift;
31 1         5 return $self->UnsafeRefCapture( !$val );
32             }
33             else {
34 0         0 return $self->UnsafeRefCapture;
35             }
36             }
37              
38 40     40 1 77 sub Fields { () }
39             }
40              
41             use overload
42              
43             # an exception is always true
44 6     6   340 bool => sub {1}, '""' => 'as_string', fallback => 1;
  6     7   10  
  6         33  
  7         568  
45              
46             # Create accessor routines
47             BEGIN {
48 6     6   23 my @fields = qw( message pid uid euid gid egid time trace );
49              
50 6         12 foreach my $f (@fields) {
51 48     50   133 my $sub = sub { my $s = shift; return $s->{$f}; };
  50         2247  
  50         235  
52              
53             ## no critic (TestingAndDebugging::ProhibitNoStrict)
54 6     6   861 no strict 'refs';
  6         12  
  6         879  
55 48         62 *{$f} = $sub;
  48         174  
56             }
57 6         15 *error = \&message;
58              
59 6         20 my %trace_fields = (
60             package => 'package',
61             file => 'filename',
62             line => 'line',
63             );
64              
65 6         31 while ( my ( $f, $m ) = each %trace_fields ) {
66             my $sub = sub {
67 4     4   952 my $s = shift;
68 4 50       13 return $s->{$f} if exists $s->{$f};
69              
70 4         13 my $frame = $s->trace->frame(0);
71              
72 4 50       485 return $s->{$f} = $frame ? $frame->$m : undef;
73 18         42 };
74              
75             ## no critic (TestingAndDebugging::ProhibitNoStrict)
76 6     6   38 no strict 'refs';
  6         9  
  6         200  
77 18         26 *{$f} = $sub;
  18         5192  
78             }
79             }
80              
81 0     0 0 0 sub Classes { Exception::Class::Classes() }
82              
83             sub throw {
84 39     39 1 9707 my $proto = shift;
85              
86 39 50       94 $proto->rethrow if ref $proto;
87              
88 39         113 die $proto->new(@_);
89             }
90              
91             sub rethrow {
92 0     0 1 0 my $self = shift;
93              
94 0         0 die $self;
95             }
96              
97             sub new {
98 39     39 1 51 my $proto = shift;
99 39   33     130 my $class = ref $proto || $proto;
100              
101 39         75 my $self = bless {}, $class;
102              
103 39         121 $self->_initialize(@_);
104              
105 39         170 return $self;
106             }
107              
108             sub _initialize {
109 39     39   49 my $self = shift;
110 39 100       120 my %p = @_ == 1 ? ( error => $_[0] ) : @_;
111              
112 39   100     864 $self->{message} = $p{message} || $p{error} || q{};
113              
114 39 100       82 $self->{show_trace} = $p{show_trace} if exists $p{show_trace};
115              
116 39 100       113 if ( $self->NoContextInfo ) {
117 1         8 $self->{show_trace} = 0;
118 1         3 $self->{package} = $self->{file} = $self->{line} = undef;
119             }
120             else {
121             # CORE::time is important to fix an error with some versions of
122             # Perl
123 38         297 $self->{time} = CORE::time();
124 38         89 $self->{pid} = $$;
125 38         231 $self->{uid} = $<;
126 38         224 $self->{euid} = $>;
127 38         293 $self->{gid} = $(;
128 38         258 $self->{egid} = $);
129              
130 38         115 my @ignore_class = (__PACKAGE__);
131 38         60 my @ignore_package = 'Exception::Class';
132              
133 38 100       105 if ( my $i = delete $p{ignore_class} ) {
134 1 50       5 push @ignore_class, ( ref($i) eq 'ARRAY' ? @$i : $i );
135             }
136              
137 38 100       66 if ( my $i = delete $p{ignore_package} ) {
138 2 50       6 push @ignore_package, ( ref($i) eq 'ARRAY' ? @$i : $i );
139             }
140              
141             $self->{trace} = Devel::StackTrace->new(
142             ignore_class => \@ignore_class,
143             ignore_package => \@ignore_package,
144             unsafe_ref_capture => $self->UnsafeRefCapture,
145             respect_overload => $self->RespectOverload,
146             max_arg_length => $self->MaxArgLength,
147 38 100       158 map { $p{$_} ? ( $_ => delete $p{$_} ) : () } qw(
  114         1164  
148             frame_filter
149             filter_frames_early
150             skip_frames
151             ),
152             );
153             }
154              
155 39         11380 my %fields = map { $_ => 1 } $self->Fields;
  9         22  
156 39         131 while ( my ( $key, $value ) = each %p ) {
157 39 100       248 next if $key =~ /^(?:error|message|show_trace)$/;
158              
159 5 50       13 if ( $fields{$key} ) {
160 5         16 $self->{$key} = $value;
161             }
162             else {
163 0         0 Exception::Class::Base->throw(
164             error => "unknown field $key passed to constructor for class "
165             . ref $self );
166             }
167             }
168             }
169              
170             sub context_hash {
171 1     1 1 2 my $self = shift;
172              
173             return {
174             time => $self->{time},
175             pid => $self->{pid},
176             uid => $self->{uid},
177             euid => $self->{euid},
178             gid => $self->{gid},
179             egid => $self->{egid},
180 1         10 };
181             }
182              
183             sub field_hash {
184 1     1 1 3 my $self = shift;
185              
186 1         2 my $hash = {};
187              
188 1         30 for my $field ( $self->Fields ) {
189 2         34 $hash->{$field} = $self->$field;
190             }
191              
192 1         6 return $hash;
193             }
194              
195             sub description {
196 2     2 1 314 return 'Generic exception';
197             }
198              
199             sub show_trace {
200 9     9 1 11 my $self = shift;
201              
202 9 50       31 return 0 unless $self->{trace};
203              
204 9 50       3167 if (@_) {
205 0         0 $self->{show_trace} = shift;
206             }
207              
208 9 100       34 return exists $self->{show_trace} ? $self->{show_trace} : $self->Trace;
209             }
210              
211             sub as_string {
212 9     9 1 103 my $self = shift;
213              
214 9         23 my $str = $self->full_message;
215 9 50 33     40 unless ( defined $str && length $str ) {
216 0         0 my $desc = $self->description;
217 0 0 0     0 $str = defined $desc
218             && length $desc ? "[$desc]" : '[Generic exception]';
219             }
220              
221 9 100       23 $str .= "\n\n" . $self->trace->as_string
222             if $self->show_trace;
223              
224 9         633 return $str;
225             }
226              
227 8     8 1 19 sub full_message { $_[0]->message }
228              
229             #
230             # The %seen bit protects against circular inheritance.
231             #
232             ## no critic (BuiltinFunctions::ProhibitStringyEval, ErrorHandling::RequireCheckingReturnValueOfEval)
233             eval <<'EOF' if $] == 5.006;
234             sub isa {
235             my ( $inheritor, $base ) = @_;
236             $inheritor = ref($inheritor) if ref($inheritor);
237              
238             my %seen;
239              
240             no strict 'refs';
241             my @parents = ( $inheritor, @{"$inheritor\::ISA"} );
242             while ( my $class = shift @parents ) {
243             return 1 if $class eq $base;
244              
245             push @parents, grep { !$seen{$_}++ } @{"$class\::ISA"};
246             }
247             return 0;
248             }
249             EOF
250              
251             sub caught {
252 3     3 0 640 my $class = shift;
253              
254 3         6 my $e = $@;
255              
256 3 100 33     29 return unless defined $e && blessed($e) && $e->isa($class);
      66        
257 2         7 return $e;
258             }
259              
260             1;
261              
262             # ABSTRACT: A base class for exception objects
263              
264             __END__