Как я могу удалить переменную в Template Toolkit?

Глядя на раздел Template::Manual::VMethods руководства по Template Toolkit, я не не вижу никакого метода, делающего это. Также не работает присвоение undef переменной - variable.defined возвращает true постфактум.


person Piotr Dobrogost    schedule 29.09.2011    source источник


Ответы (2)


Что ж, гугление "delete variable" site:mail.template-toolkit.org/pipermail/templates/ принесло вопрос [Templates] Могу ли я «УДАЛИТЬ some_var ”? от Фелипе Гаспера с двумя ответами от Петра Данихлика. Петр предлагает:

[% SET foo = 1 %]
[% IF foo.defined %] defined1 [% END %]
[% PERL %]
delete($stash->{foo});
[% END %]
[% IF foo.defined %] defined2 [% END %]
person Piotr Dobrogost    schedule 29.09.2011
comment
Интересный. Когда мы используем ссылки из тайника (Catalyst?) в шаблонах ТТ, мы пишем [% var %] вместо [% stash.var %]. Мне интересно, пробовали ли вы уже возиться с [% stash.var %]. - person Marco De Lellis; 29.09.2011
comment
Ссылка на переменную таким образом не дает никаких новых возможностей, не так ли? Я не могу использовать директиву PERL, как показано в ответе, который я нашел, потому что процессор TT, который я использую, не допускает встроенный Perl. - person Piotr Dobrogost; 29.09.2011

Я просмотрел Catalyst::View: TT код, чтобы понять контекст переменных.

Следующая подпрограмма, которую я немного обобщил, выполняет рендеринг:

sub render {
    my ( $self, $c, $template, $args ) = @_;
    # [...]
    my $output;    # Template rendering will end here
    # Variables interpolated by TT process() are passed inside an hashref
    # as copies.
    my $vars = {
        ( ref $args eq 'HASH' ? %$args : %{ $c->stash() } ),
        $self->template_vars( $c )
    };
    # [...]
    unless ( $self->template->process( $template, $vars, \$output ) ) { 
        # [ ... ]
    }
    # [ ... ]
    return $output;
}

TT process() вызывается с копиями переменных в $c->stash, так зачем нам возиться с $c->stash, чтобы избавиться от локальной копии? Может быть, мы не делаем.

Более того, TT define() VMethod, как и другие методы, похоже, был создан для списков. Скаляры автоматически повышаются до списка с одним элементом, когда к ним вызывается VMethod: возможно, по этой причине тест IF всегда возвращает true.

Я провел несколько тестов с переменными, содержащими ссылки на объекты DBIx::Class::ResultSet, и это, похоже, работает при тестировании переменной:

[%- resultset_rs = undef %]
[%- IF ( resultset_rs ) %]
    <h3>defined</h3>
[%- END %]

Первая строка удаляет переменную, а вторая выполняет правильную проверку.

ОБНОВЛЕНИЕ

Если вы можете добавить флаг EVAL_PERL => 1 в свой Catalyst View, внутри аргументов config(),

__PACKAGE__->config({
    # ...
    EVAL_PERL => 1
});

затем вы можете использовать директиву [% RAWPERL %] в шаблонах, которая дает вам прямой доступ к объекту Template::Context: тогда вы можете удалить переменные, и .defined() VMethod сделает все правильно.

[%- RAWPERL %]
    delete $context->stash->{ 'resultset_rs' };
[%- END %]
[%- IF ( resultset_rs.defined ) %]
    <h3>defined: [% resultset_rs %]<h3>
[%- ELSE %]
    <h3>undefined: [% resultset_rs %]<h3>
[%- END %]
person Marco De Lellis    schedule 29.09.2011
comment
Какую переменную вы пытаетесь undef? Массив, скаляр? - person Marco De Lellis; 29.09.2011
comment
И не работает? Можете ли вы опубликовать часть своего кода с неожиданным поведением? - person Marco De Lellis; 29.09.2011
comment
Это не работает, так как проверяет не определена ли переменная, а истинно ли она. Моя переменная обозначает размер в пикселях, поэтому она может иметь значение 0, которое является ложным в логическом контексте. - person Piotr Dobrogost; 29.09.2011
comment
В разделе документации Directives/RAWPERL говорится: Синтаксический анализатор Template Toolkit считывает исходный шаблон и генерирует текст подпрограммы Perl в качестве вывода. Затем он использует eval() для преобразования его в ссылку на подпрограмму. Возможно, это препятствует прямому доступу к переменным hashref, если только мы не поместим код в блок [% RAWPERL %]. - person Marco De Lellis; 29.09.2011
comment
Чем код в вашем обновлении отличается от кода, показанного в моем ответе? - person Piotr Dobrogost; 29.09.2011
comment
Ну, вы можете найти (небольшое) отличие, написанное в руководстве, где говорится, что [% RAWPERL %] более эффективен, чем [% PERL %]: Директива RAWPERL позволяет вам писать код Perl, который интегрируется непосредственно в сгенерированный текст подпрограммы Perl. Он оценивается один раз во время компиляции и сохраняется в кэшированной форме как часть подпрограммы скомпилированного шаблона. Это делает блоки RAWPERL более эффективными, чем блоки PERL. Я думаю, вы должны принять свой собственный ответ, который был хорошей возможностью заглянуть под прикрытие TT. - person Marco De Lellis; 30.09.2011