SYNOPSIS
I've been working on a set of modules for a couple of weeks now based on
work I've been doing with several web page authors and copywriters.
I created a module named Text::UberText which is designed to be a
lightweight template system with the ability to be extended easily with
third party code.
Text::UberText was designed meet several needs.
1. Create a template language specification that was easy to read and write.
People using the language should not be required to have strong programming
skills.
2. The template language should not follow Perl syntax rules, or be designed
with preference towards Perl users or programmers. It should also not
be used as a system to simply merge perl code in a document.
3. The parser needs to have a simple interface for module authors to add
their own code without requiring extensive rewrites of an existing
codebase.
4. The parser needs to understand the order and structure of the document
data. The information needs to be made available to programmers writing
code to interact with the parser.
5. The template language should use multiple namespaces, so object code
using the system don't create overlapping commands. For example, if two
different objects created a tag named "address", the parser should
understand which object the tag is associated with.
OTHER TEMPLATE PARSERS
Searching under the "Text" namespace alone reveals at least four different
template parsing systems. There are also parsers under "Apache",
"HTML", and a top level namespace called "Template". The high number of
submissions is partially what lead to the need for a unique named like
"Text::UberText".
Given the high number of template systems out there, it is easy to understand
the reluctance or hesitation in adding another one to CPAN. But I would
like to briefly cover some of the other systems out there. It is not
my intention to criticize other works, but to discuss why I felt these
systems didn't meet all of the requirements I wanted.
1. Text::FillIn, Text::SimpleText, Text::Template
Each of these systems work on the principle of simple variable
substitution. The example documents listed show perl syntax embedded in
the source templates to reference variables, or in one example, perl
subroutines. The features are too limited for complex documents.
2. Text::MetaText
MetaText uses a simple set of commands to generate documents, like INCLUDE,
and DEFINE. It is a good tool for merging multiple documents, or variable
substritution, but it has a very limited command set with no means
to allow for expansion.
3. Text::Templar
Text::Templar allows for template designers to create subroutines that
are called from the template parser. However, it only maps methods of
the Templar object itself, which limits the ability to add more
method calls.
4. HTML::Mason, Text::MicroMason
Mason allows document writers to include large chunks of perl code in
documents that is evaluated, and the result of that code is replaced
in the document. It's very flexible, but it relies on document writers
to be Perl programmers, or have an understanding of perl.
5. Template Toolkit
The closest match to Text::UberText is the Template Toolkit. It allows
for template commands to be matched against variables or subroutines,
and it has a large plug-in library which indicates that it is
easy to expand.
EXAMPLE DOCUMENT
The following is very simple document that can be read by Text::UberText
>
>Today is [uber.time date format:(mm/yy/dd)].
>
>[uber.var name:(user) value:([unix.env var:(USER)])]
>Your username is [uber.var name:(user)].
>
>The ball is [uber.var name:(color)] and [uber.var name:(size)]
>inches in diameter.
>
Other examples are listed in the POD documentation below.
HOW THE DOCUMENT IS PARSED
The command structure is refered to as a command tag. It contains a
namespace which points to an instantiated perl module, and commands
with additional options and values passed to options.
Like HTML or XML, it also allows for command tags to act as containers
for document text or other commands.
When the source data is read, it is parsed and broken down into a tree
structure. When the parsing method is explicitly called, the command tags
are examined, and the appropriate method calls are made depending on
the namespace and the command in the tag. The output is then saved and
returned back to the caller when requested.
Comments and criticism welcome. Below is the POD documentation for the
main module. The code is still in beta, but it's relatively stable and
could probably be uploaded to CPAN within a week.
----------------------------------------
NAME
Text::UberText - Customizable Template Engine
SYNOPSIS
use Text::UberText qw(standard);
$ub=Text::UberText->new();
$ub->read(@array);
$ub->extend($acme_invoice);
$doctree=$ub->parse();
if ($doctree)
{
$doctree->run();
print($doctree->output());
}
DESCRIPTION
Text::UberText is an expandable template system designed to let
programmers write their own commands and tie those commands to
program code. UberText reads command tags in documents, and then
calls perl modules based on the tag.
SAMPLE DOCUMENT
The following is an example of a document that uses the UberText
template system.
Invoice#: [uber.print string:([acme.invoice number]) fmt:(%010d)]
Date: [uber.date date fmt:(MM/DD/YYYY)]
Ship To: [acme.invoice address:(shipping) ]
Tracking number: [acme.invoice tracking-number vendor:(ups)]
[acme.invoice itemlist -> ]
Item: [acme.invoice itemnumber] [acme.invoice description]
[<- acme.invoice itemlist ]
[acme.invoice terms]
The template is designed by a programmer that has designated the
"acme.invoice" namespace is to be used for his code. He then
writes Perl modules that interface with Text::UberText when the
document is parsed.
UBERTEXT FORMAT
UberText documents are plain text mixed with command tags. A
very simple command tag contains a namespace and a command.
[uber.info version]
In this case, the namespace is `uber.info' and the command is
`version'.
Commands can have values passed to them.
[uber.info version:"full"]
Commands can also have additional options, and those options can
have values.
[uber.var name:(variable) value:"This is the value of the variable"]
Values for commands or options are specified by following the
command or options with a colon, and then enclosing the value in
paranthesis or double quotes.
An UberText command can also be wrapped around portions of text
or other UberText commands. These are considered block commands.
[uber.transform indent class:(quote) ->]
"You can reach be anytime at my work number [per.info phonenum:(work)]"
[<- uber.transform ]
Command options can be placed in either the tag that starts the
block, or the tag that ends the block. This example....
[uber.loop count:(20) -> ]
This text will repeat 10 times
[<- uber.loop start:(11) ]
Is identical to..... [uber.loop count:(20) start:(11) -> ] This
text will repeat 10 times [<- uber.loop ]
You can also insert UberText commands in the values of options
or commands.
[uber.var name:(version) value:([uber.info version])]
[uber.print string:(The fruit is [uber.rand words:(orange,apple,banana)]) ]
But you cannot use block commands inside the values to options
or commands.
UberText command tags can span multiple lines.
[
uber.var name:(customer)
value : "John Q. Public"
]
Leading and trailing whitespace within an UberText command is
eliminated. Some whitespace is needed to seperate the namespace,
the command and options, but that's it. Whitespace within values
to commands and options is kept intact. Also, whitespace after
the command tag (including carriage returns) is kept intact as
well.
LOADING
UberText comes with a set of modules handling a small set of
basic functions. All of the modules are in the
Text::UberText::Modules Perl namespace. You can specify which of
those modules are loaded on the use line.
use Text::UberText qw(minimal);
The modules are not actually loaded until an UberText object is
initiated.
The following is a list of module sets.
none
None of the included UberText modules are loaded.
minimal
Only the Text::UberText::Modules::Info module is loaded
standard
The modules Text::UberText::Modules::(Info,Version) are
loaded.
METHODS
$ubt=Text::UberText->new();
Creates a new UberText object. The parser, the dispatch
table, and the log are all initialized.
$ubt->read(@input);
Reads in the passed array and passes it to the parser.
$tree=$ubt->parse();
Runs the parser against the input. At this time, the
commands and the document text are sorted out and placed in
a Text::UberText::Tree object, which keeps track of the
document. The tree object is then returned from the method
call.
$ubt->extend($object);
Sends an object to the Text::UberText::Dispatch object,
which controls all methods that interface with the command
nodes. $object is either a Perl object, or just the name of
a class. In either case, the Dispatch object searches for a
method called `uberText' and runs it. It then takes data
returned from the call and uses it to expand its internal
dispatch table.
BUGS/CAVEATS
UberText is pretty complex. There's probably bugs floating
around because I haven't even conceived of all of the possible
input errors or third party module errors that it needs to deal
with.
AUTHOR
Chris Josephes <[EMAIL PROTECTED]>
SEE ALSO
the Text::UberText::Tree manpage, the Text::UberText::Dispatch
manpage, the Text::UberText::Parser manpage
COPYRIGHT
Copyright 2002, Chris Josephes. All rights reserved. This module
is free software. It may be used, redistributed, and/or modified
under the same terms as Perl itself.
--------------------
Christopher Josephes
[EMAIL PROTECTED]