Нужен конец действия в лексической области, которое может умереть нормально

Мне нужна возможность добавлять действия в конец лексического блока, где действие может умереть. И мне нужно, чтобы исключение было выбрано нормально и чтобы его можно было нормально поймать.

К сожалению, особые случаи исключений 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 из-за способа, который изменяет стек.

7
задан Schwern 5 January 2011 в 23:49
поделиться