Add Error.pm to the distribution
[git/gitweb.git] / perl / Error.pm
blobebd07498a22ec598449211e8a26c0b63689633ff
1 # Error.pm
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***
12 package Error;
14 use strict;
15 use vars qw($VERSION);
16 use 5.004;
18 $VERSION = "0.15009";
20 use overload (
21 '""' => 'stringify',
22 '0+' => 'value',
23 'bool' => sub { return 1; },
24 'fallback' => 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
37 my $args = shift;
38 return Error::Simple->new($args->{'text'});
41 $Error::ObjectifyCallback = \&throw_Error_Simple;
44 # Exported subs are defined in Error::subs
46 use Scalar::Util ();
48 sub import {
49 shift;
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
57 sub prior {
58 shift; # ignore
60 return $LAST unless @_;
62 my $pkg = shift;
63 return exists $ERROR{$pkg} ? $ERROR{$pkg} : undef
64 unless ref($pkg);
66 my $obj = $pkg;
67 my $err = 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__'};
77 $err;
80 sub flush {
81 shift; #ignore
83 unless (@_) {
84 $LAST = undef;
85 return;
88 my $pkg = shift;
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
98 sub stacktrace {
99 my $self = shift;
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);
109 $text;
112 # Allow error propagation, ie
114 # $ber->encode(...) or
115 # return Error->prior($ber)->associate($ldap);
117 sub associate {
118 my $err = shift;
119 my $obj = shift;
121 return unless ref($obj);
123 if($obj->isa('HASH')) {
124 $obj->{'__Error__'} = $err;
126 elsif($obj->isa('GLOB')) {
127 ${*$obj}{'__Error__'} = $err;
129 $obj = ref($obj);
130 $ERROR{ ref($obj) } = $err;
132 return;
135 sub new {
136 my $self = shift;
137 my($pkg,$file,$line) = caller($Error::Depth);
139 my $err = bless {
140 '-package' => $pkg,
141 '-file' => $file,
142 '-line' => $line,
144 }, $self;
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
152 if($Error::Debug) {
153 require Carp;
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.
168 sub throw {
169 my $self = shift;
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( ... );
182 sub with {
183 my $self = shift;
184 local $Error::Depth = $Error::Depth + 1;
186 $self->new(@_);
189 # syntactic sugar for
191 # record Error( ... ) and return;
193 sub record {
194 my $self = shift;
195 local $Error::Depth = $Error::Depth + 1;
197 $self->new(@_);
200 # catch clause for
202 # try { ... } catch CLASS with { ... }
204 sub catch {
205 my $pkg = shift;
206 my $code = shift;
207 my $clauses = shift || {};
208 my $catch = $clauses->{'catch'} ||= [];
210 unshift @$catch, $pkg, $code;
212 $clauses;
215 # Object query methods
217 sub object {
218 my $self = shift;
219 exists $self->{'-object'} ? $self->{'-object'} : undef;
222 sub file {
223 my $self = shift;
224 exists $self->{'-file'} ? $self->{'-file'} : undef;
227 sub line {
228 my $self = shift;
229 exists $self->{'-line'} ? $self->{'-line'} : undef;
232 sub text {
233 my $self = shift;
234 exists $self->{'-text'} ? $self->{'-text'} : undef;
237 # overload methods
239 sub stringify {
240 my $self = shift;
241 defined $self->{'-text'} ? $self->{'-text'} : "Died";
244 sub value {
245 my $self = shift;
246 exists $self->{'-value'} ? $self->{'-value'} : undef;
249 package Error::Simple;
251 @Error::Simple::ISA = qw(Error);
253 sub new {
254 my $self = shift;
255 my $text = "" . shift;
256 my $value = shift;
257 my(@args) = ();
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)
264 if defined($value);
266 $self->SUPER::new(-text => $text, @args);
269 sub stringify {
270 my $self = shift;
271 my $text = $self->SUPER::stringify;
272 $text .= sprintf(" at %s line %d.\n", $self->file, $self->line)
273 unless($text =~ /\n$/s);
274 $text;
277 ##########################################################################
278 ##########################################################################
280 # Inspired by code from Jesse Glick <jglick@sig.bsh.com> and
281 # Peter Seibel <peter@weblogic.com>
283 package Error::subs;
285 use Exporter ();
286 use vars qw(@EXPORT_OK @ISA %EXPORT_TAGS);
288 @EXPORT_OK = qw(try with finally except otherwise);
289 %EXPORT_TAGS = (try => \@EXPORT_OK);
291 @ISA = qw(Exporter);
293 sub run_clauses ($$$\@) {
294 my($clauses,$err,$wantarray,$result) = @_;
295 my $code = undef;
297 $err = $Error::ObjectifyCallback->({'text' =>$err}) unless ref($err);
299 CATCH: {
301 # catch
302 my $catch;
303 if(defined($catch = $clauses->{'catch'})) {
304 my $i = 0;
306 CATCHLOOP:
307 for( ; $i < @$catch ; $i += 2) {
308 my $pkg = $catch->[$i];
309 unless(defined $pkg) {
310 #except
311 splice(@$catch,$i,2,$catch->[$i+1]->());
312 $i -= 2;
313 next CATCHLOOP;
315 elsif(Scalar::Util::blessed($err) && $err->isa($pkg)) {
316 $code = $catch->[$i+1];
317 while(1) {
318 my $more = 0;
319 local($Error::THROWN);
320 my $ok = eval {
321 if($wantarray) {
322 @{$result} = $code->($err,\$more);
324 elsif(defined($wantarray)) {
325 @{$result} = ();
326 $result->[0] = $code->($err,\$more);
328 else {
329 $code->($err,\$more);
333 if( $ok ) {
334 next CATCHLOOP if $more;
335 undef $err;
337 else {
338 $err = defined($Error::THROWN)
339 ? $Error::THROWN : $@;
340 $err = $Error::ObjectifyCallback->({'text' =>$err})
341 unless ref($err);
343 last CATCH;
349 # otherwise
350 my $owise;
351 if(defined($owise = $clauses->{'otherwise'})) {
352 my $code = $clauses->{'otherwise'};
353 my $more = 0;
354 my $ok = eval {
355 if($wantarray) {
356 @{$result} = $code->($err,\$more);
358 elsif(defined($wantarray)) {
359 @{$result} = ();
360 $result->[0] = $code->($err,\$more);
362 else {
363 $code->($err,\$more);
367 if( $ok ) {
368 undef $err;
370 else {
371 $err = defined($Error::THROWN)
372 ? $Error::THROWN : $@;
374 $err = $Error::ObjectifyCallback->({'text' =>$err})
375 unless ref($err);
379 $err;
382 sub try (&;$) {
383 my $try = shift;
384 my $clauses = @_ ? shift : {};
385 my $ok = 0;
386 my $err = undef;
387 my @result = ();
389 unshift @Error::STACK, $clauses;
391 my $wantarray = wantarray();
393 do {
394 local $Error::THROWN = undef;
395 local $@ = undef;
397 $ok = eval {
398 if($wantarray) {
399 @result = $try->();
401 elsif(defined $wantarray) {
402 $result[0] = $try->();
404 else {
405 $try->();
410 $err = defined($Error::THROWN) ? $Error::THROWN : $@
411 unless $ok;
414 shift @Error::STACK;
416 $err = run_clauses($clauses,$err,wantarray,@result)
417 unless($ok);
419 $clauses->{'finally'}->()
420 if(defined($clauses->{'finally'}));
422 if (defined($err))
424 if (Scalar::Util::blessed($err) && $err->can('throw'))
426 throw $err;
428 else
430 die $err;
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
451 sub with (&;$) {
455 sub finally (&) {
456 my $code = shift;
457 my $clauses = { 'finally' => $code };
458 $clauses;
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.
464 sub except (&;$) {
465 my $code = shift;
466 my $clauses = shift || {};
467 my $catch = $clauses->{'catch'} ||= [];
469 my $sub = sub {
470 my $ref;
471 my(@array) = $code->($_[0]);
472 if(@array == 1 && ref($array[0])) {
473 $ref = $array[0];
474 $ref = [ %$ref ]
475 if(UNIVERSAL::isa($ref,'HASH'));
477 else {
478 $ref = \@array;
480 @$ref
483 unshift @{$catch}, undef, $sub;
485 $clauses;
488 sub otherwise (&;$) {
489 my $code = shift;
490 my $clauses = shift || {};
492 if(exists $clauses->{'otherwise'}) {
493 require Carp;
494 Carp::croak("Multiple otherwise clauses");
497 $clauses->{'otherwise'} = $code;
499 $clauses;
503 __END__
505 =head1 NAME
507 Error - Error/exception handling in an OO-ish way
509 =head1 SYNOPSIS
511 use Error qw(:try);
513 throw Error::Simple( "A simple error");
515 sub xyz {
517 record Error::Simple("A simple error")
518 and return;
521 unlink($file) or throw Error::Simple("$file: $!",$!);
523 try {
524 do_some_stuff();
525 die "error!" if $condition;
526 throw Error::Simple -text => "Oops!" if $other_condition;
528 catch Error::IO with {
529 my $E = shift;
530 print STDERR "File ", $E->{'-file'}, " had a problem\n";
532 except {
533 my $E = shift;
534 my $general_handler=sub {send_message $E->{-description}};
535 return {
536 UserException1 => $general_handler,
537 UserException2 => $general_handler
540 otherwise {
541 print STDERR "Well I don't know what to say\n";
543 finally {
544 close_the_garage_door_already(); # Should be reliable
545 }; # Don't forget the trailing ; or you might be surprised
547 =head1 DESCRIPTION
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.
562 =over 4
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
584 found.
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.
592 =item except 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
598 type.
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
609 =item finally 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
620 =back
622 =head1 CLASS INTERFACE
624 =head2 CONSTRUCTORS
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.
631 -file
632 -line
633 -text
634 -value
635 -object
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.
650 =over 4
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
656 the program to exit.
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
663 syntactic sugar, eg
665 die with Some::Error ( ... );
667 =item record ( [ ARGS ] )
669 Create a new C<Error> object and returns it. This is defined for
670 syntactic sugar, eg
672 record Some::Error ( ... )
673 and return;
675 =back
677 =head2 STATIC METHODS
679 =over 4
681 =item prior ( [ PACKAGE ] )
683 Return the last error created, or the last error associated with
684 C<PACKAGE>
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.
692 $Error->flush;
694 =cut
696 =back
698 =head2 OBJECT METHODS
700 =over 4
702 =item stacktrace
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
709 newline.
711 =item object
713 The object this error was associated with
715 =item file
717 The file where the constructor of this error was called from
719 =item line
721 The line where the constructor of this error was called from
723 =item text
725 The text of the error
727 =back
729 =head2 OVERLOAD METHODS
731 =over 4
733 =item stringify
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.
742 =item value
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
747 time.
749 By default this method returns the C<-value> argument that was passed
750 to the constructor.
752 =back
754 =head1 PRE-DEFINED ERROR CLASSES
756 =over 4
758 =item Error::Simple
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
763 overload methods.
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
767 of the error object.
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)
772 =back
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
789 my $args = shift;
790 my $err = MyError::Bar->new();
791 $err->{'MyBarText'} = $args->{'text'};
792 return $err;
796 local $Error::ObjectifyCallback = \&throw_MyError_Bar;
798 # Error handling here.
801 =head1 KNOWN BUGS
803 None, but that does not mean there are not any.
805 =head1 AUTHORS
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>.
813 =head1 MAINTAINER
815 Shlomi Fish <shlomif@iglu.org.il>
817 =head1 PAST MAINTAINERS
819 Arun Kumar U <u_arunkumar@yahoo.com>
821 =cut