Oliver Charles > ConditionSystem > ConditionSystem



Annotate this POD


New  6
Open  0
View/Report Bugs
Module Version: 0.02   Source  


ConditionSystem - A Common Lisp like condition/restart system for exceptions


{ package MalformedLogEntry; use Moose; extends 'Throwable::Error';

    has bad_data => ( is => 'ro' );

    package LogParser;
    use Conditions;
    sub parse_log_entry {
        my $entry = shift or die "Must specify entry";
        if($entry =~ /(\d+-\d+-\d+) (\d+:\d+:\d+) (\w+) (.*)/) {
            return ($1, $2, $3, $4);
        else {
            restart_case {
            bind_continue(use_value => sub { return shift }),
            bind_continue(log => sub {
                warn "*** Invalid entry: $entry";
                return undef;

    package MyApp;
    use Conditions;
    my @logs = with_handlers {
        [ parse_log_entry('2010-01-01 10:09:5 WARN Test') ],
        [ parse_log_entry('Oh no bad data') ],
        [ parse_log_entry('2010-10-12 12:11:03 INFO Notice it still carries on!') ];
    handle(MalformedLogEntry => restart('log'));

    # @logs contains 3 logs, the 2nd of which is 'undef'
    # A single warning will have been printed to STDERR as well.


This distribution implements a Common Lisp-like approach to exception handling, providing both a mechanism for throwing/catching exceptions, but also a mechanism for continuing on from an exception via a non-local exit. This essentially allows you "fix" the code that was throwing an exception from outside that code itself, rather than trying to handle stuff when it's already too late.

For a good introduction to the condition system (that this was all inspired by), I highly recommend Practical Common Lisp, in particular the chapter Beyond Exception Handling

HALT! This module is both very new, and does some fairly crazy things, and as such may not be ready for prime time usage. However, the basic test cases do pass, so maybe you will have some luck. I encourage the usage of this module for a bit of fun, and exploration for now. Hopefully it will mature into a production ready module, but it's not there yet. But with your help, it can be so... please submit patches, bug reports and all that goodness.



Run a block of code, and if any exception is raised, try and invoke one of the handlers.

    with_handlers {
        # Dangerous code...
    handle(ExceptionType => sub {
        # Recovery


Return from a restart with a specific value.

    with_handlers {
        my $foo = restart_case {
        # foo is 500
    handle(Exception => continue_with { 500 });


Invoke a restart with a specific name, and pass extra arguments through.

with_handlers { restart_case { Exception->new } bind_restart(Log => sub { warn "An Exception was raised"; }); } handle(Exception => restart('Log'))


Throw an exception (from a specified block) with pre-defined strategies on how to resume execution later.

    restart_case { Exception->new }
    bind_restart(delegate_responsibility => sub {

The body of restart_case must yield an exception, and will be when the restart case is invoked. There may be 0 to many restarts provided. Restarts are invoked by restart, called from a handler set up with with_handlers.


Create a handler for a given exception type, and associated code reference:

    handle('Exception::Class' => sub {
        # Handle exception here...


Bind a restart for the scope of a restart_case block, with a given name and code reference:

    bind_continue(panic => sub {
        warn "OMG OMG OMG OMG";


Oliver Charles


This software is copyright (c) 2011 by Oliver Charles <oliver.g.charles@googlemail.com>.

This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.

syntax highlighting: