App::Followme::Template - Handle templates and prototype files
use App::Followme::Template; my $template = App::Followme::Template->new; my $render = $template->compile($prototype_file, $template_file); my $output = $render->($hash);
This module contains the methods that perform template handling. A Template is a file containing commands and variables for making a web page. First, the template is compiled into a subroutine and then the subroutine is called with a hash as an argument to fill in the variables and produce a web page.
This module has one public method:
Combine a prototype file and a template, compile them, and return the compiled subroutine. The prototype is the most recently modified file in the directory. A template if a file containing commands and variables that describe how data is to be represented. The method returns a subroutine reference, which when called with a reference to a hash, returns a web page containing the data in the hash. fields in the hash are substituted into variables in the template. Variables in the template are preceded by Perl sigils, so that a link would look like:
Templates support the control structures in Perl: "for" and "while" loops, "if-else" blocks, and some others. Creating output is a two step process. First you generate a subroutine from one or more templates, then you call the subroutine with your data to generate the output.
The template format is line oriented. Commands are enclosed in html comments (<!-- -->). A command may be preceded by white space. If a command is a block command, it is terminated by the word "end" followed by the command name. For example, the "for" command is terminated by an "endfor" command and the "if" command by an "endif" command.
All lines may contain variables. As in Perl, variables are a sigil character ('$,' '@,' or '%') followed by one or more word characters. For example,
@names. To indicate a literal character instead of a variable, precede the sigil with a backslash. When you run the subroutine that this module generates, you pass it a reference, usually a reference to a hash, containing some data. The subroutine replaces variables in the template with the value in the field of the same name in the hash. If the types of the two disagree, the code will coerce the data to the type of the sigil. You can pass a reference to an array instead of a hash to the subroutine this module generates. If you do, the template will use
@data to refer to the array.
If the first non-white characters on a line are the command start string, the line is interpreted as a command. The command name continues up to the first white space character. The text following the initial span of white space is the command argument. The argument continues up to the command end string, or if this is empty, to the end of the line.
Variables in the template have the same format as ordinary Perl variables, a string of word characters starting with a sigil character. for example,
$SUMMARY @data %dictionary
are examples of variables. The subroutine this module generates will substitute values in the data it is passed for the variables in the template. New variables can be added with the "set" command.
Arrays and hashes are rendered as unordered lists and definition lists when interpolating them. This is done recursively, so arbitrary structures can be rendered. This is mostly intended for debugging, as it does not provide fine control over how the structures are rendered. For finer control, use the commands described below so that the scalar fields in the structures can be accessed. Undefined fields are replaced with the empty string when rendering. If the type of data passed to the subroutine differs from the sigil on the variable the variable is coerced to the type of the sigil. This works the same as an assignment. If an array is referenced as a scalar, the length of the array is output.
The following commands are supported in templates:
The remainder of the line is interpreted as Perl code. For assignments, use the set command.
The text until the matching
endif is included only if the expression in the "if" command is true. If false, the text is skipped. The "if" command can contain an
else, in which case the text before the "else" is included if the expression in the "if" command is true and the text after the "else" is included if it is false. You can also place an "elsif" command in the "if" block, which includes the following text if its expression is true.
<!-- if $highlight eq 'y' --> <em>$text</em> <!-- else --> $text <!-- endif -->
Expand the text between the "for" and "endfor" commands several times. The "for" command takes a name of a field in a hash as its argument. The value of this name should be a reference to a list. It will expand the text in the for block once for each element in the list. Within the "for" block, any element of the list is accessible. This is especially useful for displaying lists of hashes. For example, suppose the data field name phonelist points to an array. This array is a list of hashes, and each hash has two entries, name and phone. Then the code
<!-- for @phonelist --> <p>$name<br> $phone</p> <!-- endfor -->
displays the entire phone list.
If a template contains a section, the text until the endsection command will be replaced by the section block with the same name in one the subtemplates. For example, if the main template has the code
<!-- section footer --> <div></div> <!-- endsection -->
and the subtemplate has the lines
<!-- section footer --> <div>This template is copyright with a Creative Commons License.</div> <!-- endsection -->
The text will be copied from a section in the subtemplate into a section of the same name in the template. If there is no block with the same name in the subtemplate, the text is used unchanged.
Adds a new variable or updates the value of an existing variable. The argument following the command name looks like any Perl assignment statement minus the trailing semicolon. For example,
<!-- set $link = "<a href=\"$url\">$title</a>" -->
Expand the text between the
endwhile as long as the expression following the
while is true.
<!-- set $i = 10 --> <p>Countdown ...<br> <!-- while $i >= 0 --> $i<br> <!-- set $i = $i - 1 --> <!-- endwhile -->
Lists within a hash can be accessed using the "for" command. Hashes within a hash are accessed using the "with" command. For example:
<!-- with %address --> <p><i>$street<br /> $city, $state $zip</i></p. <!-- endwith -->
What to check when this module throws an error
The template is in a file and the file could not be opened. Check the filename and permissions on the file. Relative filenames can cause problems and the web server is probably running another account than yours.
The sigil on a variable differs from the data passed to the subroutine and conversion. between the two would not be legal. Or you forgot to escape the '@' in an email address by preceding it with a backslash.
Either a command was spelled incorrectly or a line that is not a command begins with the command start string.
The template contains a command for the start of a block, but not the command for the end of the block. For example an "if" command is missing an "endif" command.
The parser found a different end command than the begin command for the block it was parsing. Either an end command is missing, or block commands are nested incorrectly.
The expression used in a command is not valid Perl.
Copyright (C) Bernie Simon.
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
Bernie Simon <email@example.com>