NAME
dTemplate - A powerful template handling logic with advanced features.
SYNOPSIS
use dTemplate;
$mail_template = define dTemplate "mail_tmpl.txt";# definition
$mail = $mail_template->parse( # parsing
TO => "foo@bar.com",
SUBJECT => $subject,
BODY =>
sub { $email_type==3 ? $body_for_type_3 : $body_for_others },
SIGNATURE=> $signature_template->parse( KEY => "value" )
);
print "Please send this mail: $mail";
where mail_tmpl.txt is:
From : Me
To : $TO$
Subject : $SUBJECT$
Message body:
$BODY$
$SIGNATURE$
# Changing placeholder special characters:
$dTemplate::START_DELIMITER = '<%\s*'; # default: \$
$dTemplate::END_DELIMITER = '\s*%>'; # default: \$
$dTemplate::VAR_PATH_SEP = '\/'; # default: \.
$dTemplate::PRINTF_SEP = '\$'; # default: %+
$dTemplate::ENCODER_SEP = '\@'; # default: \*+
$dTemplate::ENCODER_PARAM_START = '\('; # default: \/
$dTemplate::ENCODER_PARAM_END = '\)'; # default:
# Advanced feature: Styling
$style={lang =>'hungarian',color=>'white'}; # Style definition
$html_template = choose dTemplate( $style, # Selector definition
'hungarian+white' =>
define dTemplate("hun_white_template.html"),
'spanish' =>
define dTemplate("spanish.html"),
'black+hungarian' =>
define dTemplate("hun_black_template.html"),
'english' =>
define dTemplate("english_template.html"),
'empty' =>
"This is a text, $BODY$ is NOT substituted!!!!"",
'' =>
text dTemplate "$BODY$", # default
);
$body_template= choose dTemplate( $style, # Selector definition
'hungarian' =>
define dTemplate("sziasztok_emberek.html"),
'spanish' =>
define dTemplate("adios_amigos.html"),
'' =>
define dTemplate("bye_bye.html"),
);
print $html_template->parse(BODY => $body_template->parse());
# will print "sziasztok_emberek.html" in the
#"hun_white_template.html"
%$style=();
print $html_template->parse(BODY => $body_template->parse());
# will print "bye_bye.html" surrounded by "" and "" tags.
%$style=( lang => 'english' );
print $html_template->parse(BODY => $body_template->parse());
# will print the "bye_bye.html" in of the "english_template.html"
DESCRIPTION
This module is aimed to be a simple, general-purpose, lightweight, but
very powerful templating system.
You can write template-parsing routines in the way the templates are
structured logically. Starting from the biggest to the smallest. Your
program code will be very clear, structured and easy to understand. This
logic can be attained by using inline subroutines as values of template
variables. (Look at the example at the end of the document)
USAGE
First, you need to know how a template looks like, then you need to know
how to define a template in a perl program, then you can parse it.
After that you can see how to make new encoders.
How a template looks like
A template is a simple text file, which contains template variable
placeholders.
The full format of a placeholder is:
$Template_Variable%printf_style_format_string*encoder1/par1*encoder2/par2$
Note: The special characters ($, % and *) can be changed, look below.
Where:
Template_Variable
It is a mandatory part of the placeholder. Can contain any
(locale-aware) alphanumeric characters and '.' .
%printf_style_format_string
This is an optional part. Used when you want to format the output.
You can use as many '%' as you want, it can be good to pad the
variable, for example when you parse a table. E.g: $MONEY%%%%%%011d$
is a valid placeholder.
This version can be used only before the encoders (because of
historical reasons) and if you need to use it other places in the
encoder chain, then you can use the "printf" encoder instead (see
below).
However you have a "printf" encoder since 2.2.2, this formatting
will be supported in the later versions because of the simple
syntax.
*encoder/par
There are predefined encoders in the module, which can be used to
format the input data. These are:
- u : url-encoder
- h : HTML-encoder (converts > to >, etc)
- ha : Advanced HTML encoder (\n =>
, tabs => spaces)
- uc : convert the string to uppercase
- lc : convert the string to lowercase
- eq/par : returns true if the encoded string is "par"
- if/par : returns "par" if the encoded string is true
- printf/par : returns printf formatted data, where "par" is the format
string
"/par" is an optional scalar parameter.
You can use zero or more of these:
$TITLE*uc*h$
or
$weight*eq/7*if/CHECKED$
(the last example returns CHECKED if the weight is equal to "7",
useful for radio-buttons or drop-down menus in HTML)
Read more on encoders (and how to make new encoders) in the Encoders
part.
Definition of a template
There are 3 ways to define a template.
$template = define dTemplate $filename
This reads the template from a file.
$template = text dTemplate $scalar
This creates a template from a scalar
$template = choose dTemplate $hash, "style1" => $template1, "style2" =>
...
It is the definition of the template chooser. It is the way how you
can create styled templates.
Parsing
Parsing means substituting the variables which are defined in the
template. It can be done by simply calling the "parse" method of a
dTemplate object.
The parameters of the "parse" method are the substitution definitions.
You can provide substitution parameters in two form:
- list of name => value pairs
- with a hash reference
You can mix them if you want:
$template->parse(
name => $value,
{ name2 => $value2, name3 => $value3 },
name4 => $value4,
{ name5 => $value5 },
...
)
The "value" can be:
scalar or scalar ref.
If a value is scalar, it will be substituted. Scalar refs can be
used to save some memory if you use them more than one time.
code reference ( sub { }, or \&subroutine )
The sub will be evaluated at each occurence of the template
variable.
hash
You can assign a hash to a template variable if you want. In this
way, you can use structured data in the templates, e.g you assign a
{ name => "Greg", "zip" => 111 } to the template variable "person",
and if you use "person.name" in the template, you will get "Greg"
back. Nesting (more "."-s) will also work.
You can use %dTemplate::parse hash to assign global parse parameters.
The return value of the parse method is a dTemplate::Scalar object,
which can be used as a simple scalar, but really it is a scalar
reference to save some memory. It is useful if you use large templates.
Encoders
The global hash, %dTemplate::ENCODERS contains the defined encoders.
The hash keys are the names, the values are subroutine references. These
subs get the encodable data as the first parameter and returns the
encoded value. The second parameter is the optional parameter, which can
provided by the "/" separator after the encoder name.
$dTemplate::parse{''}
$dTemplate::parse{''} is a special hash key in the %dTemplate::parse
hash. This value is parsed into the place of the unassigned variable.
By default, it is an empty scalar, so you won't even notice if you
forget to assign a variable.
If you want to be warned if a variable is not assigned, you can use the
following code reference:
use Carp qw(cluck);
$dTemplate::parse{''} = sub {
cluck "$_[0] is not assigned";
return "";
}
By this, the output of the further "parse" calls will call this sub if a
variable is not assigned.
Magical (tied) hashes
You can use magical hashes everywhere in the "parse" method parameter
list, where you can to use normal hashes, but because I redesign the
"parse" method with the speed with the first priority, it works quite a
bit different than the older ( <= 2.0 ) versions.
At template-compile time, the "compile" method collects the variable
names, which are found in that template, and the "parse" method knows
which variables are required for processing this template.
When the "parse" method realizes that the given parameter is a hash
reference, then it always tries all the remaining template variables
(which are not assigned in the preceding part of the parameter list) in
that hash reference.
Imagine the following situation:
$template->parse( name => "blow", \%hash);
... where %hash is a magical hash, and the $template contains the
"name", "address" and "method.type" variables. When the parse method
meets with the \%hash, the "name" is already assigned, so it olny tries
to read the $hash{address} and $hash{method} variables.
This is not a problem with normal hashes, but if you use magical hashes,
you may have a very expensive FETCH function, and this effect can cause
problems.
There are two way to work around it:
* Use qualified variable names. If you use the following form of
parse:
$template->parse( name => "blow", data => \%hash);
... then the %hash is called only when the template parser finds the
"data.address" and "data.method.type" variable references in the
template. Of course, you have to change the template variable names
also.
* Use the hash instead of a hash reference:
$template->parse( name => "blow", %hash);
In this case, the magical hash is iterated through when the
parameter list is assembled. This is better only if you are afraid
of random key retrieval, but it can be also slow, if the FIRSTKEY,
NEXTKEY and FETCH operations are slow.
But if the random-key retrieval is not a problem for your magical
hash, then use the default form instead of this, because that
requires less operation (only one FETCH).
Changing placeholder special characters
You can change the placeholder parameters by changing (or localizing)
the following variables.
$dTemplate::START_DELIMITER = '\$';
$dTemplate::END_DELIMITER = '\$';
$dTemplate::VAR_PATH_SEP = '\.';
$dTemplate::PRINTF_SEP = '%+';
$dTemplate::ENCODER_SEP = '\*';
$dTemplate::ENCODER_PARAM_START = '\/';
$dTemplate::ENCODER_PARAM_END = '';
If you change these variables, then these are used in the compilation of
the following templates. Currently there is no supported way to
recompile an already compiled template, so you need to create a new
instance.
Although if you want to compile a variable, which is not compiled, then
you can call the $template->compile method on them by hand.
These variables can be set to any regular expressions, not just one
single character.
If you don't want to use any of the features, then set the corresponding
variable to any regexp that is too complex to be true.
HINTS
* In the first parse of every template, the templates will be
compiled. It is used to speed up parsing.
* Don't forget that %dTemplate::parse can be localized. This means you
can define local-only variable assignments in a subroutine:
local %dTemplate::parse=(
%dTemplate::parse,
local_name => $value
);
* You don't need to use text as the input value of an encoder, you can
use any scalar, even referenes! If you want (for example) print a
date by a date encoder, which expects the date to be an array ref of
[ year, month, day ], then you can do this, e.g:
$dTemplate::ENCODERS{date}=sub {
return "" if ref($_[0]) ne 'ARRAY';
return $_[0]->[0]."-".$_[0]->[1]."-".$_[0]->[2];
}
Then, when you put $START_DATE*date$ to a template, you can parse
this template:
$template->parse(
START_DATE => [2000,11,13],
...
);
EXAMPLE
It is an example, which contains most of the features this module has.
It is not intended to be a real-world example, but it can show the usage
of this module.
This example consists of one program, and some template modules.
The executable version of this program can be found in the example
directory of the module distribution.
use dTemplate;
### definition of the standard templates
my @TEMPLATE_LIST=qw(page table_row table_cell);
my $templates={};
foreach my $template (@TEMPLATE_LIST) {
$templates->{$template} =
define dTemplate("templates/$template.htm");
}
### definition of the styled templates (styles = languages)
my @STYLES=qw(eng hun);
my @STYLED_TEMPLATE_LIST=qw(table_title);
my $style_select={ lang => 'hun' };
foreach my $template (@STYLED_TEMPLATE_LIST) {
my @array=();
foreach my $style (@STYLES) {
push @array, $style =>
define dTemplate("text/$style/$template.txt");
}
$templates->{$template} =
choose dTemplate $style_select, @array;
}
### setting up input data
my $table_to_print=[
[ "Buwam", 3, 6, 9 ],
[ "Greg", 8, 4, 2 ],
[ "You're", 8, 3, 4 ],
[ "HTML chars: <>", 3],
];
### setting up the global parse hash with parse parameters;
$dTemplate::parse{PAGENO}=7;
### settings up a hash with personal data.
my $person_hash={
name => { first_name => "Greg" },
zip => "9971",
};
### this hash is simply added to other parse parameters
my $parse_hash={
"unknown" => { data => 157 },
};
### the main page parse routine
print $templates->{page}->parse(
TABLE_TITLE => # name => value pair
$templates->{table_title}->parse(),
TABLE => sub { # name => value pair. value is a sub
my $ret="";
foreach my $row (@$table_to_print) {
$ret .= $templates->{table_row}->parse(
BODY => sub {
my $ret="";
foreach my $cell (@$row) {
$ret .= $templates->{table_cell}->parse(
TEXT => $cell,
)
}
return $ret;
}
)
}
return $ret;
},
"person" => $person_hash, # name => value pair. value is a href
$parse_hash, # only a hash with parse parameters
);
And the templates:
templates/page.htm: