# find labeled blocks in the argument list.
# catch and finally tag the blocks by blessing a scalar reference to them.
foreach my $code_ref (@code_refs) {
- next unless $code_ref;
- my $ref = ref($code_ref);
-
- if ( $ref eq 'Try::Tiny::Catch' ) {
+ if ( ref($code_ref) eq 'Try::Tiny::Catch' ) {
+ croak 'A try() may not be followed by multiple catch() blocks'
+ if $catch;
$catch = ${$code_ref};
- } elsif ( $ref eq 'Try::Tiny::Finally' ) {
+ } elsif ( ref($code_ref) eq 'Try::Tiny::Finally' ) {
push @finally, ${$code_ref};
} else {
- confess("Unknown code ref type given '${ref}'. Check your usage & try again");
+ croak(
+ 'try() encountered an unexpected argument ('
+ . ( defined $code_ref ? $code_ref : 'undef' )
+ . ') - perhaps a missing semi-colon before or'
+ );
}
}
sub catch (&;@) {
my ( $block, @rest ) = @_;
+ croak 'Useless bare catch()' unless defined wantarray;
+
return (
bless(\$block, 'Try::Tiny::Catch'),
@rest,
sub finally (&;@) {
my ( $block, @rest ) = @_;
+ croak 'Useless bare finally()' unless defined wantarray;
+
return (
bless(\$block, 'Try::Tiny::Finally'),
@rest,
package # hide from PAUSE
Try::Tiny::ScopeGuard;
+ use constant UNSTABLE_DOLLARAT => ($] < '5.013002') ? 1 : 0;
+
sub _new {
shift;
bless [ @_ ];
}
sub DESTROY {
- my @guts = @{ shift() };
- my $code = shift @guts;
- $code->(@guts);
+ my ($code, @args) = @{ $_[0] };
+
+ local $@ if UNSTABLE_DOLLARAT;
+ eval {
+ $code->(@args);
+ 1;
+ } or do {
+ warn
+ "Execution of finally() block $code resulted in an exception, which "
+ . '*CAN NOT BE PROPAGATED* due to fundamental limitations of Perl. '
+ . 'Your program will continue as if this event never took place. '
+ . "Original exception text follows:\n\n"
+ . (defined $@ ? $@ : '$@ left undefined...')
+ . "\n"
+ ;
+ }
}
}
Once all execution is finished then the C<finally> block, if given, will execute.
-=item catch (&;$)
+=item catch (&;@)
Intended to be used in the second argument position of C<try>.
local $@ = $_;
-=item finally (&;$)
+=item finally (&;@)
try { ... }
catch { ... }
not do anything about handling possible errors coming from code located in these
blocks.
+Furthermore B<exceptions in C<finally> blocks are not trappable and are unable
+to influence the execution of your program>. This is due to limitation of
+C<DESTROY>-based scope guards, which C<finally> is implemented on top of. This
+may change in a future version of Try::Tiny.
+
In the same way C<catch()> blesses the code reference this subroutine does the same
except it bless them as C<Try::Tiny::Finally>.
I gave a lightning talk about this module, you can see the slides (Firefox
only):
-L<http://nothingmuch.woobling.org/talks/takahashi.xul?data=yapc_asia_2009/try_tiny.txt>
+L<web.archive.org/web/20100628040134/http://nothingmuch.woobling.org/talks/takahashi.xul>
Or read the source:
-L<http://nothingmuch.woobling.org/talks/yapc_asia_2009/try_tiny.yml>
+L<http://web.archive.org/web/20100305133605/http://nothingmuch.woobling.org/talks/yapc_asia_2009/try_tiny.yml>
=head1 VERSION CONTROL