アクションが終了する可能性のあるレキシカル ブロックの末尾にアクションを追加する機能が必要です。そして、例外が正常にスローされ、正常にキャッチされる必要があります。
残念ながら、メッセージに "(in cleanup)" を追加し、それらをトラップできないようにすることで、DESTROY 中に Perl の特殊なケースの例外が発生します。例えば:
{
package Guard;
use strict;
use warnings;
sub new {
my $class = shift;
my $code = shift;
return bless $code, $class;
}
sub DESTROY {
my $self = shift;
$self->();
}
}
use Test::More tests => 2;
my $guard_triggered = 0;
ok !eval {
my $guard = Guard->new(
#line 24
sub {
$guard_triggered++;
die "En guarde!"
}
);
1;
}, "the guard died";
is $@, "En guarde! at $@ line 24\n", "with the right error message";
is $guard_triggered, 1, "the guard worked";
私はそれを渡したい。現在、例外は eval によって完全に飲み込まれています。
これは Test::Builder2 用なので、純粋な Perl しか使用できません。
根本的な問題は、次のようなコードがあることです。
{
$self->setup;
$user_code->();
$self->cleanup;
}
$user_code が死んでも、そのクリーンアップは行われなければなりません。さもなければ、$self は奇妙な状態になります。だから私はこれをしました:
{
$self->setup;
my $guard = Guard->new(sub { $self->cleanup });
$user_code->();
}
複雑なのは、クリーンアップが任意のユーザー コードを実行し、そのコードが停止するユース ケースであるためです。その例外はトラップ可能であり、ガードによって変更されないことを期待しています。
スタックを変更する方法があるため、すべてを eval ブロックにラップすることは避けています。