From: Yuval Kogman Date: Fri, 11 Sep 2009 17:52:41 +0000 (+0900) Subject: Restore the value of $@ from before the local X-Git-Tag: Try-Tiny-0.03~12 X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=511c05caecd550023e029dcfdeb3995c64def4d9;p=p5sagit%2FTry-Tiny.git Restore the value of $@ from before the local This allows exception objects to be constructed with the previous value of $@, but that behavior would rely on Try::Tiny --- diff --git a/lib/Try/Tiny.pm b/lib/Try/Tiny.pm index dd6d466..e3fdf8d 100644 --- a/lib/Try/Tiny.pm +++ b/lib/Try/Tiny.pm @@ -23,6 +23,9 @@ sub try (&;$) { # to $failed my $wantarray = wantarray; + # save the value of $@ so we can set $@ back to it in the begining of the eval + my $prev_error = $@; + my ( @ret, $error, $failed ); # FIXME consider using local $SIG{__DIE__} to accumilate all errors. It's @@ -37,6 +40,7 @@ sub try (&;$) { # failed will be true if the eval dies, because 1 will not be returned # from the eval body $failed = not eval { + $@ = $prev_error; # evaluate the try block in the correct context if ( $wantarray ) { @@ -180,6 +184,13 @@ not yet handled. C<$@> must be properly localized before invoking C in order to avoid this issue. +More specifically, C<$@> is clobbered at the begining of the C, which +also makes it impossible to capture the previous error before you die (for +instance when making exception objects with error stacks). + +For this reason C will actually set C<$@> to its previous value (before +the localization) in the begining of the C block. + =head2 Localizing $@ silently masks errors Inside an eval block C behaves sort of like: diff --git a/t/basic.t b/t/basic.t index ebc4106..7f1471c 100644 --- a/t/basic.t +++ b/t/basic.t @@ -3,7 +3,7 @@ use strict; #use warnings; -use Test::More tests => 19; +use Test::More tests => 21; BEGIN { use_ok 'Try::Tiny' }; @@ -39,6 +39,8 @@ sub throws_ok (&$$) { } +my $prev; + lives_ok { try { die "foo"; @@ -125,3 +127,25 @@ sub Evil::new { bless { }, $_[0] } is( $@, "magic", '$@ untouched' ); is( $_, "other magic", '$_ untouched' ); } + +{ + my $caught; + + { + local $@; + + eval { die "bar\n" }; + + is( $@, "bar\n", 'previous value of $@' ); + + try { + die { + prev => $@, + } + } catch { + $caught = $_; + } + } + + is_deeply( $caught, { prev => "bar\n" }, 'previous value of $@ available for capture' ); +}