3 # Copyright (c) 1997-8 Graham Barr <gbarr@ti.com>. All rights reserved.
4 # This program is free software; you can redistribute it and/or
5 # modify it under the same terms as Perl itself.
7 # Based on my original Error.pm, and Exceptions.pm by Peter Seibel
8 # <peter@weblogic.com> and adapted by Jesse Glick <jglick@sig.bsh.com>.
10 # but modified ***significantly***
15 use vars
qw($VERSION);
23 'bool' => sub { return 1; },
27 $Error::Depth = 0; # Depth to pass to caller()
28 $Error::Debug = 0; # Generate verbose stack traces
29 @Error::STACK = (); # Clause stack for try
30 $Error::THROWN = undef; # last error thrown, a workaround until die $ref works
32 my $LAST; # Last error created
33 my %ERROR; # Last error associated with package
35 sub throw_Error_Simple
38 return Error::Simple->new($args->{'text'});
41 $Error::ObjectifyCallback = \&throw_Error_Simple;
44 # Exported subs are defined in Error::subs
50 local $Exporter::ExportLevel = $Exporter::ExportLevel + 1;
51 Error::subs->import(@_);
54 # I really want to use last for the name of this method, but it is a keyword
55 # which prevent the syntax last Error
60 return $LAST unless @_;
63 return exists $ERROR{$pkg} ? $ERROR{$pkg} : undef
68 if($obj->isa('HASH')) {
69 $err = $obj->{'__Error__'}
70 if exists $obj->{'__Error__'};
72 elsif($obj->isa('GLOB')) {
73 $err = ${*$obj}{'__Error__'}
74 if exists ${*$obj}{'__Error__'};
89 return unless ref($pkg);
91 undef $ERROR{$pkg} if defined $ERROR{$pkg};
94 # Return as much information as possible about where the error
95 # happened. The -stacktrace element only exists if $Error::DEBUG
96 # was set when the error was created
101 return $self->{'-stacktrace'}
102 if exists $self->{'-stacktrace'};
104 my $text = exists $self->{'-text'} ? $self->{'-text'} : "Died";
106 $text .= sprintf(" at %s line %d.\n", $self->file, $self->line)
107 unless($text =~ /\n$/s);
112 # Allow error propagation, ie
114 # $ber->encode(...) or
115 # return Error->prior($ber)->associate($ldap);
121 return unless ref($obj);
123 if($obj->isa('HASH')) {
124 $obj->{'__Error__'} = $err;
126 elsif($obj->isa('GLOB')) {
127 ${*$obj}{'__Error__'} = $err;
130 $ERROR{ ref($obj) } = $err;
137 my($pkg,$file,$line) = caller($Error::Depth);
146 $err->associate($err->{'-object'})
147 if(exists $err->{'-object'});
149 # To always create a stacktrace would be very inefficient, so
150 # we only do it if $Error::Debug is set
154 local $Carp::CarpLevel = $Error::Depth;
155 my $text = defined($err->{'-text'}) ? $err->{'-text'} : "Error";
156 my $trace = Carp::longmess($text);
157 # Remove try calls from the trace
158 $trace =~ s/(\n\s+\S+__ANON__[^\n]+)?\n\s+eval[^\n]+\n\s+Error::subs::try[^\n]+(?=\n)//sog;
159 $trace =~ s/(\n\s+\S+__ANON__[^\n]+)?\n\s+eval[^\n]+\n\s+Error::subs::run_clauses[^\n]+\n\s+Error::subs::try[^\n]+(?=\n)//sog;
160 $err->{'-stacktrace'} = $trace
163 $@ = $LAST = $ERROR{$pkg} = $err;
166 # Throw an error. this contains some very gory code.
170 local $Error::Depth = $Error::Depth + 1;
172 # if we are not rethrow-ing then create the object to throw
173 $self = $self->new(@_) unless ref($self);
175 die $Error::THROWN = $self;
178 # syntactic sugar for
180 # die with Error( ... );
184 local $Error::Depth = $Error::Depth + 1;
189 # syntactic sugar for
191 # record Error( ... ) and return;
195 local $Error::Depth = $Error::Depth + 1;
202 # try { ... } catch CLASS with { ... }
207 my $clauses = shift || {};
208 my $catch = $clauses->{'catch'} ||= [];
210 unshift @$catch, $pkg, $code;
215 # Object query methods
219 exists $self->{'-object'} ? $self->{'-object'} : undef;
224 exists $self->{'-file'} ? $self->{'-file'} : undef;
229 exists $self->{'-line'} ? $self->{'-line'} : undef;
234 exists $self->{'-text'} ? $self->{'-text'} : undef;
241 defined $self->{'-text'} ? $self->{'-text'} : "Died";
246 exists $self->{'-value'} ? $self->{'-value'} : undef;
249 package Error::Simple;
251 @Error::Simple::ISA = qw(Error);
255 my $text = "" . shift;
259 local $Error::Depth
= $Error::Depth
+ 1;
261 @args = ( -file
=> $1, -line
=> $2)
262 if($text =~ s/\s+at\s+(\S+)\s+line\s+(\d+)(?:,\s*<[^>]*>\s+line\s+\d+)?\.?\n?$//s);
263 push(@args, '-value', 0 + $value)
266 $self->SUPER::new
(-text
=> $text, @args);
271 my $text = $self->SUPER::stringify
;
272 $text .= sprintf(" at %s line %d.\n", $self->file, $self->line)
273 unless($text =~ /\n$/s);
277 ##########################################################################
278 ##########################################################################
280 # Inspired by code from Jesse Glick <jglick@sig.bsh.com> and
281 # Peter Seibel <peter@weblogic.com>
286 use vars
qw(@EXPORT_OK @ISA %EXPORT_TAGS);
288 @EXPORT_OK = qw(try with finally except otherwise);
289 %EXPORT_TAGS = (try
=> \
@EXPORT_OK);
293 sub run_clauses
($$$\@
) {
294 my($clauses,$err,$wantarray,$result) = @_;
297 $err = $Error::ObjectifyCallback
->({'text' =>$err}) unless ref($err);
303 if(defined($catch = $clauses->{'catch'})) {
307 for( ; $i < @
$catch ; $i += 2) {
308 my $pkg = $catch->[$i];
309 unless(defined $pkg) {
311 splice(@
$catch,$i,2,$catch->[$i+1]->());
315 elsif(Scalar
::Util
::blessed
($err) && $err->isa($pkg)) {
316 $code = $catch->[$i+1];
319 local($Error::THROWN
);
322 @
{$result} = $code->($err,\
$more);
324 elsif(defined($wantarray)) {
326 $result->[0] = $code->($err,\
$more);
329 $code->($err,\
$more);
334 next CATCHLOOP
if $more;
338 $err = defined($Error::THROWN
)
339 ?
$Error::THROWN
: $@
;
340 $err = $Error::ObjectifyCallback
->({'text' =>$err})
351 if(defined($owise = $clauses->{'otherwise'})) {
352 my $code = $clauses->{'otherwise'};
356 @
{$result} = $code->($err,\
$more);
358 elsif(defined($wantarray)) {
360 $result->[0] = $code->($err,\
$more);
363 $code->($err,\
$more);
371 $err = defined($Error::THROWN
)
372 ?
$Error::THROWN
: $@
;
374 $err = $Error::ObjectifyCallback
->({'text' =>$err})
384 my $clauses = @_ ?
shift : {};
389 unshift @Error::STACK
, $clauses;
391 my $wantarray = wantarray();
394 local $Error::THROWN
= undef;
401 elsif(defined $wantarray) {
402 $result[0] = $try->();
410 $err = defined($Error::THROWN
) ?
$Error::THROWN
: $@
416 $err = run_clauses
($clauses,$err,wantarray,@result)
419 $clauses->{'finally'}->()
420 if(defined($clauses->{'finally'}));
424 if (Scalar
::Util
::blessed
($err) && $err->can('throw'))
434 wantarray ?
@result : $result[0];
437 # Each clause adds a sub to the list of clauses. The finally clause is
438 # always the last, and the otherwise clause is always added just before
439 # the finally clause.
441 # All clauses, except the finally clause, add a sub which takes one argument
442 # this argument will be the error being thrown. The sub will return a code ref
443 # if that clause can handle that error, otherwise undef is returned.
445 # The otherwise clause adds a sub which unconditionally returns the users
446 # code reference, this is why it is forced to be last.
448 # The catch clause is defined in Error.pm, as the syntax causes it to
449 # be called as a method
457 my $clauses = { 'finally' => $code };
461 # The except clause is a block which returns a hashref or a list of
462 # key-value pairs, where the keys are the classes and the values are subs.
466 my $clauses = shift || {};
467 my $catch = $clauses->{'catch'} ||= [];
471 my(@array) = $code->($_[0]);
472 if(@array == 1 && ref($array[0])) {
475 if(UNIVERSAL
::isa
($ref,'HASH'));
483 unshift @
{$catch}, undef, $sub;
488 sub otherwise
(&;$) {
490 my $clauses = shift || {};
492 if(exists $clauses->{'otherwise'}) {
494 Carp
::croak
("Multiple otherwise clauses");
497 $clauses->{'otherwise'} = $code;
507 Error - Error/exception handling in an OO-ish way
513 throw Error::Simple( "A simple error");
517 record Error::Simple("A simple error")
521 unlink($file) or throw Error::Simple("$file: $!",$!);
525 die "error!" if $condition;
526 throw Error::Simple -text => "Oops!" if $other_condition;
528 catch Error::IO with {
530 print STDERR "File ", $E->{'-file'}, " had a problem\n";
534 my $general_handler=sub {send_message $E->{-description}};
536 UserException1 => $general_handler,
537 UserException2 => $general_handler
541 print STDERR "Well I don't know what to say\n";
544 close_the_garage_door_already(); # Should be reliable
545 }; # Don't forget the trailing ; or you might be surprised
549 The C<Error> package provides two interfaces. Firstly C<Error> provides
550 a procedural interface to exception handling. Secondly C<Error> is a
551 base class for errors/exceptions that can either be thrown, for
552 subsequent catch, or can simply be recorded.
554 Errors in the class C<Error> should not be thrown directly, but the
555 user should throw errors from a sub-class of C<Error>.
557 =head1 PROCEDURAL INTERFACE
559 C<Error> exports subroutines to perform exception handling. These will
560 be exported if the C<:try> tag is used in the C<use> line.
564 =item try BLOCK CLAUSES
566 C<try> is the main subroutine called by the user. All other subroutines
567 exported are clauses to the try subroutine.
569 The BLOCK will be evaluated and, if no error is throw, try will return
570 the result of the block.
572 C<CLAUSES> are the subroutines below, which describe what to do in the
573 event of an error being thrown within BLOCK.
575 =item catch CLASS with BLOCK
577 This clauses will cause all errors that satisfy C<$err-E<gt>isa(CLASS)>
578 to be caught and handled by evaluating C<BLOCK>.
580 C<BLOCK> will be passed two arguments. The first will be the error
581 being thrown. The second is a reference to a scalar variable. If this
582 variable is set by the catch block then, on return from the catch
583 block, try will continue processing as if the catch block was never
586 To propagate the error the catch block may call C<$err-E<gt>throw>
588 If the scalar reference by the second argument is not set, and the
589 error is not thrown. Then the current try block will return with the
590 result from the catch block.
594 When C<try> is looking for a handler, if an except clause is found
595 C<BLOCK> is evaluated. The return value from this block should be a
596 HASHREF or a list of key-value pairs, where the keys are class names
597 and the values are CODE references for the handler of errors of that
600 =item otherwise BLOCK
602 Catch any error by executing the code in C<BLOCK>
604 When evaluated C<BLOCK> will be passed one argument, which will be the
605 error being processed.
607 Only one otherwise block may be specified per try block
611 Execute the code in C<BLOCK> either after the code in the try block has
612 successfully completed, or if the try block throws an error then
613 C<BLOCK> will be executed after the handler has completed.
615 If the handler throws an error then the error will be caught, the
616 finally block will be executed and the error will be re-thrown.
618 Only one finally block may be specified per try block
622 =head1 CLASS INTERFACE
626 The C<Error> object is implemented as a HASH. This HASH is initialized
627 with the arguments that are passed to it's constructor. The elements
628 that are used by, or are retrievable by the C<Error> class are listed
629 below, other classes may add to these.
637 If C<-file> or C<-line> are not specified in the constructor arguments
638 then these will be initialized with the file name and line number where
639 the constructor was called from.
641 If the error is associated with an object then the object should be
642 passed as the C<-object> argument. This will allow the C<Error> package
643 to associate the error with the object.
645 The C<Error> package remembers the last error created, and also the
646 last error associated with a package. This could either be the last
647 error created by a sub in that package, or the last error which passed
648 an object blessed into that package as the C<-object> argument.
652 =item throw ( [ ARGS ] )
654 Create a new C<Error> object and throw an error, which will be caught
655 by a surrounding C<try> block, if there is one. Otherwise it will cause
658 C<throw> may also be called on an existing error to re-throw it.
660 =item with ( [ ARGS ] )
662 Create a new C<Error> object and returns it. This is defined for
665 die with Some::Error ( ... );
667 =item record ( [ ARGS ] )
669 Create a new C<Error> object and returns it. This is defined for
672 record Some::Error ( ... )
677 =head2 STATIC METHODS
681 =item prior ( [ PACKAGE ] )
683 Return the last error created, or the last error associated with
686 =item flush ( [ PACKAGE ] )
688 Flush the last error created, or the last error associated with
689 C<PACKAGE>.It is necessary to clear the error stack before exiting the
690 package or uncaught errors generated using C<record> will be reported.
698 =head2 OBJECT METHODS
704 If the variable C<$Error::Debug> was non-zero when the error was
705 created, then C<stacktrace> returns a string created by calling
706 C<Carp::longmess>. If the variable was zero the C<stacktrace> returns
707 the text of the error appended with the filename and line number of
708 where the error was created, providing the text does not end with a
713 The object this error was associated with
717 The file where the constructor of this error was called from
721 The line where the constructor of this error was called from
725 The text of the error
729 =head2 OVERLOAD METHODS
735 A method that converts the object into a string. This method may simply
736 return the same as the C<text> method, or it may append more
737 information. For example the file name and line number.
739 By default this method returns the C<-text> argument that was passed to
740 the constructor, or the string C<"Died"> if none was given.
744 A method that will return a value that can be associated with the
745 error. For example if an error was created due to the failure of a
746 system call, then this may return the numeric value of C<$!> at the
749 By default this method returns the C<-value> argument that was passed
754 =head1 PRE-DEFINED ERROR CLASSES
760 This class can be used to hold simple error strings and values. It's
761 constructor takes two arguments. The first is a text value, the second
762 is a numeric value. These values are what will be returned by the
765 If the text value ends with C<at file line 1> as $@ strings do, then
766 this infomation will be used to set the C<-file> and C<-line> arguments
769 This class is used internally if an eval'd block die's with an error
770 that is a plain string. (Unless C<$Error::ObjectifyCallback> is modified)
774 =head1 $Error::ObjectifyCallback
776 This variable holds a reference to a subroutine that converts errors that
777 are plain strings to objects. It is used by Error.pm to convert textual
778 errors to objects, and can be overrided by the user.
780 It accepts a single argument which is a hash reference to named parameters.
781 Currently the only named parameter passed is C<'text'> which is the text
782 of the error, but others may be available in the future.
784 For example the following code will cause Error.pm to throw objects of the
785 class MyError::Bar by default:
787 sub throw_MyError_Bar
790 my $err = MyError::Bar->new();
791 $err->{'MyBarText'} = $args->{'text'};
796 local $Error::ObjectifyCallback = \&throw_MyError_Bar;
798 # Error handling here.
803 None, but that does not mean there are not any.
807 Graham Barr <gbarr@pobox.com>
809 The code that inspired me to write this was originally written by
810 Peter Seibel <peter@weblogic.com> and adapted by Jesse Glick
811 <jglick@sig.bsh.com>.
815 Shlomi Fish <shlomif@iglu.org.il>
817 =head1 PAST MAINTAINERS
819 Arun Kumar U <u_arunkumar@yahoo.com>