I'm trying to use perl Text::Template for s开发者_如何学运维hort templates and so far failed to get it to iterate over an array.
Here is a short test program I wrote to demonstrate what I'm trying to do:
#!/usr/bin/perl
use Text::Template;
my $template = Text::Template->new(TYPE => 'STRING', SOURCE => <<'__EOT__');
array[0]: { $array[0] }
{ foreach my $i (@array) { }
{$i}
}
__EOT__
print $template->fill_in(HASH => { array => [qw(item1 item2)]});
According to the Text::Template manual I expected this to print: array[0]: item1 item1 item2 But instead it prints array[0]: item1
(i.e. the output of the first line outside the loop and an empty line).
I couldn't find anywhere on the web any example of someone actually using a loop inside a template, though the documentation says it should "just work".
What am I missing?
my $template = Text::Template->new(TYPE => 'STRING', SOURCE => <<'__EOT__', DELIMITERS => [qw(<% %>)],);
Pick different delimiters. The documentation advises you to do so several times for various reasons, mostly for being easier to work with because Perl code also uses {}
braces. It also says:
Because the parsing of templates is simplified by the absence of backslash escapes, using alternative DELIMITERS may speed up the parsing process by 20-25%. This shows that my original choice of { and } was very bad.
Just {$i}
does not work here because it is in void context. The documentation says:
The result of the last statement executed will be evaluted in scalar context; the result of this statement is a string, which is interpolated into the template in place of the program fragment itself.
Rewrite it with the $OUT
variable:
<% foreach my $i (@array) {
$OUT .= $i
} %>
The documentation says:
Anything you append to this variable will appear in the output of the template. Also, if you use $OUT in a program fragment, the normal behavior, of replacing the fragment with its return value, is disabled; instead the fragment is replaced with the value of $OUT.
<% $OUT .= $_ for @array %>
Same result, but shorter.
A couple of experiments indicate that this:
{ stuff }
Is turned into (effectively) something like this pseudo-perl:
my $x = eval(stuff);
$template =~ s/{ stuff }/$x/;
So the "stuff" needs to be an expression so that it returns something to put into the template. Your "stuff" is a foreach
loop which doesn't have a value so your template doesn't do anything interesting.
If you look at the tests for Text::Template
(always go to the test suite for examples, the test suites for CPAN packages are invaluable for learning how things work), you'll see things like this:
{ $t = ''; foreach $n (1 .. 20) { $t .= $n . ' ' } $t }
Note the way $t
is being used. That indicates that you want something more like this for your template:
array[0]: { $array[0] }
{ $t = ''; foreach my $i (@array) { $t .= "\t$i\n" } }
There's also the $OUT
special variable which can take the place of $t
above. The documentation for CPAN packages is generally pretty good and well worth reading, you'll miss it when you work in other languages.
精彩评论