模板工具包:从命令行将数组变量传递到 tpage?

template-toolkit: passing array variables into tpage from command line?

我可以正常使用此模板:

$ 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 是一个标量。我想从命令行传递数组,有什么办法吗?

根据数组中值的复杂程度,您也许可以摆脱这样的情况:

[%- 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 代码。

当你 运行 这样做时,请确保引用你的论点以防止它们被 shell:

扩展
$ ./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 版本不支持。数字、字符串、数组和散列应该都可以工作;子程序没有。

这是一种从命令行将任何数据传递到 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

如果 shell 支持这种重定向,该方法适用于任何可以处理 stdin 的程序。我希望它很便携。