template-toolkit: передача переменных массива в tpage из командной строки?

У меня этот шаблон работает правильно:

$ cat matrix.tt 
[% DEFAULT
    ncols = 3
    elems = [1,2,3,4,5,6,7,8,9]
%]
\left[\begin{matrix}
[% WHILE elems.size %]
    [% elems.splice(0,ncols).join(' & ') %]
    [% IF elems.size %]\\[% END %]
[% END %]
\end{matrix}\right]
$ tpage --pre_chomp --post_chomp matrix.tt 
\left[\begin{matrix}1 & 2 & 3\\4 & 5 & 6\\7 & 8 & 9\end{matrix}\right]

Но это не работает

$ tpage --define ncols=2 --define elems=[1,2,3,4] matrix.tt 
undef error - WHILE loop terminated (> 1000 iterations) 

Используя следующий код, я обнаружил, что нетривиально передавать массивы с помощью --define возможность tpage,

$ cat pk.tt 
[% DEFAULT 
    ho = [1,2]
-%]
ho is [% ho %]
po is [% po %]
$ tpage --define po=[1,3] pk.tt #I want po to be interpreted as an array
ho is ARRAY(0x1a3fd00)
po is [1,3]

Выходные данные показывают, что po является скаляром. Я хочу передать массивы из командной строки, есть ли способ сделать это?

3 ответа

Решение

Вот способ передать любые данные в tpage из командной строки без необходимости настраивать tpage источник или шаблон.

$ cat matrix.tt 
[% DEFAULT
    ncols = 3
    elems = [1,2,3,4,5,6,7,8,9,10,11,12]
%]
\left[\begin{matrix}
[% WHILE elems.size %]
    [% elems.splice(0,ncols).join(' & ') %]
    [% IF elems.size %]\\[% END %]
[% END %]
\end{matrix}\right]
$ cat <(echo '[% elems=["x","y","z",1,2,3] %]') matrix.tt |tpage --pre_chomp --post_chomp
\left[\begin{matrix}x & y & z\\1 & 2 & 3\end{matrix}\right]
$ 

или, если хотите, вы можете ввести директиву для установки переменных и нажать ^D:

$ rlwrap cat - matrix.tt |tpage --pre_chomp --post_chomp
[%
  ncols=4
  elems=[4,5,6,7,"x","y","z","t"]
%]
\left[\begin{matrix}4 & 5 & 6 & 7\\x & y & z & t\end{matrix}\right]
$

rlwrap сохраняет введенные вами строки и делает их доступными позже, нажав up ключ. Вы можете удалить rlwrap если тебе это не нужно

Метод работает с любой программой, которая может обрабатывать stdin данная оболочка поддерживает этот вид перенаправления. Я надеюсь, что это довольно портативно.

В зависимости от того, насколько сложными являются значения в вашем массиве, вы можете получить что-то вроде:

[%- el = elems.split(',') -%]
\left[\begin{matrix}
[% WHILE el.size %]
    [% el.splice(0,ncols).join(' & ') %]
... #etc

$ tpage --define ncols=2 --define elems="1,2,3,4" matrix.tt 

Но если конечно elems не контролируется или имеет встроенные метасимволы или запятые, которые могут привести к боли. Но в противном случае достаточно просто преобразовать скаляр в массив, используя .split() VMethod.

Аргументы командной строки для tpage не оцениваются как Perl-код, поэтому вы можете получить только строковые значения. Если вы хотите поддержать произвольный код Perl, вам нужно взломать tpage источник.


Найдите следующую строку в источнике:

my %ttopts   = $config->varlist('^template_(?!directive_)', 1);

На следующей строке добавьте следующий код:

foreach my $var (keys %{ $ttopts{variables} }) {
    $ttopts{variables}{$var} = eval $ttopts{variables}{$var};
    die $@ if $@;
}

Это перебирает все аргументы --define и звонки eval на них, преобразовывая их из строк в код Perl.

Когда вы запустите это, не забудьте процитировать ваши аргументы, чтобы защитить их от расширения оболочкой:

$ ./tpage --define 'array=["foo","bar"]' --define 'hash={baz=>"qux"}' foo.tt

$VAR1 = [
          'foo',
          'bar'
        ];

$VAR1 = {
          'baz' => 'qux'
        };

$ cat foo.tt
[% USE Dumper %]
[% Dumper.dump(array) %]
[% Dumper.dump(hash) %]

Чтобы передать буквальную строку, вы должны заключить ее в кавычки q{} или же qq{} потому что AppConfig удаляет обычные кавычки (tpage негласно использует AppConfig для чтения аргументов командной строки). Например:

$ ./tpage --define 'string=q{foo}' foo.tt 

$VAR1 = 'foo';

$ cat foo.tt
[% USE Dumper %]
[% Dumper.dump(string) %]

Обратите внимание, что хотя Template Toolkit поддерживает переменные практически любого типа Perl, моя модифицированная версия tpage не делает. Числа, строки, массивы и хэши должны все работать; подпрограммы нет.

Другие вопросы по тегам