package Sxoop::TinyTemplate;
our $VERSION = '0.01';
=head1 NAME
TinyTemplate - A Tiny Inline-Perl Template module with an execution model similar to JSP's.
Templates are strings which are converted to Perl code for evaluation.
=head1 SYNOPSIS
use Sxoop::TinyTemplate ':all';
print "Content-type: text/html\n\n";
#
# parse will convert a template (in the form of a string)
# into equivalent perl code. The following sample uses Perl's here document syntax...
#
eval parse <<'END';
[% foreach my $row ({name=>"Walter Higgins", address=>"Cork,Ireland"},
{name=>"John Doe", address=>"Surrey,England"})
{ %]
| [% print $row->{name};%] |
[% print $row->{address};%] |
[% } %]
END
=head1 DESCRIPTION
TinyTemplate is a tiny template system that parses a string and converts it into Perl code.
Inline perl code must be enclosed in [% %] markers.
For example:
[% if ($age > 65) { %]
Please avail of our special offer for Senior Citizens
[% } %]
You can send directives to the parser using [%! %] markers.
For example:
[%!include "header.html" %]
will include (and parse) the content of header.html.
Currently there is only one directive (include) supported.
Everything that isn't enclosed in [% %] will be printed in double-quotes (interpolated),
so to print a variable name ...
You are connected to $hostname
...This means that if you want to include an email address in your template you should
escape the @ character like so...
Contact
=head1 SAMPLE CODE
#!/usr/bin/perl
#
# A simple CGI program
#
use strict;
use Sxoop::TinyTemplate ':all';
print "Content-Type: text/html\n\n";
eval include "my_template.html";
exit;
Contents of my_template.html...
[%!include "header.html" %]
[% foreach my $person ({name=>"Jane Malone",
age=> 64,
address=>"Cork,Ireland"},
{name=>"John Doe",
age=> 68,
address=>"Surrey,England"}) { %]
| $person->{name} |
$person->{address} |
[% if ($person->{age} > 65) { %]
Please avail of our Senior Citizens Offers
[% } %]
|
[% } %]
Contents of header.html...
People List
=cut
use strict;
require Exporter;
our @ISA = ("Exporter");
our @EXPORT_OK = qw(parse include);
our %EXPORT_TAGS = (all => \@EXPORT_OK,);
sub prep_text
{
my ($text,$options) = @_;
$text =~ s/\\/\\\\/g; # \ => \\
$text =~ s/"/\\"/g; # " => "\""
$text =~ s/\$/\\\$/g;
$text =~ s/\@/\\\@/g;
if ($options->{debug} == 1){
my @lines = split /(\n)/, $text ;
my @perl_lines = map { s/\n/\\n/g; "print \"$_\";"} @lines;
@perl_lines;
}else{
$text =~ s/\n/\\n/g;
"print \"$text\";";
}
}
#
# Parse a string splitting it into tokens then
# joining it back to form a string which can be evaluated
# as perl code.
#
sub parse
{
my ($token_string,$options) = @_;
my @tokens = split /(\[%.*?)%\]/s, $token_string;
my @perl_statements = map {
my ( $enclosed, $directive, $text) = $_ =~ /(\[%)*(!)*(.+)/s;
if ($directive){
my $result = eval($text);
die "directive failed: could not evaluate $text\n$@" if $@;
$result;
}elsif ($enclosed){
if ($text =~ /^\%/){
$text =~ s/^\%//;
$text = "[%$text%]";
prep_text $text, $options;
}else{
$text;
}
}else{
prep_text $text, $options;
}
} grep /.+/, @tokens;
my $perl_block = join "\n", @perl_statements;
return $perl_block;
}
#
# Include content from another file for evaluation
#
sub include
{
my ($filename, $options) = @_;
open FILE, $filename or die "COULDN'T OPEN FILE $filename because $!\n";
my $contents = join '', ;
close FILE;
parse $contents, $options;
}
1;