0
|
1 #-----------------------------------------------------------------------------
|
|
2 # PACKAGE : Bio::Root::Err.pm
|
|
3 # AUTHOR : Steve Chervitz (sac@bioperl.org)
|
|
4 # CREATED : 22 July 1996
|
|
5 # REVISION: $Id: Err.pm,v 1.15 2002/10/22 07:38:37 lapp Exp $
|
|
6 # STATUS : Alpha
|
|
7 #
|
|
8 # For documentation, run this module through pod2html
|
|
9 # (preferably from Perl v5.004 or better).
|
|
10 #
|
|
11 # Copyright (c) 1996-8 Steve Chervitz. All Rights Reserved.
|
|
12 # This module is free software; you can redistribute it and/or
|
|
13 # modify it under the same terms as Perl itself.
|
|
14 # Retain this notice and note any modifications made.
|
|
15 #-----------------------------------------------------------------------------
|
|
16
|
|
17 package Bio::Root::Err;
|
|
18 use strict;
|
|
19
|
|
20 use Bio::Root::Global qw(:devel $CGI);
|
|
21 use Bio::Root::Vector ();
|
|
22 use Bio::Root::Object;# qw(:std);
|
|
23 use Exporter ();
|
|
24
|
|
25 use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
|
|
26 @ISA = qw( Bio::Root::Object Bio::Root::Vector Exporter );
|
|
27 @EXPORT = qw();
|
|
28 @EXPORT_OK = qw( %ERR_FIELDS @ERR_TYPES &format_stack_entry &throw &warning);
|
|
29 %EXPORT_TAGS = (
|
|
30 data => [qw(%ERR_FIELDS @ERR_TYPES)],
|
|
31 std => [qw(&throw &warning)]
|
|
32 );
|
|
33
|
|
34 use vars qw($ID $VERSION);
|
|
35 $ID = 'Bio::Root::Err';
|
|
36 $VERSION = 0.041;
|
|
37
|
|
38 %Bio::Root::Err::ERR_FIELDS = (TYPE=>1, MSG=>1, NOTE=>1, CONTEXT=>1,
|
|
39 TECH=>1, STACK=>1 );
|
|
40
|
|
41 @Bio::Root::Err::ERR_TYPES = qw(WARNING EXCEPTION FATAL);
|
|
42
|
|
43
|
|
44 ## MAIN POD DOCUMENTATION:
|
|
45
|
|
46 =head1 NAME
|
|
47
|
|
48 Bio::Root::Err - Exception class for Perl 5 objects
|
|
49
|
|
50 =head1 SYNOPSIS
|
|
51
|
|
52 =head2 Object Creation
|
|
53
|
|
54 B<Bio::Root::Object.pm> is a wrapper for Bio::Root::Err.pm objects so clients
|
|
55 do not have to create these objects directly. Please see
|
|
56 B<Bio::Root::Object::throw()> as well as L<_initialize>()
|
|
57 for a more complete treatment
|
|
58 of how to create Bio::Root::Err.pm objects.
|
|
59
|
|
60 use Bio::Root::Err;
|
|
61
|
|
62 $err = Bio::Root::Err->new(-MSG =>"Bad data: $data",
|
|
63 -STACK =>[\caller(0), \caller(1), ...],
|
|
64 );
|
|
65
|
|
66
|
|
67 To use the L<throw>() method directly:
|
|
68
|
|
69 use Bio::Root::Err (:std);
|
|
70
|
|
71 throw( $object_ref, 'Error message', 'additional note', 'technical note');
|
|
72
|
|
73 The C<$object_ref> argument should be a reference to a Bio::Root::Object.pm.
|
|
74
|
|
75 See also L<the USAGE section | USAGE>.
|
|
76
|
|
77 =head1 INSTALLATION
|
|
78
|
|
79 This module is included with the central Bioperl distribution:
|
|
80
|
|
81 http://bio.perl.org/Core/Latest
|
|
82 ftp://bio.perl.org/pub/DIST
|
|
83
|
|
84 Follow the installation instructions included in the INSTALL file.
|
|
85
|
|
86 =head1 DESCRIPTION
|
|
87
|
|
88 A Bio::Root::Err.pm object encapsulates data and methods that facilitate
|
|
89 working with errors and exceptional conditions that arise in Perl objects.
|
|
90 There are no biological semantics in this module, as one may suspect from its
|
|
91 location in the Bio:: hierarchy. The location of this module serves to
|
|
92 separate it from the namespaces of other Perl Error modules. It also makes it
|
|
93 convenient for use by Bio:: objects.
|
|
94
|
|
95 The motivation for having an error object is to allow
|
|
96 Perl 5 objects to deal with errors or exceptional conditions that
|
|
97 can arise during their construction or manipulation. For example:
|
|
98
|
|
99 (1) A complex object can break in many ways.
|
|
100 (2) Tracking errors within a set of nested objects can be difficult.
|
|
101 (3) The way an error is reported should be context-sensitive:
|
|
102 a web-user needs different information than does the
|
|
103 software engineer.
|
|
104
|
|
105 Bio::Root::Err.pm, along with B<Bio::Root::Object.pm>, attempt to make such
|
|
106 problems tractable. Please see the L<Bio::Root::Object> documentation for more
|
|
107 about my error handling philosophy.
|
|
108
|
|
109 A B<Bio::Root::Err.pm> object is an example of a Vector-Object: This module
|
|
110 inherits both from B<Bio::Root::Object.pm> and B<Bio::Root::Vector.pm>. This
|
|
111 permits a single Err object to exist within a linked list of Err objects OR
|
|
112 alone. See the L<Bio::Root::Vector> documentation for more about Vector-Objects.
|
|
113
|
|
114 B<The API for this module is not complete since the module is under development.>
|
|
115
|
|
116 =head2 Other Exception Strategies
|
|
117
|
|
118 Exception handling with Perl 5 objects is currently not as evolved as one
|
|
119 would like. The error handling used by B<Bio::Root::Object.pm> and Bio::Root::Err.pm
|
|
120 relies on Perl's built-in error/exception handling with eval/die,
|
|
121 which is not very object-aware. What I've attempted to do with these
|
|
122 modules is to make eval/die more object-savvy, as well as make Perl 5
|
|
123 objects more eval/die-savvy (but the current strategy is basically a hack).
|
|
124
|
|
125 It would be great if Perl could throw an object reference with die().
|
|
126 This would permit more intelligent and easy to write exception handlers.
|
|
127 For now the Err.pm object is reconstructed from the output of L<string>().
|
|
128
|
|
129 There are some other third-party Exception classes such as
|
|
130 Torsten Ekedahl's B<Experimental::Exception.pm> or Ken Steven's Throwable.pm or
|
|
131 Graham Barr's Error.pm (see L<Other Exception Modules>). These modules
|
|
132 attempt to introduce a traditional "try-catch-throw" exception handling mechanism
|
|
133 into Perl. Future version of my modules (and perhaps Perl itself) may utilize one
|
|
134 of these.
|
|
135
|
|
136 =head1 USAGE
|
|
137
|
|
138 A demo script that illustrates working with Bio::Root::Err objects is
|
|
139 examples/root_object/error.pl.
|
|
140
|
|
141
|
|
142 =head1 DEPENDENCIES
|
|
143
|
|
144 Bio::Root::Err.pm inherits from B<Bio::Root::Object.pm> and B<Bio::Root::Vector.pm>.
|
|
145
|
|
146
|
|
147 =head1 FEEDBACK
|
|
148
|
|
149 =head2 Mailing Lists
|
|
150
|
|
151 User feedback is an integral part of the evolution of this and other Bioperl modules.
|
|
152 Send your comments and suggestions preferably to one of the Bioperl mailing lists.
|
|
153 Your participation is much appreciated.
|
|
154
|
|
155 bioperl-l@bioperl.org - General discussion
|
|
156 http://bioperl.org/MailList.shtml - About the mailing lists
|
|
157
|
|
158 =head2 Reporting Bugs
|
|
159
|
|
160 Report bugs to the Bioperl bug tracking system to help us keep track the bugs and
|
|
161 their resolution. Bug reports can be submitted via email or the web:
|
|
162
|
|
163 bioperl-bugs@bio.perl.org
|
|
164 http://bugzilla.bioperl.org/
|
|
165
|
|
166 =head1 AUTHOR Steve Chervitz
|
|
167
|
|
168 Email sac@bioperl.org
|
|
169
|
|
170 See L<the FEEDBACK section | FEEDBACK> section for where to send bug reports and comments.
|
|
171
|
|
172 =head1 VERSION
|
|
173
|
|
174 Bio::Root::Err.pm, 0.041
|
|
175
|
|
176
|
|
177 =head1 SEE ALSO
|
|
178
|
|
179 Bio::Root::Object.pm - Core object
|
|
180 Bio::Root::Vector.pm - Vector object
|
|
181 Bio::Root::Global.pm - Manages global variables/constants
|
|
182
|
|
183 http://bio.perl.org/Projects/modules.html - Online module documentation
|
|
184 http://bio.perl.org/ - Bioperl Project Homepage
|
|
185
|
|
186 =head2 Other Exception Modules
|
|
187
|
|
188 Experimental::Exception.pm - ftp://ftp.matematik.su.se/pub/teke/
|
|
189 Error.pm - http://www.cpan.org/authors/id/GBARR/
|
|
190 Throwable.pm - mailto:kstevens@globeandmail.ca
|
|
191
|
|
192 http://genome-www.stanford.edu/perlOOP/exceptions.html
|
|
193
|
|
194 =head1 ACKNOWLEDGEMENTS
|
|
195
|
|
196 This module was developed under the auspices of the Saccharomyces Genome
|
|
197 Database:
|
|
198 http://genome-www.stanford.edu/Saccharomyces
|
|
199
|
|
200 Other Bioperl developers contributed ideas including Ewan Birney, Ian Korf,
|
|
201 Chris Dagdigian, Georg Fuellen, and Steven Brenner.
|
|
202
|
|
203 =head1 COPYRIGHT
|
|
204
|
|
205 Copyright (c) 1996-8 Steve Chervitz. All Rights Reserved.
|
|
206 This module is free software; you can redistribute it and/or
|
|
207 modify it under the same terms as Perl itself.
|
|
208
|
|
209 =head1 TODO
|
|
210
|
|
211 =over 2
|
|
212
|
|
213 =item * Improve documentation.
|
|
214
|
|
215 =item * Experiment with other Exception modules.
|
|
216
|
|
217 =back
|
|
218
|
|
219 =cut
|
|
220
|
|
221 ## END MAIN POD DOCUMENTATION'
|
|
222
|
|
223 =head1 APPENDIX
|
|
224
|
|
225 Methods beginning with a leading underscore are considered private
|
|
226 and are intended for internal use by this module. They are
|
|
227 B<not> considered part of the public interface and are described here
|
|
228 for documentation purposes only.
|
|
229
|
|
230 =cut
|
|
231
|
|
232
|
|
233 ########################################################
|
|
234 # CONSTRUCTOR #
|
|
235 ########################################################
|
|
236
|
|
237
|
|
238 =head2 _initialize
|
|
239
|
|
240 Usage : n/a; automatically called by Bio::Root::Object::new()
|
|
241 Purpose : Initializes key Bio::Root::Err.pm data.
|
|
242 Returns : String (the -MAKE constructor option.)
|
|
243 Argument : Named parameters passed from new()
|
|
244 : (PARAMETER TAGS CAN BE UPPER OR LOWER CASE).
|
|
245 : -MSG => basic description of the exception.
|
|
246 : -NOTE => additional note to indicate cause of exception
|
|
247 : or provide information about how to fix/report it
|
|
248 : -TECH => addition note with technical information
|
|
249 : of interest to developer.
|
|
250 : -STACK => array reference containing caller() data
|
|
251 : -TYPE => string, one of @Bio::Root::Err::ERR_TYPES
|
|
252 : (default = exception).
|
|
253 : -CONTEXT => array reference
|
|
254 : -OBJ => Err object to be cloned.
|
|
255
|
|
256 See Also : B<Bio::Root::Object::_set_err()>
|
|
257
|
|
258 =cut
|
|
259
|
|
260 #----------------
|
|
261 sub _initialize {
|
|
262 #----------------
|
|
263 my( $self, @param ) = @_;
|
|
264
|
|
265 my $make = $self->Bio::Root::Object::_initialize( @param );
|
|
266
|
|
267 my( $msg, $note, $tech, $stack, $type, $context, $obj) =
|
|
268 $self->_rearrange([qw(MSG NOTE TECH STACK TYPE CONTEXT OBJ)], @param);
|
|
269
|
|
270 ## NOTE: Don't eval {} the construction process for Err objects.
|
|
271
|
|
272 if($make =~ /clone/i) {
|
|
273 $self->_set_clone($obj);
|
|
274 } else {
|
|
275 if(!$self->_build_from_string($msg, $note, $tech)) {
|
|
276 # print "Failed to rebuild: msg = $msg";<STDIN>;
|
|
277 $self->set('msg', $msg );
|
|
278 $self->_set_type( $type );
|
|
279 $self->_set_context($context);
|
|
280 $self->_set_list_data('note', $note );
|
|
281 $self->_set_list_data('tech', $tech );
|
|
282 $self->_set_list_data('stack', $stack );
|
|
283 }
|
|
284 $self->set_display();
|
|
285 }
|
|
286
|
|
287 $DEBUG and do{ print STDERR "---> Initialized Err (${\ref($self)}).\n\n";
|
|
288 # $self->print();
|
|
289 };
|
|
290 $make;
|
|
291 }
|
|
292
|
|
293 ##
|
|
294 ## Destructor: Not needed currently. Perhaps if and when Vector is used by delegation.
|
|
295 ##
|
|
296
|
|
297 #####################################################################################
|
|
298 ## ACCESSORS ##
|
|
299 #####################################################################################
|
|
300
|
|
301
|
|
302
|
|
303 =head2 _set_clone
|
|
304
|
|
305 Usage : n/a; internal method used by _initialize()
|
|
306 Purpose : Copy all Bio::Root::Err.pm data members into a new object reference.
|
|
307 Argument : object ref for object to be cloned.
|
|
308 Comments : Does not cloning the vector since this method is
|
|
309 : typically used to extract a single Err object from its vector.
|
|
310
|
|
311 =cut
|
|
312
|
|
313 #---------------
|
|
314 sub _set_clone {
|
|
315 #---------------
|
|
316 my($self, $obj) = @_;
|
|
317
|
|
318 ref($obj) || throw($self, "Can't clone $ID object: Not an object ref ($obj)");
|
|
319
|
|
320 $self->{'_type'} = $obj->{'_type'};
|
|
321 $self->{'_msg'} = $obj->{'_msg'};
|
|
322 $self->{'_note'} = $obj->{'_note'};
|
|
323 $self->{'_tech'} = $obj->{'_tech'};
|
|
324 $self->{'_stack'} = $obj->{'_stack'};
|
|
325 $self->{'_context'} = $obj->{'_context'};
|
|
326 # $self->clone_vector($obj);
|
|
327 }
|
|
328
|
|
329
|
|
330 =head2 _build_from_string
|
|
331
|
|
332 Usage : n/a; called by _initialize()
|
|
333 Purpose : Re-create an Err.pm object from a string containing Err data.
|
|
334 Returns : boolean, (was the Err.pm object rebuilt?)
|
|
335 Argument : message, note, tech passed from _initialize()
|
|
336 : The message is examined to see if it contains a stringified error.
|
|
337
|
|
338 See Also : L<_initialize>(), L<string>(), L<_has_err>()
|
|
339
|
|
340 =cut
|
|
341
|
|
342 #----------------------
|
|
343 sub _build_from_string {
|
|
344 #----------------------
|
|
345 my ($self, $msg, $note, $tech) = @_;
|
|
346 my @list = split "\n", $msg;
|
|
347 my ($mode,$line);
|
|
348 my $rebuilt = 0;
|
|
349
|
|
350 # print "$ID: Attempting to build from string: $msg";<STDIN>;
|
|
351
|
|
352 MEMBER:
|
|
353 foreach $line (@list) {
|
|
354 if($line =~ /^-+$/) { last MEMBER; }
|
|
355 if($line =~ /^-+ (\w+) -+$/) { $self->{'_type'} = $1; $rebuilt = 1; next MEMBER; }
|
|
356 if($line =~ /^MSG: *(\w.*)/) { my $msg = $1;
|
|
357 if($self->_has_err($msg)) {
|
|
358 die "Duplicate error.";
|
|
359 }
|
|
360 $self->{'_msg'} = $msg;
|
|
361 $mode = 'msg';
|
|
362 next MEMBER; }
|
|
363 if($line =~ /^CONTEXT: *(\w.*)/) { push @{$self->{'_context'}}, $1; $mode = 'context'; next MEMBER; }
|
|
364 if($line =~ /^NOTE: *(\w.*)/) { push @{$self->{'_note'}}, $1; $mode = 'note'; next MEMBER; }
|
|
365 if($line =~ /^TECH: *(\w.*)/) { push @{$self->{'_tech'}}, $1; $mode = 'tech'; next MEMBER; }
|
|
366 if($line =~ /^STACK:/) { $mode = 'stack'; next MEMBER; }
|
|
367 next MEMBER if !$mode;
|
|
368 SWITCH: {
|
|
369 local $_ = $mode;
|
|
370 m/msg/ && do{ $self->{'_msg'} .= "$line\n"; last SWITCH; };
|
|
371 m/note/ && do{ push @{$self->{'_note'}}, $line; last SWITCH; };
|
|
372 m/context/ && do{ push @{$self->{'_context'}}, $line; last SWITCH; };
|
|
373 m/tech/ && do{ push @{$self->{'_tech'}}, $line; last SWITCH; };
|
|
374 m/stack/ && do{ push @{$self->{'_stack'}}, $line; last SWITCH; };
|
|
375 next MEMBER;
|
|
376 }
|
|
377 }
|
|
378 if($rebuilt) {
|
|
379 ## Optionally add additional notes.
|
|
380 $self->_set_list_data('note', $note) if defined $note;
|
|
381 $self->_set_list_data('tech', $tech) if defined $tech;
|
|
382 }
|
|
383
|
|
384 $rebuilt;
|
|
385 }
|
|
386
|
|
387
|
|
388 =head2 _has_err
|
|
389
|
|
390 Usage : n/a; internal method called by _build_from_string()
|
|
391 Purpose : Deterimine if an Err has already been set to prevent duplicate Errs.
|
|
392 Returns : boolean
|
|
393
|
|
394 See Also : L<_build_from_string>()
|
|
395
|
|
396 =cut
|
|
397
|
|
398 #-------------
|
|
399 sub _has_err {
|
|
400 #-------------
|
|
401 my ($self, $msg) = @_;
|
|
402
|
|
403 $msg =~ s/^\s+//;
|
|
404 $msg =~ s/\s+$//;
|
|
405
|
|
406 my $err = $self->first;
|
|
407 my ($existing_msg);
|
|
408 do {
|
|
409 # print "checking err object $self\n";
|
|
410 $existing_msg = $err->msg;
|
|
411 $existing_msg =~ s/^\s+//;
|
|
412 $existing_msg =~ s/\s+$//;
|
|
413 # print " msg: $existing_msg";<STDIN>;
|
|
414 return 1 if $existing_msg eq $msg;
|
|
415
|
|
416 } while($err = $err->next);
|
|
417
|
|
418 0;
|
|
419 }
|
|
420
|
|
421
|
|
422 =head2 _set_type
|
|
423
|
|
424 Usage : n/a; internal method
|
|
425 Purpose : Sets the type of Err (warning, exception, fatal)
|
|
426 : Called by _initialize()
|
|
427 Argument : string
|
|
428
|
|
429 =cut
|
|
430
|
|
431 #----------------
|
|
432 sub _set_type {
|
|
433 #----------------
|
|
434 my( $self, $data ) = @_;
|
|
435 $data ||= 'EXCEPTION';
|
|
436
|
|
437 # printf "\n$ID: Setting type (%s) for err = %s\n", $data, $self->msg;<STDIN>;
|
|
438
|
|
439 my (@type);
|
|
440 if( @type = grep /$data/i, @Bio::Root::Err::ERR_TYPES ) {
|
|
441 $self->{'_type'} = $type[0];
|
|
442 } else {
|
|
443 $self->{'_type'} = 'EXCEPTION';
|
|
444 }
|
|
445
|
|
446 # print "type = $self->{'_type'} for $self";<STDIN>;
|
|
447 }
|
|
448
|
|
449
|
|
450
|
|
451 =head2 _set_list_data
|
|
452
|
|
453 Usage : n/a; internal method used by set().
|
|
454 : $err->_set_list_data( $member, $data);
|
|
455 Purpose : For data members which are anonymous arrays: note, tech, stack,
|
|
456 : adds the given data to the list.
|
|
457 Arguments : $member = any of qw(note tech stack)
|
|
458 : $data = string
|
|
459 Comments : Splits $data on tab. Each item
|
|
460 : of the split is a new entry.
|
|
461 : To clobber the current data (unusual situation), you must first
|
|
462 : call set() with no data then call again with desired data.
|
|
463
|
|
464 =cut
|
|
465
|
|
466 #-------------------
|
|
467 sub _set_list_data {
|
|
468 #-------------------
|
|
469 my( $self, $member, $data ) = @_;
|
|
470
|
|
471 # Sensitive to data member name changes.
|
|
472 $member = "_\l$member";
|
|
473
|
|
474 # $DEBUG && do {printf STDERR "\n$ID: Setting \"%s\" list data (%s)\n", $member, $data;<STDIN>; };
|
|
475
|
|
476 defined $self->{$member} and return $self->_add_list_data( $member, $data );
|
|
477
|
|
478 if( $data ) {
|
|
479 $self->{$member} = [];
|
|
480 if( $member =~ /stack/) {
|
|
481 foreach (@$data) {
|
|
482 push @{ $self->{$member}}, format_stack_entry(@$_);
|
|
483 }
|
|
484 } else {
|
|
485 my @entries = split "\t", $data;
|
|
486 foreach (@entries) {
|
|
487 next if /^$/;
|
|
488 # $DEBUG && do {print STDERR "adding $member: $_";<STDIN>;};
|
|
489 push @{ $self->{$member}}, $_;
|
|
490 }
|
|
491 }
|
|
492 } else {
|
|
493 $self->{$member} = undef;
|
|
494 }
|
|
495 }
|
|
496
|
|
497
|
|
498 =head2 _set_context
|
|
499
|
|
500 Usage : n/a; internal method used by set().
|
|
501 Purpose : Sets the object containment context for the exception.
|
|
502 : (this is the hierarchy of objects in which the
|
|
503 : exception occurred.)
|
|
504
|
|
505 =cut
|
|
506
|
|
507 #------------------
|
|
508 sub _set_context {
|
|
509 #------------------
|
|
510 my($self, $aref) = @_;
|
|
511
|
|
512 eval {
|
|
513 if (!ref $aref) {
|
|
514 # push @{$aref}, sprintf "object %s \"%s\"",ref($self->parent), $self->parent->name;
|
|
515 push @{$aref}, "UNKNOWN CONTEXT";
|
|
516 }
|
|
517 };
|
|
518 if($@) { push @{$aref}, 'undefined object'; }
|
|
519
|
|
520 if($self->type eq 'EXCEPTION') {
|
|
521 $aref->[0] = "Exception thrown by \l$aref->[0]";
|
|
522 } else {
|
|
523 $aref->[0] = "Error in \l$aref->[0]";
|
|
524 }
|
|
525
|
|
526 my $script = ($0 =~ /([\w\/\.]+)/, $1);
|
|
527 push @$aref, "SCRIPT: $script";
|
|
528
|
|
529 $self->{'_context'} = $aref;
|
|
530
|
|
531 # print "$ID: _set_context():\n";
|
|
532 # foreach(@$aref) { print " $_\n"; }
|
|
533 # <STDIN>;
|
|
534 }
|
|
535
|
|
536
|
|
537
|
|
538 =head2 set
|
|
539
|
|
540 Usage : $err->set( $member, $data );
|
|
541 Purpose : General accessor for setting any Err.pm data member.
|
|
542 Example : $err->set('note', 'this is an additional note.');
|
|
543 Returns : n/a
|
|
544 Argument : $member = string, any of qw(msg type note tech stack)
|
|
545 : $data = string
|
|
546 Throws : n/a
|
|
547 Comments : Note, tech, and stack items are appended to any existing
|
|
548 : notes, tech notes, and stack.
|
|
549 : There should be no need to mess with the stack.
|
|
550
|
|
551 =cut
|
|
552
|
|
553 #---------
|
|
554 sub set {
|
|
555 #---------
|
|
556 my( $self, $member, $data ) = @_;
|
|
557
|
|
558 local $_ = "\u$member";
|
|
559 SWITCH: {
|
|
560 /msg/i && do{ $self->{'_msg'} = (defined $data ? $data : 'Unknown error'); last SWITCH; };
|
|
561 /type/i && do{ $self->_set_type( $data ); last SWITCH; };
|
|
562 /note|tech|stack/i && do{ $self->_set_list_data( $member, $data); last SWITCH};
|
|
563 warn "\n*** Invalid or unspecified Err data member: $member\n\n";
|
|
564 }
|
|
565 }
|
|
566
|
|
567
|
|
568 =head2 msg
|
|
569
|
|
570 Usage : $message = $err->msg;
|
|
571 Purpose : Get the main message associated with the exception.
|
|
572 Returns : String
|
|
573 Argument : optional string to be used as a delimiter.
|
|
574
|
|
575 See Also : L<get>(), L<string>()
|
|
576
|
|
577 =cut
|
|
578
|
|
579
|
|
580 #-------
|
|
581 sub msg { my($self,$delimiter) = @_; $self->get('msg',$delimiter); }
|
|
582 #-------
|
|
583
|
|
584
|
|
585 =head2 type
|
|
586
|
|
587 Usage : $type = $err->type;
|
|
588 Purpose : Get the type of Err (warning, exception, fatal)
|
|
589 Returns : String
|
|
590 Argument : optional string to be used as a delimiter.
|
|
591
|
|
592 See Also : L<get>(), L<string>()
|
|
593
|
|
594 =cut
|
|
595
|
|
596 #--------
|
|
597 sub type { my($self,$delimiter) = @_; $self->get('type',$delimiter); }
|
|
598 #--------
|
|
599
|
|
600
|
|
601 =head2 note
|
|
602
|
|
603 Usage : $note = $err->note;
|
|
604 : $note = $err->note('<P>');
|
|
605 Purpose : Get any general note associated with the exception.
|
|
606 Returns : String
|
|
607 Argument : optional string to be used as a delimiter.
|
|
608
|
|
609 See Also : L<get>(), L<string>()
|
|
610
|
|
611 =cut
|
|
612
|
|
613 #---------
|
|
614 sub note { my($self,$delimiter) = @_; $self->get('note',$delimiter); }
|
|
615 #---------
|
|
616
|
|
617
|
|
618 =head2 tech
|
|
619
|
|
620 Usage : $tech = $err->tech;
|
|
621 : $tech = $err->tech('<P>');
|
|
622 Purpose : Get any technical note associate with the exception.
|
|
623 Returns : String
|
|
624 Argument : optional string to be used as a delimiter.
|
|
625
|
|
626 See Also : L<get>(), L<string>()
|
|
627
|
|
628 =cut
|
|
629
|
|
630 #------------
|
|
631 sub tech { my($self,$delimiter) = @_; $self->get('tech',$delimiter); }
|
|
632 #------------
|
|
633
|
|
634
|
|
635
|
|
636 =head2 stack
|
|
637
|
|
638 Usage : $stack = $err->stack;
|
|
639 : $stack = $err->stack('<P>');
|
|
640 Purpose : Get the call stack for the exception.
|
|
641 Returns : String
|
|
642 Argument : optional string to be used as a delimiter.
|
|
643
|
|
644 See Also : L<get>(), L<string>()
|
|
645
|
|
646 =cut
|
|
647
|
|
648 #----------
|
|
649 sub stack { my($self,$delimiter) = @_; $self->get('stack',$delimiter); }
|
|
650 #----------
|
|
651
|
|
652
|
|
653
|
|
654 =head2 context
|
|
655
|
|
656 Usage : $context = $err->context;
|
|
657 : $context = $err->context('<P>');
|
|
658 Purpose : Get the containment context of the object which generated the exception.
|
|
659 Returns : String
|
|
660 Argument : optional string to be used as a delimiter.
|
|
661
|
|
662 See Also : L<get>(), L<string>()
|
|
663
|
|
664 =cut
|
|
665
|
|
666 #------------
|
|
667 sub context { my($self,$delimiter) = @_; $self->get('context',$delimiter); }
|
|
668 #------------
|
|
669
|
|
670
|
|
671
|
|
672 =head2 get
|
|
673
|
|
674 Usage : $err->get($member, $delimiter);
|
|
675 Purpose : Get specific data from the Err.pm object.
|
|
676 Returns : String in scalar context.
|
|
677 : Array in list context.
|
|
678 Argument : $member = any of qw(msg type note tech stack context) or combination.
|
|
679 : $delimiter = optional string to be used as a delimiter
|
|
680 : between member data.
|
|
681
|
|
682 See Also : L<string>(), L<msg>(), L<note>(), L<tech>(), L<type>(), L<context>(), L<stack>()
|
|
683
|
|
684 =cut
|
|
685
|
|
686 #---------
|
|
687 sub get {
|
|
688 #---------
|
|
689 my( $self, $member, $delimiter ) = @_;
|
|
690
|
|
691 my $outer_delim = $delimiter || "\n";
|
|
692 # my $outer_delim = ($CGI ? "\n<P>" : $delimiter); ## Subtle bug here.
|
|
693
|
|
694 my (@out);
|
|
695 local $_ = $member;
|
|
696 SWITCH: {
|
|
697 /type/i && do{ push (@out, $self->{'_type'},$outer_delim) };
|
|
698 # /msg/i && do{ print "getting msg";<STDIN>; push (@out, (defined $self->{'_msg'} ? $self->{'_msg'} : ''),$outer_delim); print "msg: @out<---";<STDIN>; };
|
|
699 /msg/i && do{ push (@out, (defined $self->{'_msg'} ? $self->{'_msg'} : ''),$outer_delim); };
|
|
700 /note/i && do{ push (@out, $self->_get_list_data('note', $delimiter ),$outer_delim) };
|
|
701 /tech/i && do{ push (@out, $self->_get_list_data('tech', $delimiter ),$outer_delim) };
|
|
702 /stack/i && do{ push (@out, $self->_get_list_data('stack', $delimiter ),$outer_delim) };
|
|
703 /context/i && do{ push (@out, $self->_get_list_data('context', $delimiter ),$outer_delim) };
|
|
704
|
|
705 ## CAN'T USE THE FOLLOWING FORM SINCE IT FAILS WHEN $member EQUALS 'msgnote'.
|
|
706 # /note|tech|stack/ && do{ push @out, $self->_get_list_data( $_, $delimiter ); };
|
|
707
|
|
708 last SWITCH;
|
|
709 $self->warn("Invalid or undefined Err data member ($member).");
|
|
710 }
|
|
711 # $DEBUG && do{ print STDERR "OUTER DELIM = $outer_delim \nOUT: \n @out <---";<STDIN>;};
|
|
712 wantarray ? @out : join('',@out);
|
|
713 }
|
|
714
|
|
715
|
|
716
|
|
717 =head2 _get_list_data
|
|
718
|
|
719 Usage : n/a; internal method used by get()
|
|
720 Purpose : Gets data for members which are list refs (note, tech, stack, context)
|
|
721 Returns : Array
|
|
722 Argument : ($member, $delimiter)
|
|
723
|
|
724 See Also : L<get>()
|
|
725
|
|
726 =cut
|
|
727
|
|
728 #-------------------
|
|
729 sub _get_list_data {
|
|
730 #-------------------
|
|
731 my( $self, $member, $delimiter ) = @_;
|
|
732 $delimiter ||= "\t";
|
|
733 # Sensitive to data member name changes.
|
|
734 $member = "_\l$member";
|
|
735 return if !defined $self->{$member};
|
|
736 join( $delimiter, @{$self->{$member}} );
|
|
737 }
|
|
738
|
|
739
|
|
740
|
|
741 =head2 get_all
|
|
742
|
|
743 Usage : (same as get())
|
|
744 Purpose : Get specific data from all errors in an Err.pm object.
|
|
745 Returns : Array in list context.
|
|
746 : String in scalar context.
|
|
747 Argument : (same as get())
|
|
748
|
|
749 See Also : L<get>()
|
|
750
|
|
751 =cut
|
|
752
|
|
753 #------------
|
|
754 sub get_all {
|
|
755 #------------
|
|
756 my( $self, $member, $delimiter ) = @_;
|
|
757
|
|
758 if( $self->size() == 1) {
|
|
759 return $self->get( $member, $delimiter);
|
|
760 } else {
|
|
761 my $err = $self;
|
|
762
|
|
763 ### Return data from multiple errors in a list.
|
|
764 if(wantarray) {
|
|
765 my @out;
|
|
766 do{ push @out, $err->get( $member);
|
|
767 } while($err = $err->prev());
|
|
768 return @out;
|
|
769
|
|
770 } else {
|
|
771 ### Return data from multiple errors in a string with each error's data
|
|
772 ### bracketed by a "Error #n\n" line and two delimiters.
|
|
773 my $out = '';
|
|
774 if($err->size() == 1) {
|
|
775 $out = $err->get( $member, $delimiter);
|
|
776 } else {
|
|
777 do{ #$out .= "Error #${\$err->rank()}$delimiter";
|
|
778 $out .= $err->get( $member, $delimiter);
|
|
779 $out .= $delimiter.$delimiter;
|
|
780 } while($err = $err->prev());
|
|
781 }
|
|
782 return $out;
|
|
783 }
|
|
784 }
|
|
785 }
|
|
786
|
|
787 #####################################################################################
|
|
788 ## INSTANCE METHODS ##
|
|
789 #####################################################################################
|
|
790
|
|
791
|
|
792 =head2 _add_note
|
|
793
|
|
794 Usage : n/a; internal method called by _add_list_data()
|
|
795 Purpose : adds a new note.
|
|
796
|
|
797 See Also : L<_add_list_data>()
|
|
798
|
|
799 =cut
|
|
800
|
|
801 #---------------
|
|
802 sub _add_note {
|
|
803 #---------------
|
|
804 my( $self, $data ) = @_;
|
|
805
|
|
806 if( defined $self->{'_note'} ) {
|
|
807 push @{ $self->{'_note'}}, $data;
|
|
808 } else {
|
|
809 $self->_set_list_data('note', $data );
|
|
810 }
|
|
811 }
|
|
812
|
|
813 #----------------------------------------------------------------------
|
|
814 =head2 _add_tech()
|
|
815
|
|
816 Usage : n/a; internal method called by _add_list_data()
|
|
817 Purpose : adds a new technical note.
|
|
818
|
|
819 See Also : L<_add_list_data>()
|
|
820
|
|
821 =cut
|
|
822
|
|
823 #-------------
|
|
824 sub _add_tech {
|
|
825 #-------------
|
|
826 my( $self, $data ) = @_;
|
|
827
|
|
828 if( defined $self->{'_tech'} ) {
|
|
829 push @{ $self->{'_tech'}}, $data;
|
|
830 } else {
|
|
831 $self->_set_list_data('Tech', $data );
|
|
832 }
|
|
833 }
|
|
834
|
|
835
|
|
836 =head2 _add_list_data
|
|
837
|
|
838 Usage : n/a; called by _set_list_data()
|
|
839 Purpose : adds a new note or tech note.
|
|
840
|
|
841 See Also : L<_set_list_data>()
|
|
842
|
|
843 =cut
|
|
844
|
|
845 #--------------------
|
|
846 sub _add_list_data {
|
|
847 #--------------------
|
|
848 my( $self, $member, $data ) = @_;
|
|
849
|
|
850 local $_ = $member;
|
|
851 SWITCH: {
|
|
852 /note/i && do{ $self->_add_note( $data ); };
|
|
853 /tech/i && do{ $self->_add_tech( $data ); };
|
|
854 }
|
|
855 }
|
|
856
|
|
857
|
|
858
|
|
859 =head2 print
|
|
860
|
|
861 Usage : $err->print;
|
|
862 Purpose : Prints Err data to STDOUT or a FileHandle.
|
|
863 Returns : Call to print
|
|
864 Argument : Named parameters for string()
|
|
865 Comments : Uses string() to get data.
|
|
866
|
|
867 See Also : L<string>()
|
|
868
|
|
869 =cut
|
|
870
|
|
871 #-----------
|
|
872 sub print {
|
|
873 #-----------
|
|
874 my( $self, %param ) = @_;
|
|
875 # my $OUT = $self->parent->fh();
|
|
876 # print $OUT $self->string(%param);
|
|
877 print $self->string(%param);
|
|
878 }
|
|
879
|
|
880
|
|
881 =head2 string
|
|
882
|
|
883 Usage : $err->string( %named_parameters);
|
|
884 Purpose : Stringify the data contained in the Err.pm object.
|
|
885 Example : print STDERR $err->string;
|
|
886 Returns : String
|
|
887 Argument : Named parameters (optional) passed to
|
|
888 : Bio::Root::IOManager::set_display().
|
|
889
|
|
890 See Also : L<print>(), L<_build_from_string>(), B<Bio::Root::IOManager::set_display()>
|
|
891
|
|
892 =cut
|
|
893
|
|
894 #-----------
|
|
895 sub string {
|
|
896 #-----------
|
|
897 my( $self, @param ) = @_;
|
|
898
|
|
899 my %param = @param;
|
|
900 $self->set_display( @param );
|
|
901 my $show = $self->show;
|
|
902 my $out = $param{-BEEP} ? "\a" : '';
|
|
903
|
|
904 my $err = $param{-CURRENT} ? $self->last : $self->first;
|
|
905
|
|
906 # my $err1 = $err;
|
|
907 # my $errL = $self->last;
|
|
908 # print "\n\nERR 1: ${\$err1->msg}";
|
|
909 # print "\nERR L: ${\$errL->msg}";<STDIN>;
|
|
910
|
|
911 my $numerate = $err->size() >1;
|
|
912 my $count = 0;
|
|
913 my ($title);
|
|
914 my $hasnote = defined $self->{'_note'};
|
|
915 my $hastech = defined $self->{'_tech'};
|
|
916
|
|
917 while (ref $err) {
|
|
918 $count++;
|
|
919 # $out .= sprintf "\nERROR #%d:", $count;
|
|
920
|
|
921 if(not $title = $err->{'_type'}) {
|
|
922 $err = $err->next();
|
|
923 next;
|
|
924 }
|
|
925 if( $numerate) {
|
|
926 ## The rank data is a bit screwy at present.
|
|
927 $out .= sprintf "\n%s %s %s\n", '-'x 20, $title,'-'x 20;
|
|
928 } else {
|
|
929 $out .= sprintf "\n%s %s %s\n", '-'x20, $title,'-'x20;
|
|
930 }
|
|
931 $show =~ /msg|default/i and $out .= "MSG: " . $err->msg("\n");
|
|
932 $show =~ /note|default/i and $hasnote and $out .= "NOTE: ".$err->note("\n");
|
|
933 $show =~ /tech|default/i and $hastech and $out .= "TECH: ".$err->tech("\n");
|
|
934 $show =~ /context|default/i and $out .= "CONTEXT: ".$err->context("\n");
|
|
935 $show =~ /stack|default/i and $out .= "STACK: \n".$err->stack("\n");
|
|
936 $out .= sprintf "%s%s%s\n",'-'x 20, '-'x (length($title)+2), '-'x 20;
|
|
937
|
|
938 # print "$ID: string: cumulative err:\n$out\n";<STDIN>;
|
|
939
|
|
940 $err = $err->next();
|
|
941 }
|
|
942
|
|
943 $out;
|
|
944 }
|
|
945
|
|
946
|
|
947
|
|
948 =head2 is_fatal
|
|
949
|
|
950 Usage : $err->is_fatal;
|
|
951 Purpose : Determine if the error is of type 'FATAL'
|
|
952 Returns : Boolean
|
|
953 Status : Experimental, Deprecated
|
|
954
|
|
955 =cut
|
|
956
|
|
957 #--------------
|
|
958 sub is_fatal { my $self = shift; $self->{'_type'} eq 'FATAL'; }
|
|
959 #--------------
|
|
960
|
|
961 #####################################################################################
|
|
962 ## CLASS METHODS ##
|
|
963 #####################################################################################
|
|
964
|
|
965
|
|
966 =head2 throw
|
|
967
|
|
968 Usage : throw($object, [message], [note], [technical note]);
|
|
969 : This method is exported.
|
|
970 Purpose : Class method version of Bio::Root::Object::throw().
|
|
971 Returns : die()s with the contents of the Err object in a string.
|
|
972 : If the global strictness is less than -1, die is not called and
|
|
973 : the error is printed to STDERR.
|
|
974 Argument : [0] = object throwing the error.
|
|
975 : [1] = optional message about the error.
|
|
976 : [2] = optional note about the error.
|
|
977 : [3] = optional technical note about the error.
|
|
978 Comments : The glogal verbosity level is not used. For verbosity-sensitive
|
|
979 : behavior, use Bio::Root::Object::throw().
|
|
980 Status : Experimental
|
|
981 : This method is an alternative to Bio::Root::Object::throw()
|
|
982 : and is not as well developed or documented as that method.
|
|
983
|
|
984 See Also : L<warning>(), B<Bio::Root::Object::throw()> B<Bio::Root::Global::strictness>()
|
|
985
|
|
986 =cut
|
|
987
|
|
988 #----------
|
|
989 sub throw {
|
|
990 #----------
|
|
991 my($obj, @param) = @_;
|
|
992
|
|
993 # print "Throwing exception for object ${\ref $self} \"${\$self->name}\"\n";
|
|
994 my $err = new Bio::Root::Err(
|
|
995 -MSG =>$param[0],
|
|
996 -NOTE =>$param[1],
|
|
997 -TECH =>$param[2],
|
|
998 -STACK =>scalar(Bio::Root::Object::stack_trace($obj,2)),
|
|
999 -CONTEXT =>Bio::Root::Object::containment($obj),
|
|
1000 -TYPE =>'EXCEPTION',
|
|
1001 # -PARENT =>$obj,
|
|
1002 );
|
|
1003
|
|
1004 if(strictness() < -1) {
|
|
1005 print STDERR $err->string(-BEEP=>1) unless verbosity() < 0;
|
|
1006 } else {
|
|
1007 die $err->string;
|
|
1008 }
|
|
1009
|
|
1010 0;
|
|
1011 }
|
|
1012
|
|
1013
|
|
1014 =head2 warning
|
|
1015
|
|
1016 Usage : warning($object, [message], [note], [technical note]);
|
|
1017 : This method is exported.
|
|
1018 Purpose : Class method version of Bio::Root::Object::warn().
|
|
1019 Returns : Prints the contents of the error to STDERR and returns false (0).
|
|
1020 : If the global strictness() is > 1, warn() calls are converted
|
|
1021 : into throw() calls.
|
|
1022 Argument : [0] = object producing the warning.
|
|
1023 : [1] = optional message about the error.
|
|
1024 : [2] = optional note about the error.
|
|
1025 : [3] = optional technical note about the error.
|
|
1026 :
|
|
1027 Comments : The glogal verbosity level is not used. For verbosity-sensitive
|
|
1028 : behavior, use Bio::Root::Object::warn().
|
|
1029 Status : Experimental
|
|
1030 : This method is an alternative to Bio::Root::Object::warn()
|
|
1031 : and is not as well developed or documented as that method.
|
|
1032
|
|
1033 See Also : L<throw>, B<Bio::Root::Object::warn()>, B<Bio::Root::Global::strictness()>
|
|
1034
|
|
1035 =cut
|
|
1036
|
|
1037 #-----------
|
|
1038 sub warning {
|
|
1039 #-----------
|
|
1040 my($obj, @param) = @_;
|
|
1041
|
|
1042 # print "Throwing exception for object ${\ref $self} \"${\$self->name}\"\n";
|
|
1043 my $err = new Bio::Root::Err(
|
|
1044 -MSG =>$param[0],
|
|
1045 -NOTE =>$param[1],
|
|
1046 -TECH =>$param[2],
|
|
1047 -STACK =>scalar(Bio::Root::Object::stack_trace($obj,2)),
|
|
1048 -CONTEXT =>Bio::Root::Object::containment($obj),
|
|
1049 -TYPE =>'WARNING',
|
|
1050 # -PARENT =>$obj,
|
|
1051 );
|
|
1052
|
|
1053 if(strictness() > 1) {
|
|
1054 die $err->string;
|
|
1055
|
|
1056 } else {
|
|
1057 print STDERR $err->string(-BEEP=>1) unless $DONT_WARN;
|
|
1058 }
|
|
1059
|
|
1060 0;
|
|
1061 }
|
|
1062
|
|
1063
|
|
1064 =head2 format_stack_entry
|
|
1065
|
|
1066 Usage : &format_stack_entry(<class>,<file>,<line>,<class_method>,<has_args>,<wantarray>)
|
|
1067 : This function is exported.
|
|
1068 Purpose : Creates a single stack entry given a caller() list.
|
|
1069 Argument : List of scalars (output of the caller() method).
|
|
1070 Returns : String = class_method($line)
|
|
1071 : e.g., Bio::Root::Object::name(1234)
|
|
1072
|
|
1073 =cut
|
|
1074
|
|
1075 #------------------------
|
|
1076 sub format_stack_entry {
|
|
1077 #------------------------
|
|
1078 my( $class, $file, $line, $classmethod, $hasargs, $wantarray) = @_;
|
|
1079
|
|
1080 # if($DEBUG) {
|
|
1081 # print STDERR "format_stack_entry data:\n";
|
|
1082 # foreach(@_) {print STDERR "$_\n"; } <STDIN>;
|
|
1083 # }
|
|
1084
|
|
1085 $classmethod ||= 'unknown class/method';
|
|
1086 $line ||= 'unknown line';
|
|
1087 return "$classmethod($line)";
|
|
1088 }
|
|
1089
|
|
1090 1;
|
|
1091 __END__
|
|
1092
|
|
1093 #####################################################################################
|
|
1094 # END OF CLASS #
|
|
1095 #####################################################################################
|
|
1096
|
|
1097 =head1 FOR DEVELOPERS ONLY
|
|
1098
|
|
1099 =head2 Data Members
|
|
1100
|
|
1101 Information about the various data members of this module is provided for those
|
|
1102 wishing to modify or understand the code. Two things to bear in mind:
|
|
1103
|
|
1104 =over 4
|
|
1105
|
|
1106 =item 1 Do NOT rely on these in any code outside of this module.
|
|
1107
|
|
1108 All data members are prefixed with an underscore to signify that they are private.
|
|
1109 Always use accessor methods. If the accessor doesn't exist or is inadequate,
|
|
1110 create or modify an accessor (and let me know, too!).
|
|
1111
|
|
1112 =item 2 This documentation may be incomplete and out of date.
|
|
1113
|
|
1114 It is easy for this documentation to become obsolete as this module is still evolving.
|
|
1115 Always double check this info and search for members not described here.
|
|
1116
|
|
1117 =back
|
|
1118
|
|
1119 An instance of Bio::Root::Err.pm is a blessed reference to a hash containing
|
|
1120 all or some of the following fields:
|
|
1121
|
|
1122 FIELD VALUE
|
|
1123 ------------------------------------------------------------------------
|
|
1124 _type fatal | warning | exception (one of @Bio::Root::Err::ERR_TYPES).
|
|
1125
|
|
1126 _msg Terse description: Main cause of error.
|
|
1127
|
|
1128 _note List reference. Verbose description: probable cause & troubleshooting for user.
|
|
1129
|
|
1130 _tech List reference. Technical notes of interest to programmer.
|
|
1131
|
|
1132 _stack List reference. Stack trace: list of "class::method(line number)" strings.
|
|
1133
|
|
1134
|
|
1135
|
|
1136 =cut
|
|
1137
|
|
1138 1;
|