File Coverage

blib/lib/Bio/NEXUS/Util/Exceptions.pm
Criterion Covered Total %
statement 197 209 94.2
branch 32 52 61.5
condition n/a
subroutine 46 49 93.8
pod 5 5 100.0
total 280 315 88.8


line stmt bran cond sub pod time code
1             ######################################################
2             # Exceptions.pm - Exception classes for Bio::NEXUS.
3             ######################################################
4             # original version thanks to Rutger
5             #
6             # $Id: Exceptions.pm,v 1.5 2012/02/07 21:49:27 astoltzfus Exp $
7             #
8             package Bio::NEXUS::Util::StackTrace;
9 34     34   180 use strict;
  34         84  
  34         28586  
10              
11             sub new {
12 13     13   22 my $class = shift;
13 13         24 my $self = [];
14 13         21 my $i = 0;
15 13         17 my $j = 0;
16             package DB; # to get @_ stack from previous frames, see perldoc -f caller
17 13         148 while( my @frame = caller($i) ) {
18 108         170 my $package = $frame[0];
19 108 100       190 if ( not Bio::NEXUS::Util::StackTrace::_skip_me( $package ) ) {
20 77         168 my @args = @DB::args;
21 77         328 $self->[$j++] = [ @frame, @args ];
22             }
23 108         712 $i++;
24             }
25             package Bio::NEXUS::Util::StackTrace;
26 13         22 shift @$self; # to remove "throw" frame
27 13         562 return bless $self, $class;
28             }
29              
30             sub _skip_me {
31 108     108   113 my $class = shift;
32 108         128 my $skip = 0;
33 108 100       533 if ( UNIVERSAL::isa( $class, 'Bio::NEXUS::Util::Exceptions') ) {
34 31         34 $skip++;
35             }
36 108 50       526 if ( UNIVERSAL::isa( $class, 'Bio::NEXUS::Util::ExceptionFactory' ) ) {
37 0         0 $skip++;
38             }
39 108         282 return $skip;
40             }
41              
42             # fields in frame:
43             # [
44             # 0 'main',
45             # +1 '/Users/rvosa/Desktop/exceptions.pl',
46             # +2 102,
47             # +3 'Object::this_dies',
48             # 4 1,
49             # 5 undef,
50             # 6 undef,
51             # 7 undef,
52             # 8 2,
53             # 9 'UUUUUUUUUUUU',
54             # +10 bless( {}, 'Object' ),
55             # +11 'very',
56             # +12 'violently'
57             # ],
58              
59             sub as_string {
60 14     14   24 my $self = shift;
61 14         19 my $string = "";
62 14         52 for my $frame ( @$self ) {
63 66         88 my $method = $frame->[3];
64 66         69 my @args;
65 66         76 for my $i ( 10 .. $#{ $frame } ) {
  66         134  
66 260         370 push @args, $frame->[$i];
67             }
68 66         112 my $file = $frame->[1];
69 66         75 my $line = $frame->[2];
70 34     34   236 no warnings 'uninitialized';
  34         61  
  34         17472  
71 66         123 $string .= $method . "(" . join(', ', map { "'$_'" } @args ) . ") called at $file line $line\n";
  260         788  
72             }
73 14         86 return $string;
74             }
75              
76             package Bio::NEXUS::Util::Exceptions;
77             BEGIN {
78 34     34   187 require Exporter;
79 34     34   234 use vars qw($AUTOLOAD @EXPORT_OK @ISA);
  34         75  
  34         9954  
80 34         624 @ISA=qw(Exporter);
81 34         716 @EXPORT_OK=qw(throw);
82             }
83 34     34   170 use strict;
  34         73  
  34         2524  
84 34     34   24239 use overload 'bool' => sub { 1 }, 'fallback' => 1, '""' => \&as_string;
  34     0   15257  
  34         728  
  0         0  
