File Coverage

blib/lib/Exception/Class/Base.pm
Criterion Covered Total %
statement 114 123 92.6
branch 28 40 70.0
condition 7 17 41.1
subroutine 26 28 92.8
pod 10 13 76.9
total 185 221 83.7


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