HTML-Macro
view release on metacpan or search on metacpan
</else>
</if>
or simply
<if expr="perl expression">
HTML block 1
</if>
Conditional tags are processed by evaluating the value of the "expr"
attribute as a perl expression. The entire conditional tag structure is
replaced by the HTML in the first block if the expression is true, or the
second block (or nothing if there is no else clause) if the expressin is
false.
Conditional expressions are subject to variable substitution, allowing for
constructs such as:
You have #NUM_ITEMS# item<if "#NUM_THINGS# > 1">s</if> in your basket.
=head2 ifdef
HTML::Macro also provides the <if def="variable-name"> conditional. This
construct evaluates to true if variable-name is defined and has a true
value. It might have been better to name this something different like <if
set="variable"> ? Sometimes there is a need for if (defined (variable)) in
the perl sense. Also we occasionally want <if ndef="var"> but just use <if
def="var"><else/> instead which seems adequate if a little clumsy.
=head1 File Interpolation
It is often helpful to structure HTML by separating commonly-used chunks
(headers, footers, etc) into separate files. HTML::Macro provides the
<include /> tag for this purpose. Markup such as <include file="file.html"
/> gets replaced by the contents of file.html, which is itself subject to
evaluation by HTML::Macro. If the "asis" attribute is present: <include/
file="quoteme.html" asis>, the file is included "as is"; without any
further evaluation.
HTML::Macro also supports an include path. This allows common "part" files
to be placed in a single central directory. HTML::Macro::push_incpath adds
to the path, as in $htm->push_incpath ("/path/to/include/files"). The
current directory (of the file being processed) is always checked first,
followed by each directory on the incpath. When paths are added to the
incpath they are always converted to absolute paths, relative to the
working directory of the invoking script. Thus, if your script is running
in "/cgi-bin" and calls push_incpath("include"), this adds
"/cgi-bin/include" to the incpath. (Note that HTML::Macro never calls chdir
as part of an effort to be thread-safe).
Also note that during the processing of an included file, the folder in
which the included file resides is pushed on to the incpath. This means
that relative includes work as you would expect in included files; a file
found in a directory relative to the included file takes precedence over
one found in a directory relative to the including file (or HTML::Macros
global incpath).
=head1 Loops
The <loop> tag and the corresponding HTML::Macro::Loop object provide
for repeated blocks of HTML, with subsequent iterations evaluated in
different contexts. Typically you will want to select rows from a database
(lines from a file, files from a directory, etc), and present each
iteration in succession using identical markup. You do this by creating a
<loop> tag in your template file containing the markup to be repeated, and
by creating a correspondingly named Loop object attached to the HTML::Macro
and containing all the data to be interpolated. Note: this requires all
data to be fetched and stored before it is applied to the template; there
is no facility for streaming data. For the intended use this is not a
problem. However it militates against using HTML::Macro for text
processing of very large datasets.
<loop id="people">
<tr><td>#first_name# #last_name#</td><td>#email#</td></tr>
</loop>
The loop tag allows the single attribute "id" which can be any
identifier. Loop tags may be nested. If during processing no matching
loop object is found, a warning is produced and the tag is simply
ignored.
$htm = new HTML::Macro;
$loop = $htm->new_loop('people', 'id', 'first_name', 'last_name', 'email');
$loop->push_array (1, 'frank', 'jones', 'frank@hotmail.com');
Create a loop object using HTML::Macro::new_loop (or
HTML::Macro::Loop::new_loop for a nested loop). The first argument is
the id of the loop and must match the id attribute of a tag in the
template (the match is case sensitive). The remaining arguments are the
names of loop variables.
Append loop iterations (rows) by calling push_array with an array of
values corresponding to the loop variables declared when the loop was
created.
An alternative is to use push_hash, which is analogous to
HTML::Macro::set_hash; it sets up multiple variable substitutions. If you
use push_hash you don't have to declare the names of the variables when you
create the loop object. This allows them to be taken out of a hash and
bound late, for example by names returned in a database query.
pushall_arrays is a shortcut that allows a number of loop iterations to
be pushed at once. It is typically used in conjunction with
DBI::selectall_arrayref.
is_empty returns a true value iff the loop has at least one row.
keys returns a list of variable names defined in the (last row of the)
loop.
=head1 Eval
<eval expr="perl expression"> ... </eval>
You can evaluate arbitrary perl expressions (as long as you can place
them in an XML attribute between double quotes!). The expression is
subject to macro substition, placed in a block and invoked as an
anonymous function whose single argument is an HTML::Macro object
representing the nested scope. Any values set in the perl expression
thus affect the markup inside the eval tag. The perl is evaluated after
setting the package to the HTML::Macro caller's package.
Note: typically we only use this to make a function call, and it would
probably be more efficient to optimize for that case - look for the
special case <eval function=""> to be implemented soon. Also we might
like to provide a singleton eval that would operate in the current scope:
<eval function="perl_function" />.
=head1 Scope
Each of the tags include, eval and loop introduce a nested "local" lexical
scope. Within a nested scope, a macro definition overrides any same-named
macro in the enclosing scope and the value of the macro outside the nested
scope is unaffected. This is generally the expected behavior and makes it
possible to write modular code.
Sometimes desirable to set values at a global scope when operating in a
nested scope. You do this using set_global. set_global is totally
analogous to set, but sets values in the outermost scope, whatever the
current scope.
Another related function is set_ovalue. Set_ovalue sets values in a
parallel scope that takes precedence over the default scope (think
"overridding" value). We use set_ovalue to place request variables in a
privileged scope so that their values override values fetched from the
datbase. Each nested lexical scope really contains two name spaces -
values and ovalues, with ovalues taking precedence. However, an inner
scope always takes precedence over an outer scope.
element Variable substitution
within a loop follows the rule that loop keys take precedence over "global"
variables set by the enclosing page (or any outer loop(s)).
=head1 Define
You can set the value of a variable using the <define /> tag which requires
two attributes: name and value. This is only occasionally useful since
mostly we set variable values in perl. An example might be setting a value
that is constant in an outer context but variable in an inner context, such
as a navigation state:
( run in 1.769 second using v1.01-cache-2.11-cpan-71847e10f99 )