将Tie :: IxHash对象传递给Template模块

时间:2016-07-27 02:37:31

标签: perl

我使用的是Perl v5.18.2。

我希望使用Perl的Template模块按顺序打印哈希元素,但哈希值似乎只有在传递给Template之后才会被排序。

use strict;
use warnings;

use Tie::IxHash;
use Template;
use Test::More;

tie my %hash, 'Tie::IxHash';
%hash = ('one' => 1, 'two' => 2, 'three' => 3);
my %vars = ('hash' => \%hash); 

is_deeply(\[keys $vars{'hash'}], \['one', 'two', 'three'], 'key order');
is_deeply(\[values $vars{'hash'}], \[1, 2, 3], 'value order');

my $t = Template->new(STRICT => 1) || die(Template->error());
my $template = '[% FOREACH k IN hash %][% k.value %][% END %]';
my $output = '';

$t->process(\$template, \%vars, \$output) || die $t->error();

is($output, '123', 'templatized hash order');

done_testing(3);

这总是失败:

ok 1 - key order
ok 2 - value order
not ok 3 - templatized hash order
#   Failed test 'templatized hash order'
#   at t/wtf.t line 18.
#          got: '132'
#     expected: '123'
1..3
# Looks like you failed 1 test of 3.

我在这里缺少什么?如何在模板中保留哈希元素顺序?

2 个答案:

答案 0 :(得分:1)

绑定的哈希在传递给不使用绑定哈希的模板工具包时会丢失其魔力,而是生成它的纯文本副本。要解决这个问题,您可以存储并传递您的密钥顺序,并使用它来按顺序提取哈希元素。

#!/usr/bin/env perl 
use strict;
use warnings;
use Tie::IxHash;
use Template;
use Test::More;

tie my %hash, 'Tie::IxHash';
%hash = ('one' => 1, 'two' => 2, 'three' => 3);
is_deeply([keys %hash], ['one', 'two', 'three'], 'key order');
is_deeply([values %hash], [1, 2, 3], 'value order');
my @key_order = keys %hash;
my %vars = ( 'hash' => \%hash, key_order => \@key_order );

my $t = Template->new(STRICT => 1) || die(Template->error());
my $template = '[% FOREACH k IN key_order %][% hash.$k %][% END %]';
my $output = '';
$t->process(\$template, \%vars, \$output) || die $t->error();
is($output, '123', 'templatized hash order');
done_testing(3);

<强>输出

ok 1 - key order
ok 2 - value order
ok 3 - templatized hash order
1..3

答案 1 :(得分:1)

你不能那样做

当您在process对象上调用Template方法时,您在%vars参数中传递的值将复制到之前的普通数据结构中它们用于构建文档

显而易见的替代方法是在调用process之前将哈希键收集到数组中,并将其作为%vars参数的另一个元素传递。该计划显示了这个想法

use strict;
use warnings 'all';

use Tie::IxHash;
use Template;

tie my %hash, 'Tie::IxHash';
%hash = (one => 1, two => 2, three => 3);


my @keys = keys %hash;
my %vars = (hash => \%hash, keys => \@keys); 

my $t = Template->new(STRICT => 1) or die Template->error;

my $template = <<'END_TEMPLATE';
[% FOREACH k IN keys %][% hash.$k %]
[% END %]
END_TEMPLATE

my $output;
$t->process(\$template, \%vars, \$output) or die $t->error;

print $output;

输出

1
2
3

当然,这首先消除了使用Tie::IxHash的大部分要点,使用带有并行数组键的普通哈希可能会更好