NAME
Text::FastTemplate - Class that compiles text templates into subroutines.
SYNOPSIS
use Text::FastTemplate;
# It can be as simple as ...
Text::FastTemplate->new( file => 'template')->print( \%data);
# or as complex as ...
Text::FastTemplate->defaults(
path => [
'/apps/sales/heads_n_feet',
'/apps/sales/content'
],
);
Text::FastTemplate->preload( [
{ file => 'template.txt', key => 'the_page' }
]);
$report= new Text::FastTemplate key => 'the_page';
$output= $report->output( \%data );
print $output;
DESCRIPTION
Text::FastTemplate compiles templates that are written in a syntax that resembles C-preprocessor syntax into Perl subroutines.
Text::FastTemplate was built around two guidelines.
the template syntax must be rudimentary.
the templates and the application logic must be completely separate.
As a template processor, its core purpose is to provide macro-substition into a text template that is provided by the user. Simple macro substitution hardly comprises a useful template processor.
In order to be truly useful, Text::FastTemplate implements two simple flow-control mechanisms and a mechanism for including additional templates.
In the end, Text::FastTemplate provides excellent control of the presentation while maintaining responsibilities of the proper individuals. The designers are responsible for the design. The programmers are responsible for the application.
One of my favourite applications of this module is to derive a Page class from it. The Page class overrides the output() method with its own method that includes common macroes in every message passed to the object, such as a DATE or USER_ID string. The Page class can also have an import function that set defaults and preloads the templates.
TEMPLATE METHODS
To start using Text::FastTemplate immediately, you only need to know two methods, new() and print().
Constructors & Attributes
new() = This is the constructor. It expects a hash and returns a Text::FastTemplate object. Although several attributes are available, only the 'file' attribute is required.
file = this is the name of the template to be loaded. It can be an absolute or relative pathname. If a relative pathname is used then the directories specified in 'path' are searched. If 'path' is not specified then the current working directory for the process is searched.
key = this is a name associated with Text::FastTemplate object. It is determined by the user and should be unique. It was designed to be used in conjuntion with the preload() class method.
path = this is a list of directories that are to be searched with a relative pathname is used as in 'file'.
preload() = This class method simply loads a list of templates by instantiating an object [ new() ] for each template in the list that is passed to it. This purpose of this method is to bypass the normal latency associated with reading and compiling a template the first time. It expects an array-ref to a list of hash-references. The contents of these hashes are passed to new() one at a time.
e.g.,
Text::FastTemplate->preload( [
{ file => 'file1.txt', key => 'file1' },
{ file => 'file2.txt', key => 'file2' },
{ file => 'file3.txt', key => 'file3' },
]);
Object Methods
output(), print() = These methods take the data provided by the user in a hash and plug it into the compiled template. output() returns a scalar that contains the resultant text. print() actually prints the text.
These are identical:
print $template->output( \%data);
$template->print( \%data);
Class Methods
defaults() = this is used to set default attributes that are to be used whenever a new object is instantiated. It is useful during a preload phase of a program. Currently, the 'path' attribute is the only useful attributed affected. For example,
Text::FastTemplate->defaults( path => '/apps/sales/pages');
Text::FastTemplate->preload( [
{ file => 'page1.txt', key => 'page1' },
{ file => 'page2.txt', key => 'page2' },
]);
TEMPLATE SYNTAX
The syntax of Text::FastTemplate is simple. Those who are familiar with the C-prepocessor will recognize the similarity. Here is an example of a template that uses everything Text::FastTemplate offers.
This is a ##A_SIMPLE_MACRO##
#include 'another_file.txt'
#if ##A_FACT##
It is true. See? ##A_FACT##
#elsif ! ##A_FACT##
It is false. See? ##A_FACT##
#else
What is it then?
#endif
#for ##A_FOR_MACRO##
##A_FOR_MACRO_LOOP_ID## : survey says, "##SOME_TEXT##"
#endfor
Templates are processed in two ways.
macroes are substituted into the text.
statements are processed.
Macro substition is performed anywhere in the text of the template. They are case-sensitive.
Statements are line-oriented. That means that a statement must exist on any lines by itself; a statement cannot be embedded in the actual content.
A statement is comprised of a keyword and a macro argument, if one is required. Whereas the macroes are case-sensitive in all contexts, keywords are case-insensitive.
Statements can be continued on separate lines by using the backslash. Also, the statement doesn't need to start at the left margin.
Text::FastTemplate offers the following keywords: #include, #if, #elsif, #else, #endif, #for and #endfor. They are described in detail below.
Macro Syntax
Very simply, Text::FastTemplate identifies a macro as a word bounded by double-hashes, '##'. Macroes are case-sensitive. The regular expression looks like this,
$macro =~ m/##\w+?##/
If a template uses a macro named 'A_SIMPLE_MACRO' then it will refer to that macro in its text as '##A_SIMPLE_MACRO##'. In the program that uses this template, this macro will be referred to in a hash by its real name, 'A_SIMPLE_MACRO'.
Here is an example.
This is a ##A_SIMPLE_MACRO##
If we now assign some text, "lousy example", to the macro 'A_SIMPLE_MACRO' in our data structure that we pass to this template then the output will look like this.
This is a lousy example
[ The ability to specify a delimiter different than '##' might be provided in a future version. ]
#include
Other templates can be included by a template.
#include 'filename' | "filename" | filename
The name of the file can be a relative or absolute pathname, just as with the 'file' constructor attribute. If a relative pathname is used then the same rules apply as during object instanatation. The 'path' of the including object, if provided, is searched; otherwise, the current working directory of the script is searched.
The filename can be enclosed in single quotes, double quotes or not at all. All are legal. Currently, a macro cannot be used; this feature is in the queue.
Beware of #include loops!!! This will cause infinite recursion in your program. Currently, Text::FastTemplate does not check for infinite recursion; this, too, is in the queue.
#if / #elsif / #else / #endif
The condition statements should be obvious. They correspond directly with the Perl statements. The #if and #elsif statements require arguments. They don't need to be macroes; but they are not otherwise very useful.
#if ##A_FACT##
It is true. See? ##A_FACT##
#elsif ! ##A_FACT##
It is false. See? ##A_FACT##
#else
What is it then?
#endif
The condition statements are the exception to the separation of the presentation and the application.
That is because the argument given in a condition statement can be a full-fledged Perl expression. The only difference is that only scalars are available and only via the macro syntax. You might use something like this:
#if ##PAGE## eq 'home'
highlight the home tab
#elsif ##PAGE## eq 'search'
highlight the search tab
#endif
or
#if ##GROUP_ID## =~ /^dba-.*/
you are a group member
#endif
This is really not a design flaw; it was just easier to implement it this way.
#for / #endfor
The repitition or looping construct used by Text::FastTemplate is the #for / #endfor statement. This is not part of the C-preprocessor syntax; but the resemblance is still there.
#for ##A_FOR_MACRO##
some text; survey says, "##SOME_TEXT##"
#endfor
#for LOOP_ID
There is one special feature about the #for loop that needs to be mentioned. Every #for loop has a special macro that corresponds to the number of times that the loop has iterated. This is called the LOOP_ID. To access the LOOP_ID inside of the #for loop, simply concatenate the #for macro and '_LOOP_ID'. For example,
#for ##A_FOR_MACRO##
uses a macro named 'A_FOR_MACRO'. Concatentate this with '_LOOP_ID' and the result is
A_FOR_MACRO_LOOP_ID
This special macro can be used to access to number of iterations of the #for loop. For example, if the following loop iterates three times
#for ##A_FOR_MACRO##
iteration ##A_FOR_MACRO_LOOP_ID##
#endfor
then the result will be
iteration 1
iteration 2
iteration 3
Clear?
TEMPLATE DATA STRUCTURE
A data structure that might be used for the above examples might look like this. It is a hash-ref and it is the basic data structure used by Text::FastTemplate. The keys of this hash-ref correspond with the template's macroes. The values for the hash-ref are scalars except for the #for macro.
The #for macro uses a array-ref that contains a list of these hash-refs.
{ A SIMPLE_MACRO => 'fact',
A_FACT => 1,
A_FOR_MACRO => [ # a #for loop
{ SOME_TEXT => "Iteration #1"},
{ SOME_TEXT => "Iteration #2"}
]
}
Anybody that is familiar with HTML::Template should recognize this scheme.
Like mud, right?
EXAMPLES
None yet. Look in the ./examples directory...later.
BUGS
These bugs were deemed to be acceptable for release since they are currently in production on several web sites. They have been targeted for elimination.
Once loaded, the templates are static for the life of the process. In order to load updated templates, the program needs to be restarted.
Macro scopes are poorly handled. Consider a #for loop around some HTML tags that refer to a ##BGCOLOR## macro that is commonly used. The #for loop will not access the ##BGCOLOR## macro used outside of the loop. The ##BGCOLOR## macro needs to be included in the data that is passed to the #for loop.
Infinite recursion with the #include statement is not checked. Care should be taken to avoid it.
If the any line of the actual content of a template starts with a keyword then it will be processed by Text::FastTemplate.
Error handling could be much better.
FUTURE ENHANCEMENTS
Implement on-line template reloads, both automatic and forced manual.
Add a "group" attribute to group Text::FastTemplate objects and attributes like path and dynamic reload.
Add "#define" and "#undef" to template syntax; will require that handling of macro scope be improved.
Add "source" attribute so that strings and arrays can be used for templates.
AUTHOR
Robert Lehr, bozzio@the-lehrs.com
I certainly would appreciate any feedback from people that use it, including complaints, suggestions or patches. Even people that don't use it are welcome to send comments.
COPYRIGHT & DISCLAIMER
Copyright (c) 2001 Robert Lehr. All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
Caveat emptor. Use this module at your own risk. I will accept no responsibility any loss of any kind that is the direct or indirect result of the use of this module.
SEE ALSO
perl(1), perlref(1).
1 POD Error
The following errors were encountered while parsing the POD:
- Around line 321:
You have '=item 4' instead of the expected '=item 5'