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***
20
'bool' => sub { return 1; },
24
$Error::Depth = 0; # Depth to pass to caller()
25
$Error::Debug = 0; # Generate verbose stack traces
26
@Error::STACK = (); # Clause stack for try
27
$Error::THROWN = undef; # last error thrown, a workaround until die $ref works
29
my $LAST; # Last error created
30
my %ERROR; # Last error associated with package
32
# Exported subs are defined in Error::subs
36
local $Exporter::ExportLevel = $Exporter::ExportLevel + 1;
37
Error::subs->import(@_);
40
# I really want to use last for the name of this method, but it is a keyword
41
# which prevent the syntax last Error
46
return $LAST unless @_;
49
return exists $ERROR{$pkg} ? $ERROR{$pkg} : undef
54
if($obj->isa('HASH')) {
55
$err = $obj->{'__Error__'}
56
if exists $obj->{'__Error__'};
58
elsif($obj->isa('GLOB')) {
59
$err = ${*$obj}{'__Error__'}
60
if exists ${*$obj}{'__Error__'};
66
# Return as much information as possible about where the error
67
# happened. The -stacktrace element only exists if $Error::DEBUG
68
# was set when the error was created
73
return $self->{'-stacktrace'}
74
if exists $self->{'-stacktrace'};
76
my $text = exists $self->{'-text'} ? $self->{'-text'} : "Died";
78
$text .= sprintf(" at %s line %d.\n", $self->file, $self->line)
79
unless($text =~ /\n$/s);
84
# Allow error propagation, ie
86
# $ber->encode(...) or
87
# return Error->prior($ber)->associate($ldap);
93
return unless ref($obj);
95
if($obj->isa('HASH')) {
96
$obj->{'__Error__'} = $err;
98
elsif($obj->isa('GLOB')) {
99
${*$obj}{'__Error__'} = $err;
102
$ERROR{ ref($obj) } = $err;
109
my($pkg,$file,$line) = caller($Error::Depth);
118
$err->associate($err->{'-object'})
119
if(exists $err->{'-object'});
121
# To always create a stacktrace would be very inefficient, so
122
# we only do it if $Error::Debug is set
126
local $Carp::CarpLevel = $Error::Depth;
127
my $text = defined($err->{'-text'}) ? $err->{'-text'} : "Error";
128
my $trace = Carp::longmess($text);
129
# Remove try calls from the trace
130
$trace =~ s/(\n\s+\S+__ANON__[^\n]+)?\n\s+eval[^\n]+\n\s+Error::subs::try[^\n]+(?=\n)//sog;
131
$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;
132
$err->{'-stacktrace'} = $trace
135
$@ = $LAST = $ERROR{$pkg} = $err;
138
# Throw an error. this contains some very gory code.
142
local $Error::Depth = $Error::Depth + 1;
144
# if we are not rethrow-ing then create the object to throw
145
$self = $self->new(@_) unless ref($self);
147
die $Error::THROWN = $self;
150
# syntactic sugar for
152
# die with Error( ... );
156
local $Error::Depth = $Error::Depth + 1;
161
# syntactic sugar for
163
# record Error( ... ) and return;
167
local $Error::Depth = $Error::Depth + 1;
174
# try { ... } catch CLASS with { ... }
179
my $clauses = shift || {};
180
my $catch = $clauses->{'catch'} ||= [];
182
unshift @$catch, $pkg, $code;
187
# Object query methods
191
exists $self->{'-object'} ? $self->{'-object'} : undef;
196
exists $self->{'-file'} ? $self->{'-file'} : undef;
201
exists $self->{'-line'} ? $self->{'-line'} : undef;
206
exists $self->{'-text'} ? $self->{'-text'} : undef;
213
defined $self->{'-text'} ? $self->{'-text'} : "Died";
218
exists $self->{'-value'} ? $self->{'-value'} : undef;
221
package Error::Simple;
223
@Error::Simple::ISA = qw(Error);
227
my $text = "" . shift;
231
local $Error::Depth = $Error::Depth + 1;
233
@args = ( -file => $1, -line => $2)
234
if($text =~ s/ at (\S+) line (\d+)(\.\n)?$//s);
236
push(@args, '-value', 0 + $value)
239
$self->SUPER::new(-text => $text, @args);
244
my $text = $self->SUPER::stringify;
245
$text .= sprintf(" at %s line %d.\n", $self->file, $self->line)
246
unless($text =~ /\n$/s);
250
##########################################################################
251
##########################################################################
253
# Inspired by code from Jesse Glick <jglick@sig.bsh.com> and
254
# Peter Seibel <peter@weblogic.com>
259
use vars qw(@EXPORT_OK @ISA %EXPORT_TAGS);
261
@EXPORT_OK = qw(try with finally except otherwise);
262
%EXPORT_TAGS = (try => \@EXPORT_OK);
266
sub run_clauses ($$$\@) {
267
my($clauses,$err,$wantarray,$result) = @_;
270
$err = new Error::Simple($err) unless ref($err);
276
if(defined($catch = $clauses->{'catch'})) {
280
for( ; $i < @$catch ; $i += 2) {
281
my $pkg = $catch->[$i];
282
unless(defined $pkg) {
284
splice(@$catch,$i,2,$catch->[$i+1]->());
288
elsif($err->isa($pkg)) {
289
$code = $catch->[$i+1];
292
local($Error::THROWN);
295
@{$result} = $code->($err,\$more);
297
elsif(defined($wantarray)) {
299
$result->[0] = $code->($err,\$more);
302
$code->($err,\$more);
307
next CATCHLOOP if $more;
311
$err = defined($Error::THROWN)
312
? $Error::THROWN : $@;
313
$err = new Error::Simple($err)
324
if(defined($owise = $clauses->{'otherwise'})) {
325
my $code = $clauses->{'otherwise'};
329
@{$result} = $code->($err,\$more);
331
elsif(defined($wantarray)) {
333
$result->[0] = $code->($err,\$more);
336
$code->($err,\$more);
344
$err = defined($Error::THROWN)
345
? $Error::THROWN : $@;
346
$err = new Error::Simple($err)
356
my $clauses = @_ ? shift : {};
361
unshift @Error::STACK, $clauses;
363
my $wantarray = wantarray();
366
local $Error::THROWN = undef;
372
elsif(defined $wantarray) {
373
$result[0] = $try->();
381
$err = defined($Error::THROWN) ? $Error::THROWN : $@
387
$err = run_clauses($clauses,$err,wantarray,@result)
390
$clauses->{'finally'}->()
391
if(defined($clauses->{'finally'}));
393
throw $err if defined($err);
395
wantarray ? @result : $result[0];
398
# Each clause adds a sub to the list of clauses. The finally clause is
399
# always the last, and the otherwise clause is always added just before
400
# the finally clause.
402
# All clauses, except the finally clause, add a sub which takes one argument
403
# this argument will be the error being thrown. The sub will return a code ref
404
# if that clause can handle that error, otherwise undef is returned.
406
# The otherwise clause adds a sub which unconditionally returns the users
407
# code reference, this is why it is forced to be last.
409
# The catch clause is defined in Error.pm, as the syntax causes it to
410
# be called as a method
418
my $clauses = { 'finally' => $code };
422
# The except clause is a block which returns a hashref or a list of
423
# key-value pairs, where the keys are the classes and the values are subs.
427
my $clauses = shift || {};
428
my $catch = $clauses->{'catch'} ||= [];
432
my(@array) = $code->($_[0]);
433
if(@array == 1 && ref($array[0])) {
436
if(UNIVERSAL::isa($ref,'HASH'));
444
unshift @{$catch}, undef, $sub;
449
sub otherwise (&;$) {
451
my $clauses = shift || {};
453
if(exists $clauses->{'otherwise'}) {
455
Carp::croak("Multiple otherwise clauses");
458
$clauses->{'otherwise'} = $code;
468
Error - Error/exception handling in an OO-ish way
474
throw Error::Simple( "A simple error");
478
record Error::Simple("A simple error")
482
unlink($file) or throw Error::Simple("$file: $!",$!);
486
die "error!" if $condition;
487
throw Error::Simple -text => "Oops!" if $other_condition;
489
catch Error::IO with {
491
print STDERR "File ", $E->{'-file'}, " had a problem\n";
495
my $general_handler=sub {send_message $E->{-description}};
497
UserException1 => $general_handler,
498
UserException2 => $general_handler
502
print STDERR "Well I don't know what to say\n";
505
close_the_garage_door_already(); # Should be reliable
506
}; # Don't forget the trailing ; or you might be surprised
510
The C<Error> package provides two interfaces. Firstly C<Error> provides
511
a procedural interface to exception handling. Secondly C<Error> is a
512
base class for errors/exceptions that can either be thrown, for
513
subsequent catch, or can simply be recorded.
515
Errors in the class C<Error> should not be thrown directly, but the
516
user should throw errors from a sub-class of C<Error>.
518
=head1 PROCEDURAL INTERFACE
520
C<Error> exports subroutines to perform exception handling. These will
521
be exported if the C<:try> tag is used in the C<use> line.
525
=item try BLOCK CLAUSES
527
C<try> is the main subroutine called by the user. All other subroutines
528
exported are clauses to the try subroutine.
530
The BLOCK will be evaluated and, if no error is throw, try will return
531
the result of the block.
533
C<CLAUSES> are the subroutines below, which describe what to do in the
534
event of an error being thrown within BLOCK.
536
=item catch CLASS with BLOCK
538
This clauses will cause all errors that satisfy C<$err-E<gt>isa(CLASS)>
539
to be caught and handled by evaluating C<BLOCK>.
541
C<BLOCK> will be passed two arguments. The first will be the error
542
being thrown. The second is a reference to a scalar variable. If this
543
variable is set by the catch block then, on return from the catch
544
block, try will continue processing as if the catch block was never
547
To propagate the error the catch block may call C<$err-E<gt>throw>
549
If the scalar reference by the second argument is not set, and the
550
error is not thrown. Then the current try block will return with the
551
result from the catch block.
555
When C<try> is looking for a handler, if an except clause is found
556
C<BLOCK> is evaluated. The return value from this block should be a
557
HASHREF or a list of key-value pairs, where the keys are class names
558
and the values are CODE references for the handler of errors of that
561
=item otherwise BLOCK
563
Catch any error by executing the code in C<BLOCK>
565
When evaluated C<BLOCK> will be passed one argument, which will be the
566
error being processed.
568
Only one otherwise block may be specified per try block
572
Execute the code in C<BLOCK> either after the code in the try block has
573
successfully completed, or if the try block throws an error then
574
C<BLOCK> will be executed after the handler has completed.
576
If the handler throws an error then the error will be caught, the
577
finally block will be executed and the error will be re-thrown.
579
Only one finally block may be specified per try block
583
=head1 CLASS INTERFACE
587
The C<Error> object is implemented as a HASH. This HASH is initialized
588
with the arguments that are passed to it's constructor. The elements
589
that are used by, or are retrievable by the C<Error> class are listed
590
below, other classes may add to these.
598
If C<-file> or C<-line> are not specified in the constructor arguments
599
then these will be initialized with the file name and line number where
600
the constructor was called from.
602
If the error is associated with an object then the object should be
603
passed as the C<-object> argument. This will allow the C<Error> package
604
to associate the error with the object.
606
The C<Error> package remembers the last error created, and also the
607
last error associated with a package. This could either be the last
608
error created by a sub in that package, or the last error which passed
609
an object blessed into that package as the C<-object> argument.
613
=item throw ( [ ARGS ] )
615
Create a new C<Error> object and throw an error, which will be caught
616
by a surrounding C<try> block, if there is one. Otherwise it will cause
619
C<throw> may also be called on an existing error to re-throw it.
621
=item with ( [ ARGS ] )
623
Create a new C<Error> object and returns it. This is defined for
626
die with Some::Error ( ... );
628
=item record ( [ ARGS ] )
630
Create a new C<Error> object and returns it. This is defined for
633
record Some::Error ( ... )
638
=head2 STATIC METHODS
642
=item prior ( [ PACKAGE ] )
644
Return the last error created, or the last error associated with
649
=head2 OBJECT METHODS
655
If the variable C<$Error::Debug> was non-zero when the error was
656
created, then C<stacktrace> returns a string created by calling
657
C<Carp::longmess>. If the variable was zero the C<stacktrace> returns
658
the text of the error appended with the filename and line number of
659
where the error was created, providing the text does not end with a
664
The object this error was associated with
668
The file where the constructor of this error was called from
672
The line where the constructor of this error was called from
676
The text of the error
680
=head2 OVERLOAD METHODS
686
A method that converts the object into a string. This method may simply
687
return the same as the C<text> method, or it may append more
688
information. For example the file name and line number.
690
By default this method returns the C<-text> argument that was passed to
691
the constructor, or the string C<"Died"> if none was given.
695
A method that will return a value that can be associated with the
696
error. For example if an error was created due to the failure of a
697
system call, then this may return the numeric value of C<$!> at the
700
By default this method returns the C<-value> argument that was passed
705
=head1 PRE-DEFINED ERROR CLASSES
711
This class can be used to hold simple error strings and values. It's
712
constructor takes two arguments. The first is a text value, the second
713
is a numeric value. These values are what will be returned by the
716
If the text value ends with C<at file line 1> as $@ strings do, then
717
this infomation will be used to set the C<-file> and C<-line> arguments
720
This class is used internally if an eval'd block die's with an error
721
that is a plain string.
727
None, but that does not mean there are not any.
731
Graham Barr, gbarr@pobox.com
733
The code that inspired me to write this was originally written by
734
Peter Seibel E<lt>peter@weblogic.comE<gt> and adapted by Jesse Glick
735
E<lt>jglick@sig.bsh.comE<gt>.
739
Arun Kumar U, u_arunkumar@yahoo.com