I needed a templating engine for a Perl script, but I couldn't install any modules, and I needed everything in one file. So, I wrote one in about 40 lines of Perl. Suitable for cut-n-paste into other projects.
See the updated version.It only has to be really simple. Normally I hate having to construct a hash-of-hash-of-hashes for template engines, but the data model was also simple.
- hash-of-hash data input
- scalar interpolation
- iterate on a list
- No "if," no "include"
- No escaping/quoting of interpolated values
- No literal $
- Efficient? Not very. For non-large templates.
- Safe? Not very: interpolated values could get re-processed.
Key technology: Perl 5.10 and Text::Balanced::extract_bracketed.
use strict; use warnings; no warnings 'uninitialized';
use Text::Balanced qw(extract_bracketed);
sub render {
my ($template, $data) = @_;
# replace $x with $data->{'x'}
# replace @x[...]
# with foreach my $x (@{$data->{'x'}}) { ... }
# repeats, 1st, recurse
my @rez;
# avoid $' with a split
while (my @repeats = split(/@(\w+)(?=\[)/, $template,2)) {
push @rez, $repeats[0];
last if ! $repeats[1];
my $field_name = $repeats[1];
# warn "During '\@$field_name'";
my $bracketed;
($bracketed, $template) = extract_bracketed( $repeats[2], '[');
$bracketed =~ s/^\[//;
$bracketed =~ s/\]$//;
# warn "To repeat '\@$field_name', ".@{$data->{$field_name}}." times";
foreach my $sub_data ( @{$data->{$field_name}} ) {
# recurse on this block with our block's data
push @rez, render( $bracketed, {%$data, %$sub_data});
}
# warn "Finished '\@$field_name'";
}
my $rez = join("",@rez);
# scalars
$rez =~ s/\$(\w+)/$data->{$1}/eg;
return $rez;
}
No comments:
Post a Comment
Be relevant. Be constructive.