NAME
Template::Perlate - Template module using Perl as the langauge.
SYNOPSIS
use Template::Perlate;
$Template::Perlate::defaults->{...} = ...;
print Template::Perlate::main($options);
To catch errors, wrap calls to this module in eval{} and check $@.
DESCRIPTION
This module provides a simple translation system for writing files that are mostly text, TeX, HTML, XML, an email message, etc with some Perl code interspersed. The input files use [[ and ]] to mark the beginning and end of Perl code. Text outside of these tags is returned without modification (except for the effects of conditional statements or loops contained in surrounding tags of course). PHP users will notice the similarity to the <? ?> tags used by PHP to separate code from literal text.
A template written in this style is called a "perlate". In contrast, "Perlate" is the name of this module.
This approach provides the simplicity of using a language you're accustomed to (Perl) for logic, rather than inventing a trimmed-down language. Admittedly that means you must exercise restraint in separating logic and text. However, this approach is faster (in execution) and less bug-prone since it uses a well-developed compiler and language you already know well. Many argue that an unrestrained programmer will find a way to shoot themselves despite the best efforts of the language to prevent it. If you agree, Perlate is for you.
WRITING PERLATES
As HTML is a common use for Perlate, the following examples show HTML code outside the tags. The Perl code is surrounded in [[ ]] tags. There is no preamble or postscript; the file is otherwise indistinguishable from its output. For example, the following is a valid perlate:
<html><body>
[[ if($_params->{enabled}) { ]]
Enabled = [[ _get "enabled"; ]]
[[ } ]]
</body></html>
Note that statements that normally end in a semicolon must include the semicolon as shown.
Perlate declares some variables and functions for you in the setup code. All symbol names prefixed with an underline are reserved. So far, the following are available for your use:
_echo() emits the expressions passed to it.
_get() emits the parameters named by the arguments. _get("foo") is the same as _echo($params->{foo}) and _echo($_options->{params}{foo}).
_echoifdef() and _getifdef() are the same as _echo() and _get() except they prevent warnings about undefined values.
$_options is a copy of the same hash passed by the caller, with any default settings (from the global variable $defaults) added to it. Options tell Perlate.pm what to do (what source file to load, what to do with the output, etc).
$_params is a convenient alias of $_options->{params}. This contains input parameters to your perlate.
A more interesting example of using Perlate follows. The following is an example Perl program that calls a perlate:
#!/usr/bin/perl
use strict;
use warnings;
use Template::Perlate;
eval {
print Template::Perlate::main({
input_file => "my.html.perlate",
params => {
enabled => 1,
times => 6,
message => "Display this 6 times.",
},
});
};
if($@) {
print STDERR "An error occurred: $@\n";
}
The file my.html.perlate may contain:
<html><body>
[[- if($_params->{enabled}) { ]]
Enabled.<br />
[[- for(my $count = 0; $count < $_params->{times}; $count++) { ]]
[[ _get "message"; ]]<br />
[[- } ]]
[[- } ]]
[[ _echo "This was repeated $_params->{times} times."; ]]<br />
</body></html>
Some of the tags in the example have a leading hyphen. This signals Perlate to remove one line of whitespace in the source before the tag. One trailing hyphen means to remove one line of whitespace after the tag. N hyphens removes up to N lines, and a plus removes all blank lines. Removal always stops at the first nonblank line. Next, there may be an octothorpe (#), which indicates that the entire tag is a comment. A tag cannot contain both code and comments (see caveat below). To summarize, the tags have the following syntax (note the position of the required whitespace):
\[\[(\-*|\+)#?\s.*\s(\-*|\+)\]\]
The strange indentation in the example above is designed to maintain the indentation levels of the output. Flow control statements strip one line of leading whitespace and are indented independently of the HTML code and output statements. This is simply a suggested style. Feel free to invent your own.
While you don't need to know the internals to use Perlate, it may be useful to understand the basic approach. It translates the perlate into a single string containing Perl code, surrounds it with a bit of setup and tear-down code, then eval's the string to create a new package, then calls the package's _main() function. The setup code includes a "package" statement and "sub _main {". The text between the tags is quoted and rewritten as a call to the _echo function. This way the user can open a lexical scope in one tag and close it in a later one, for example, to conditionally emit certain text or to repeat a block of text in a loop. A perlate is only eval'd once. Subsequent calls to it simply call _main() again. (This is the reason it is wrapped in a function declaration.) Perl allows function declarations inside of functions, so it's valid to define a function in a perlate that's called by other parts of the same perlate. This can be useful on a web page, for example, if there is a bit of HTML code that needs to be repeated in several places. (If this doesn't quite make sense, try executing the code above with the preprocess_only flag.)
A NON-COMMENT TAG MAY NOT CONTAIN ANY COMMENTS.
A comment in the perlate code will screw up later tags on the same line. The only correct way to insert a comment is to use [[# comment ]] with no whitespace between [[ and #. This tells Perlate that the whole tag should be ignored even if it contains newlines.
Consider: [[ # foo ]] some HTML [[ _echo('bar'); ]]
These two tags have no newline between them, so the whole line will be a comment, rather than just the first tag. Obviously, a coder would expect the comment to end where the tag ends. At best, this causes a syntax error when Perlate tries to eval the code. (If this doesn't quite make sense, try adding a comment to a simple perlate and run it with the preprocess_only flag.) We can't just insert a newline after every tag, because that would screw up the line numbers reported by Perl errors and warnings in the final eval. Sadly, Perl's grammar is so complex that parsing out comments would entail parsing most of Perl. So we arrive at this caveat:
A NON-COMMENT TAG MAY NOT CONTAIN ANY COMMENTS.
OPTIONS
There are some options available in $options. Defaults for these options can be specified as a hash in the global variable $defaults. For options where it makes sense, the default is combined with the passed options. For example, a default perlate input file can be specified instead of passing an explicit filename with every call. When used with Apache and mod_perl, for example, setting defaults can be useful in a PerlRequire script.
Several options are available:
$options->{input_file} specifies a filename to read the perlate from. Overrides both the input_file and input_string defaults. If the filename is absolute (begins with a slash), the path and correct directory are not searched. See also $options->{path}.
$options->{input_string} specifies the source for a perlate as a literal string. Overrides both the input_file and input_string defaults.
$options->{params} contains the input parameters to the perlate itself. These can be emitted into the perlate's output by calling _get("param name") or they can be accessed through the $_params hash. Default parameters are added to this hash, but do not override values set in $options->{params}.
$options->{path} may be set to an array of directory names to search. $defaults->{path} is always searched after that. When you add paths to $defaults->{path}, your code may work better with future code of yours if you unshift them onto the array rather than using direct assignment. The search order is always: current directory, $options->{path}, $defaults->{path}, @INC. The path option as seen from inside the perlate (called $_options->{path}) includes all of these directories.
$options->{rawperl} may be set to true to indicate that the whole file is Perl code without [[ ]] tags. This is useful for using parameter passing and searching $options->{path}. This is probably not going to be useful very often, except perhaps for debugging.
$options->{preprocess_only} may be set to true to return the preprocessed file without executing (or caching) anything. This is probably only useful for debugging, unless you want to rely on the existence of _main(), which is subject to change. At times, this can explain why Perl is reporting a syntax error.
OTHER FEATURES & NOTES
The @INC list of directories is automatically appended to the search path. This means you can put perlates in your lib directory beside any modules that call them. After all, a perlate represents a module (in a loose sense). A common approach in large web applications uses a small index.pl file to call a module containing all the real logic (so that mod_perl caches the bulk of the compilation and to avoid warnings about redefined functions). Searching @INC fits in nicely with that design.
Assign a true value to $Template::Perlate::debug to see some debugging information.
CAVEATS
As described above, perlates may be specified by name, or the contents of an unnamed perlate may be passed directly. Naming a file is preferable because Perlate will compile it only once unless it is modified. The device number, inode number, and modification time are used to uniquely identify the specified file. Without caching, the memory usage will grow slightly with each execution, since there is no way to unload a module from memory, and each perlate is loaded more or less like any regular Perl module. Please email the author if you know of a reasonable way to free that memory.
Of course, general programming wisdom holds that global variables are usually a bad approach. In a perlate, they are worse than usual for several reasons. First, their contents is never freed, since Perl doesn't provide an easy way for the package and its contents to be removed from memory. Second, a perlate's package is reused when possible, but that is not guaranteed. A global variable will maintain its value if and only if the package is reused. A perlate will be recompiled under a new package name, for example, if the file's modification time changes. This can easily lead to a perlate acting inconsistently on subsequent executions. If you really need a global variable, the best way to get around these problems is to give it an explicit package name that you control, such as the package name of the caller.
Errors and warnings usually report the line number they occurred on. However, Perl seems easily confused over line numbers in an eval. Often line 1 or the last line will be erroneously reported as the error point. Perlate is careful to keep the position of newlines correct (even when stripping blank lines), but as Perl sometimes gets confused this isn't always helpful.
The "use strict;" and "use warnings;" pragmas are applied to all perlates. This is not optional. If you insist on writing bad code, you can write "no strict; no warnings;" to explicitly turn those off.
This has NOT been tested with threading, which probably means it might not work with Apache 2. However, I'd be happy to fix any problems with threading, if you send me a bug report.
Again, be careful not to put comments in tags unless the whole tag is marked as a comment, as described above.
Recursive templates are supported.
INSTALLATION
Simply copy this file to .../lib/perl5/site_perl/5.x.x/Template/Perlate.pm .
This module has no dependencies besides Perl itself.
VERSION & HISTORY
Version 0.90, released 2007-03-02. This is likely to be identical to version 1.0. Version 1.0 may contain incompatible changes, but this is unlikely unless anyone suggests a really good reason.
AUTHOR
Leif Pedersen <bilbo@hobbiton.org>
Please send suggestions and bugfixes to this address. Even if you have nothing to contribute, please send a quick message. I'd like to get an idea of how many people use this software. Thanks!
LICENSE
This may be distributed under the terms below (BSD'ish), or the same terms as Perl, or under the GPL.
Copyright (C) 2006-2007 Leif Pedersen. All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.