Мне нужна возможность добавлять действия в конец лексического блока, где действие может умереть. И мне нужно, чтобы исключение было выбрано нормально и чтобы его можно было нормально поймать.
К сожалению, особые случаи исключений Perl во время DESTROY как путем добавления «(in cleanup)») к сообщению, так и с целью сделать их недоступными для отслеживания. Например:
{
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 из-за способа, который изменяет стек.