NAME
Syntax::Feature::Try - try/catch/finally statement for exception handling
SYNOPSIS
use syntax 'try';
try {
# run this code and handle errors
}
catch (My::Class::Err $e) {
# handle exception based on class "My::Class::Err"
}
catch ($e) {
# handle other exceptions
}
finally {
# cleanup block
}
DESCRIPTION
This module implements syntax for try/catch/finally statement with behaviour similar to other programming languages (like Java, Python, etc.).
It handles correctly return/wantarray inside try/catch/finally blocks.
It uses perl keyword/parser API. So it requires perl >= 5.14.
SYNTAX
initiliazation
To initialize this syntax feature call:
use syntax 'try';
try
The try block is executed. If it throws an error, then first catch block (in order) that can handle thrown error will be executed. Other catch blocks will be skipped.
If none of catch blocks can handle the error, it is thrown out of whole statement. If try block does not throw an error, all catch blocks are skipped.
catch error class
catch (My::Error $err) { ... }
This catch block can handle error that is instance of class My::Error
or any of it's subclasses.
Caught error is accessible inside catch block via declared local variable $err
.
catch all errors
To catch all errors use syntax:
catch ($e) { ... }
Caught error is accessible inside catch block via declared local variable $e
.
catch without variable
Variable name in catch block is not mandatory:
try {
...
}
catch (MyError::FileNotFound) {
print "file not found";
}
catch {
print "operation failed";
}
rethrow error
To rethrow caught error call "die $err".
For example (log any Connection::Error):
try { ... }
catch (Connection::Error $err) {
log_error($err);
die $err;
}
finally
The finally block is executed at the end of statement. It is always executed (even if try or catch block throw an error).
my $fh;
try {
$fh = IO::File->new("/etc/hosts");
...
}
finally {
$fh->close if $fh;
}
WARNING: If finally block throws an exception, originaly thrown exception (from try/catch block) is discarded. You can convert errors inside finally block to warnings:
try {
# try block
}
finally {
try {
# cleanup code
}
catch ($e) { warn $e }
}
Supported features
Exception::Class
This module is compatible with Exception::Class
use Exception::Class (
'My::Test::Error'
);
use syntax 'try';
try {
...
My::Test::Error->throw('invalid password');
}
catch (My::Test::Error $err) {
# handle error here
}
Moose::Util::TypeConstraints
This module is able to handle subtypes defined using Moose::Util::TypeConstraints (but it does not require to be this package installed if you don't use this feature).
use Moose::Util::TypeConstraints;
class_type 'Error' => { class => 'My::Error' };
subtype 'BillingError', as 'Error', where { $_->category eq 'billing' };
try {
...
}
catch (BillingError $err) {
# handle subtype BillingError
}
return from subroutine
This module supports calling "return" inside try/catch/finally blocks to return values from subroutine.
sub read_config {
my $file;
try {
$fh = IO::File->new(...);
return $fh->getline; # it returns value from subroutine "read_config"
}
catch ($e) {
# log error
}
finally {
$fh->close() if $fh;
}
}
using custom exception class matcher
There is possible register own subroutine (custom exception matcher) for extending internal className-matcher logic.
For example:
use syntax 'try';
sub is_expected_ref {
my ($exception, $className) = @_;
my ($expected_ref) = $className =~ /^is_ref::(.+)/;
# use default logic if $className is not begning with 'is_ref::'
return if not $expected_ref;
return ( ref($exception) eq $expected_ref ? 1 : 0 );
}
Syntax::Feature::Try::register_exception_matcher(\&is_expected_ref);
...
try { ... }
catch (is_ref::CODE) {
# there is handled any exception that is CODE-reference,
# because custom exception matcher returns 1 in this case
}
Exception matcher subroutine has two arguments: first ($exception) is tested exception, second ($className) is className expected in "catch block". It should return undef if given $className cannon be handled by exception matcher (in this case next registered matchers or default matcher is executed) otherwise return 1 or 0 as result of your own match $exception to $className.
Note that multiple custom matchers may be registered.
CAVEATS
@_
@_
is not accessible inside try/catch/finally blocks, because these blocks are internally called in different context.
next, last, redo
next
, last
and redo
is not working inside try/catch/finally blocks, because these blocks are internally called in different context.
goto
goto
can't be used to get out of a try, catch or finally block.
BUGS
None bugs known.
SEE ALSO
syntax - Active syntax extensions
Exception::Class - A module that allows you to declare real exception classes in Perl
Other similar packages
It reports wrong line numbers from warn/die calls inside try/catch blocks.
It does not support "finally" block.
It works on perl < 5.14
It does not support catching errors by their ISA (i.e. it has only one catch block that takes all errors and you must write additinal if/else code to rethrow other exceptions).
It does not support catching errors by their ISA (i.e. it has only one catch block that takes all errors and you must write additinal if/else code to rethrow other exceptions).
It generates expression (instead of statement), i.e. it requires semicolon after last block. Missing semicolon before or after try/catch expression may be hard to debug (it is not always reported as syntax error).
It works on perl < 5.14 (It is written in pure perl).
GIT REPOSITORY
http://github.com/tomas-zemres/syntax-feature-try
AUTHOR
Tomas Pokorny <tnt at cpan dot org>
COPYRIGHT AND LICENCE
Copyright 2013 - Tomas Pokorny.
This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.