id:lestrratさんの
http://perl-users.jp/articles/advent-calendar/2008/03.html
を読んで。
そういや、つけたり、つけなかったりしてた...特にポリシーもなく。
全部につける必要はないとのことですが、つけてテストを書いたらはまった。
書いたコードを単純化すると、
eval { xxx(); }; print $@ =~/Undefined Subroutine/ ? "ok\n" : "not ok\n# $@\n"; sub xxx { local $@; eval { use Ktat::DummyModule; }; if ($@) { die "Got exception: $@"; } }
Ktat::DummyFunc()がないというエラーが出るのを確かめるテストだったのだが、取れない。
出力するには。xxx を下記のように変更する必要がある。
sub xxx { my $err; { local $@; eval { Ktat::DummyFunc(); }; $err = $@; } if ($err) { die "Got exception: $err"; } }
要するに、local $@; と同一スコープで例外吐いてはいけない、ということ。
local $@と同一スコープの例外も同じ$@には入るため、当然、スコープを抜けた時点で、$@の値が消える。
なので、それをさらに evalしたようなコードでは、$@の値を取得できなくなってしまう。
まぁ、確かに当たり前なんだがー...意識してないとよろしくないですね。
DBD::Proxyにこんなコードがありました。こんなんでもいいですね。
http://www.google.com/codesearch?hl=ja&q=%22local+%24%40%22+die+show:VQ_zqwVcauw:X5g8WUd-O6k:nHF7_TZer6k&sa=N&cd=1&ct=rc&cs_p=http://www.cpan.org/authors/id/T/TI/TIMB/DBI-1.55.tar.gz&cs_f=DBI-1.55/lib/DBD/Proxy.pm#l281
286: local $SIG{__DIE__} = 'DEFAULT'; my $err = do { local $@; eval $method_code.2; $@ }; die $err if $err;