The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.

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.