NAME
Exception::Resumable -- resumable exceptions for Perl.
SYNOPSIS
use Exception::Resumable;
handle {
...
raise $exception, @args;
...
} exception_1 => sub { ...; return $value_to_use },
qr/exception_2/ => sub { ...; raise $new_exception, @args },
[qw(exception_3 exception_4)] => $value_to_use,
{ exception_5 => 1, exception_6 => 1 } => sub { ... };
DESCRIPTION
This module implements a basic version of "resumable exceptions." This means that a dynamically-bound handling function is called before the stack is unwound, rather than afterwards (like die
). The appropriate handler is found by looking (in order) at @Exception::Resumable::CATCH
. If no appropriate handler is found, die
is called instead.
Why would you want to do this? Perl's standard eval/die
exception handling limits what you can do when something goes wrong: by the time you get control again after something dies, the stack has already been unwound to your eval
. If you want to fix the problem and continue, you have to get back to where the code died.
Sometimes this is fine: if your web server encountered a network error, you probably want to clean up the connection and wait for the user to hit "reload." However, sometimes it's easier to fix the problem right there and keep going: if a function receives invalid input, you may want to ask the user for a better answer and continue.
handle BLOCK HANDLERS...
Handle exceptions from within BLOCK
using HANDLERS
, a list of key/value pairs. The handlers defined by a handle
block are not active while they are called, so re-raising the same exception will not cause an infinite loop. A handler value may be either a function, which will be called with the arguments passed to raise
, or a scalar, which will be returned as-is.
On Perls older than 5.10, the key may be one of the following:
\@ARRAY
-
Catch the exception if it is (
eq
to) a member of@ARRAY
. \%HASH
-
Catch the exception if it is a key in
%HASH
. qr/REGEXP/
-
Catch the exception if it matches
REGEXP
. $SCALAR
-
Catch the exception if it is
eq
to$SCALAR
.
On Perl 5.10 and newer, the key may be any scalar that can go on the right side of a "smart match".
raise NAME, DETAILS...
Raise exception NAME
with detailed information DETAILS
.
test_raise NAME
See what would happen if you raise NAME
. Return the $key, $value
that would have handled NAME
, or undef
if it would have died.
EXAMPLE
Say you have a program that watches some log files. If one of the files disappears all of a sudden, and it is running interactively, it can ask the user to point it in the right direction. If not, it should just die:
sub process_file
{
my $file = shift;
if (!-f $file) {
$file = raise "Missing file", $file;
}
# do stuff, now that we know $file is valid
}
sub get_a_file
{
print "Use what for $_[0]? "; chomp(my $f = <STDIN>);
$f = raise "Missing file", $f unless -f $f;
$f;
}
sub main
{
handle {
# stuff that calls process_file
} is_interactive() ? ('Missing file' => \&get_a_file) : ();
}
SEE ALSO
Exception::*
(and especially Try::Tiny) on CPAN, for many, many flavors of exception handling. Writing exception modules seems almost as popular as writing test modules, sudoku solvers, and Fibonacci functions.
See also the Common Lisp Hyperspec section 9.1, "Condition System Concepts" and Common Lisp the Language's section 29, "Conditions." Both are available online, and describe the error-handling model partially emulated here.
AUTHOR
Sean O'Rourke, <seano@cpan.org>
Bug reports welcome, patches even more welcome.
COPYRIGHT
Copyright (C) 2007-2011 Sean O'Rourke. All rights reserved, some wrongs reversed. This module is distributed under the same terms as Perl itself.