| PException documentation | Contained in the PException distribution. |
PException - Exception manager
use PException;
try {
throw( AnException->new() ) if $something;
throw( AnOtherException->new( [] ) )
unless $anotherthing;
}
catch AnException( sub { } ) ,
onfly AnOtherException( sub { } ) ;
execute code until its end or an exception happens.
throw a list of exceptions.
create a new instance of an Exception.
execute an subroutine if this kind of exception is thrown
execute an subroutine and continue the execution of the last try if this kind of exception is thrown
add a flying exception handler. it allows to continue the try block where the exception appear.
return true if there is waitting exceptions, false elsewhere
create an object for catching methods. when a catch happens,
control if there is some exceptions to catch & treat in an stack
code for handling a exception. it's an empty sub actually. you overload it if you want a default handler for an exception.
the handler which intercept __WARN__ or __DIE__ signal
local %_XCPHDL_ = ( EXCEPTIONS => [], FLYS => [], STACKFLY => [], ONFLY => 0, FRESH => 0, CANDIE => 0 );
@{$PException::_XCPHDL_->{EXCEPTIONS}} is the stack of thrown exceptions.
@{$PException::_XCPHDL_->{FLYS}} is the stack of fly exception handler.
@{$PException::_XCPHDL_->{STACKFLY}} contain a stack of the list of onfly exception. each list is linked to a nested try.
it's a flag which determine if an handler can die when it throws.
is up only when fresh exception are thrown.
is up when a die call must be done.
a try block is a code block which is evaluated.
when you throw a new set of exception, this set is pushed in @{$PException::_XCPHDL_->{EXCEPTIONS}} , the system call die.
then $SIG{__DIE__} check if any waitting may be catched, when it finish and there is waitting exception yet, it die, else it continues the try block ; it's the onfly exception handling.
the catching part is the same thing than upside, but you can't continue the execution of the try block.
Don't try to change $SIG{__WARN__} and $SIG{__DIE__} inside a try block.
Copyright (c) 1998-2003 Samuel MOUNIEE
This file is part of PException.
PException is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
PException is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with PException; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Samuel Mouniée <mouns@mouns.net>
| PException documentation | Contained in the PException distribution. |
# -*- cperl -*- # # Copyright (c) 1997-2003 Samuel MOUNIEE # # This file is part of PException. # # PException is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PException is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PException; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # package PException; use strict; use vars qw( $VERSION @ISA @EXPORT @EXPORT_OK $_XCPHDL_ ); #sub DEBUG { 5 } #sub debug { print STDERR join( " ! ", @_ ) if $_[0] >= DEBUG } sub debug { } require Exporter; $VERSION= "2.4";
@ISA = qw( Exporter ); @EXPORT = qw( throw try ); @EXPORT_OK = qw( ); #my $_XCPHDL_ = [ { # EXCEPTIONS => 1, # FLYS => 2, # STACKFLY => 3, # ONFLY => 4, # FRESH => 5, # CANDIE => 6 # }, [], [], [], 0, 0, 0 ]; $_XCPHDL_ = { EXCEPTIONS => [], FLYS => [], STACKFLY => [], ONFLY => 0, FRESH => 0, CANDIE => 0 }; BEGIN { $SIG{__WARN__} = \&__onflyhandler; $SIG{__DIE__} = sub { # $PException::_XCPHDL_->{CANDIE} = 1; # if( $@ && hadWaittingExceptions() ) # { debug( 2, "NN-> $@ <" ) } # elsif ( $@ ) { debug( 2, "NO-> $@ <" ); $@ = undef } # elsif ( @_ ) { debug( 2, "ON->", @_, "<" ) } # else { debug( 2, "OO->", $@, @_, "<" ) } # $@ .= " - "; die ( $@, @_ ); # throw(); }; }
sub try(&@) { my $e = shift; my @catch = grep { $_->isa("PException::CATCH") } @_; my @onfly = grep { $_->isa("PException::ONFLY") } @_; ## add an new stack of onfly exception push( @{$PException::_XCPHDL_->{STACKFLY}}, [ @onfly ] ); # debug( 1, "try", $e, @_ ); eval { &$e; }; ## remove the stack of onfly exception pop( @{$PException::_XCPHDL_->{STACKFLY}} ); if( $@ && hadWaittingExceptions() ) { chomp( $@ ); # debug( 2, "---> $@ <" ); throw() if checkException( @catch ); } elsif ( $@ ) { chomp( $@ ); # debug( 2, "no-> $@ <" ); $@ = undef; } # debug( 2, "STACKFLY", scalar( @{$PException::_XCPHDL_->{STACKFLY}} ) ); }
sub throw(@) { # debug( 1, "throw", "begin" ); $PException::_XCPHDL_->{FRESH} = 0; if ( @_ > 0 ) { push( @{$PException::_XCPHDL_->{EXCEPTIONS}}, @_ ); $PException::_XCPHDL_->{FRESH} = 1; } my @tmp = @{$PException::_XCPHDL_->{EXCEPTIONS}}; # debug( 2, "throw", @tmp ); map { $_ = ref($_) . "($$_)" } @tmp; if ( !$PException::_XCPHDL_->{ONFLY} && $PException::_XCPHDL_->{CANDIE} ) { # debug( 2, "throw", "Die" ); $_XCPHDL_->{CANDIE} = 0; die( join( "\t- ", "Die", @tmp ) ); } elsif( !$PException::_XCPHDL_->{ONFLY} ) { # debug( 2, "throw", "Warn" ); warn( join( "\t- ", "Warn", @tmp ) ); } }
sub new($@) { my $classe = shift; my $sc = shift; return bless $sc, $classe if ref( $sc ); return bless \$sc, $classe; }
sub catch($&) { return newTypedCatching( $_[0], $_[1], "CATCH" ) }
sub onfly($&) { return newTypedCatching( $_[0], $_[1], "ONFLY" ) }
sub addFlyingHandler($&) { push( @{$PException::_XCPHDL_->{FLYS}}, newTypedCatching( $_[0], $_[1], "FLYS" ) ) }
sub hadWaittingExceptions { return scalar(@{$PException::_XCPHDL_->{EXCEPTIONS}})>0 }
sub newTypedCatching($$$) { my ( $s, $c, $sig ) = @_; if ( !defined( $c ) ) { $c = sub {} unless ( $c = $s->can( "handleException" ) ) } return bless sub() { debug( 1, $sig, $s, $c, @{$PException::_XCPHDL_->{EXCEPTIONS}} ); if ( my @tmp = grep { $_->isa($s) } @{$PException::_XCPHDL_->{EXCEPTIONS}} ) { @{$PException::_XCPHDL_->{EXCEPTIONS}} = grep { !($_->isa($s)) } @{$PException::_XCPHDL_->{EXCEPTIONS}}; &$c(@tmp); # @{$PException::_XCPHDL_->{EXCEPTIONS}} = ( @{$PException::_XCPHDL_->{EXCEPTIONS}}, @tmp ); return 1; } return 0; }, "PException::$sig"; }
sub checkException(@) { foreach(@_){&{$_}()} return hadWaittingExceptions(); }
sub handleException { }
sub __onflyhandler { if ( hadWaittingExceptions() ) { my ( @tmp ); # debug( 1, "FLYS HANDLER", "Begin" ); ## get the current stack of onfly exception if ( scalar( @{$PException::_XCPHDL_->{STACKFLY}} ) ) { @tmp = @{$PException::_XCPHDL_->{STACKFLY}->[ $#{$PException::_XCPHDL_->{STACKFLY}}]}; } else { my ( $i, @tmp ) = ( 0 ); while( @tmp = caller( $i++ ) ) { print STDERR "$i\t> " . join( " + ", grep { defined $_ } @tmp, "\n" ) } for ( @{$PException::_XCPHDL_->{EXCEPTIONS}} ) { print STDERR "\t>$_ - ", $$_ , "\n" } die( "ya1kouille! PException thrown with no try block" ) } # debug( 2, "FLYS HANDLER", @tmp ); ## add flying handlers if fresh exception push( @tmp, @{$PException::_XCPHDL_->{FLYS}} ) if ( ( $PException::_XCPHDL_->{FRESH} ) && scalar( @{$PException::_XCPHDL_->{FLYS}} ) ); $PException::_XCPHDL_->{ONFLY} = 1; if ( checkException( @tmp ) ) { # debug( 2, "FLYS HANDLER", "Following" ); $PException::_XCPHDL_->{ONFLY} = 0; $PException::_XCPHDL_->{CANDIE}= 1; throw(); } # debug( 2, "FLYS HANDLER", "End" ); undef $@; $PException::_XCPHDL_->{ONFLY} = 0; } else { print STDERR $@ } } __END__