85              
86             sub new {
87 13     13 1 34 my $class = shift;
88 13         51 my %args = @_;
89 13         85 my $self = {
90             'error' => $args{'error'},
91             'description' => $args{'description'},
92             'trace' => Bio::NEXUS::Util::StackTrace->new,
93             'time' => CORE::time(),
94             'pid' => $$,
95             'uid' => $<,
96             'euid' => $>,
97             'gid' => $(,
98             'egid' => $),
99             };
100 13         63 return bless $self, $class;
101             }
102              
103             sub as_string {
104 14     14 1 3812 my $self = shift;
105 14         123 my $error = $self->error;
106 14         495 my $description = $self->description;
107 14         34 my $class = ref $self;
108 14         115 my $trace = join "\n", map { "STACK: $_" } split '\n', $self->trace->as_string;
  69         174  
109 14         1358 return <<"ERROR_HERE_DOC";
110             -------------------------- EXCEPTION ----------------------------
111             Message: $error
112              
113             An exception of type $class
114             was thrown.
115              
116             $description
117              
118             Refer to the Bio::NEXUS::Util::Exceptions documentation for more
119             information.
120             ------------------------- STACK TRACE ---------------------------
121             $trace
122             -----------------------------------------------------------------
123             ERROR_HERE_DOC
124             }
125              
126             sub throw ($$) {
127             # called as static method
128 13 100   13 1 65 if ( scalar @_ == 3 ) {
    50          
129 8         14 my $class = shift;
130 8         45 my $self = $class->new(@_);
131 8         101 die $self;
132             }
133             # called as function, e.g. throw BadArgs => 'msg';
134             elsif ( scalar @_ == 2 ) {
135 5         10 my $type = shift;
136 5         11 my $class = __PACKAGE__ . '::' . $type;
137 5         16 my $self;
138 5         8 eval {
139 5         46 $self = $class->new( 'error' => shift );
140             };
141 5 50       16 if ( $@ ) {
142 0         0 die Bio::NEXUS::Util::Exceptions::API->new( 'error' => "Can't throw errors of type $type: $@" );
143             }
144             else {
145 5         38 die $self;
146             }
147             }
148             }
149              
150             sub rethrow {
151 0     0 1 0 my $self = shift;
152 0         0 die $self;
153             }
154              
155             sub caught {
156 0     0 1 0 my $class = shift;
157 0 0       0 if ( @_ ) {
158 0         0 $class = shift;
159             }
160 0 0       0 if ( $@ ) {
161 0 0       0 if ( UNIVERSAL::isa( $@, $class ) ) {
162 0         0 return $@;
163             }
164             else {
165 0         0 die $@;
166             }
167             }
168             }
169              
170             sub AUTOLOAD {
171 28     28   39 my $self = shift;
172 28         1180 my $field = $AUTOLOAD;
173 28         107 $field =~ s/.*://;
174 28         95 return $self->{$field};
175             }
176              
177             sub _make_exceptions {
178 34     34   468 my $class = shift;
179 34         75 my $root = shift;
180 34         595 my %exceptions = @_;
181 34         224 for my $exception ( keys %exceptions ) {
182 544         1164 my $isa = $exceptions{ $exception }->{'isa'};
183 544 100       1486 my @isa = ref $isa ? @$isa : ( $isa );
184 544         847 my $description = $exceptions{ $exception }->{'description'};
185 544         1664 my $class = <<"EXCEPTION_CLASS";
186             package ${exception};
187             use vars '\@ISA';
188             \@ISA=qw(@isa);
189             my \$desc;
190             sub description {
191             my \$self = shift;
192             if ( \@_ ) {
193             \$desc = shift;
194             }
195             return \$desc;
196             }
197             1;
198             EXCEPTION_CLASS
199 34 100   34   599 eval $class;
  34 50   34   134  
  34 50   34   3410  
  34 50   34   194  
  34 50   34   64  
  34 50   34   4468  
  34 50   34   202  
  34 100   34   62  
  34 50   34   2976  
  34 50   34   256  
  34 100   34   64  
  34 50   34   3047  
  34 100   34   243  
  34 50   34   56  
  34 50   34   2854  
  34 100   34   187  
  34     36   66  
  34     34   3078  
  34     34   179  
  34     34   78  
  34     34   2969  
  34     34   181  
  34     34   62  
  34     35   3977  
  34     34   175  
  34     34   81  
  34     42   3045  
  34     34   181  
  34     36   64  
  34     34   3960  
  34     34   181  
  34     35   95  
  34         8171  
  34         201  
  34         67  
  34         3485  
  34         207  
  34         72  
  34         3153  
  34         196  
  34         63  
  34         3329  
  34         224  
  34         64  
  34         3456  
  34         196  
  34         1904  
  34         7451  
  544         48776  
  36         93  
  36         314  
  34         72  
  36         136  
  34         93  
  34         150  
  34         69  
  34         138  
  34         79  
  34         151  
  34         66  
  34         133  
  34         100  
  34         163  
  34         77  
  34         139  
  34         177  
  34         151  
  34         72  
  34         132  
  34         84  
  34         142  
  34         67  
  34         125  
  34         91  
  34         141  
  34         67  
  34         308  
  35         87  
  35         146  
  34         68  
  35         137  
  34         85  
  34         153  
  34         65  
  34         133  
  34         90  
  34         146  
  34         68  
  34         139  
  42         102  
  42         207  
  34         70  
  42         150  
  34         89  
  34         155  
  34         67  
  34         132  
  36         87  
  36         160  
  34         71  
  36         146  
  34         82  
  34         146  
  34         71  
  34         132  
  34         91  
  34         150  
  34         77  
  34         189  
  35         101  
  35         152  
  34         76  
  35         138  
200 544         19564 $exception->description( $description );
201             }
202            
203             }
204              
205             __PACKAGE__->_make_exceptions(
206             # root classes
207             'Bio::NEXUS::Util::Exceptions',
208             'Bio::NEXUS::Util::Exceptions::Generic' => {
209             'isa' => 'Bio::NEXUS::Util::Exceptions',
210             'description' => "No further details about this type of error are available."
211             },
212            
213             # exceptions on method calls
214             'Bio::NEXUS::Util::Exceptions::API' => {
215             'isa' => 'Bio::NEXUS::Util::Exceptions::Generic',
216             'description' => "No more details about this type of error are available."
217             },
218             'Bio::NEXUS::Util::Exceptions::UnknownMethod' => {
219             'isa' => 'Bio::NEXUS::Util::Exceptions::API',
220             'description' => "This kind of error happens when a non-existent method is called.",
221             },
222             'Bio::NEXUS::Util::Exceptions::NotImplemented' => {
223             'isa' => 'Bio::NEXUS::Util::Exceptions::API',
224             'description' => "This kind of error happens when a non-implemented\n(interface) method is called.",
225             },
226             'Bio::NEXUS::Util::Exceptions::Deprecated' => {
227             'isa' => 'Bio::NEXUS::Util::Exceptions::API',
228             'description' => "This kind of error happens when a deprecated method is called.",
229             },
230              
231             # exceptions on arguments
232             'Bio::NEXUS::Util::Exceptions::BadArgs' => {
233             'isa' => 'Bio::NEXUS::Util::Exceptions::Generic',
234             'description' => "This kind of error happens when bad or incomplete arguments\nare provided.",
235             },
236             'Bio::NEXUS::Util::Exceptions::BadString' => {
237             'isa' => 'Bio::NEXUS::Util::Exceptions::BadArgs',
238             'description' => "This kind of error happens when an unsafe string argument is\nprovided.",
239             },
240             'Bio::NEXUS::Util::Exceptions::OddHash' => {
241             'isa' => 'Bio::NEXUS::Util::Exceptions::BadArgs',
242             'description' => "This kind of error happens when an uneven number\nof arguments (so no key/value pairs) was provided.",
243             },
244             'Bio::NEXUS::Util::Exceptions::ObjectMismatch' => {
245             'isa' => 'Bio::NEXUS::Util::Exceptions::BadArgs',
246             'description' => "This kind of error happens when an invalid object\nargument is provided.",
247             },
248             'Bio::NEXUS::Util::Exceptions::InvalidData' => {
249             'isa' => [
250             'Bio::NEXUS::Util::Exceptions::BadString',
251             'Bio::NEXUS::Util::Exceptions::BadFormat',
252             ],
253             'description' => "This kind of error happens when invalid character data is\nprovided."
254             },
255             'Bio::NEXUS::Util::Exceptions::OutOfBounds' => {
256             'isa' => 'Bio::NEXUS::Util::Exceptions::BadArgs',
257             'description' => "This kind of error happens when an index is outside of its range.",
258             },
259             'Bio::NEXUS::Util::Exceptions::BadNumber' => {
260             'isa' => 'Bio::NEXUS::Util::Exceptions::Generic',
261             'description' => "This kind of error happens when an invalid numerical argument\nis provided.",
262             },
263              
264             # system exceptions
265             'Bio::NEXUS::Util::Exceptions::System' => {
266             'isa' => 'Bio::NEXUS::Util::Exceptions::Generic',
267             'description' => "This kind of error happens when there is a system misconfiguration.",
268             },
269             'Bio::NEXUS::Util::Exceptions::FileError' => {
270             'isa' => 'Bio::NEXUS::Util::Exceptions::System',
271             'description' => "This kind of error happens when a file can not be accessed.",
272             },
273             'Bio::NEXUS::Util::Exceptions::ExtensionError' => {
274             'isa' => [
275             'Bio::NEXUS::Util::Exceptions::System',
276             'Bio::NEXUS::Util::Exceptions::BadFormat',
277             ],
278             'description' => "This kind of error happens when an extension module can not be\nloaded.",
279             },
280             'Bio::NEXUS::Util::Exceptions::BadFormat' => {
281             'isa' => 'Bio::NEXUS::Util::Exceptions::System',
282             'description' => "This kind of error happens when a bad\nparse or unparse format was specified.",
283             },
284              
285             );
286              
287              
288             1;
289             __END__