template-toolkit:从命令行将数组变量传递给tpage?

时间:2016-01-14 08:19:24

标签: perl templates command-line template-toolkit

我让这个模板正常工作:

$ 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 个答案:

答案 0 :(得分:1)

根据数组中值的复杂程度,您可以使用以下内容:

[%- 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将标量提升为数组非常简单。

答案 1 :(得分:1)

以下是一种从命令行将任何数据传递到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的程序,因为shell支持这种重定向。我希望它非常便携。

答案 2 :(得分:0)

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修改版本并不适用。数字,字符串,数组和散列都应该起作用;子程序不是。