The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Text::Perlate - Template module using Perl as the langauge.

SYNOPSIS

        use Text::Perlate;

        $Text::Perlate::defaults->{...} = ...;

        print Text::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 Text::Perlate;
        eval {
                print Text::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 might 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. Regular Perl comments within a tag are valid and terminate at the end of the tag or the first newline, as might be expected. 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.)

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. See also $options->{cache_id}.

  • $options->{cache_id} specifies a unique ID for this perlate. If the cache_id already exists, the perlate is not parsed again and the existing package name is reused. See also CAVEATS with regard to memory usage. (This is ignored when specifying $options->{input_file}.)

  • $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. See also $options->{skip_path}.

  • $options->{skip_path} specifies to interpret filenames literally rather than searching $options->{path}, @INC, etc. (Ignored without $options->{input_file}.)

  • $options->{raw} 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, however it is officially supported.

  • $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). One common approach in large web applications uses a small index.pl file to call a module containing all the real logic. Searching @INC fits in nicely with that design.

Assign an integer to $Text::Perlate::debug to see some debugging information. 0 is none. 1 or more enables basic debugging. 10 or more dumps the code as it is eval'd. Changes to this knob are not considered relevent to the API.

CAVEATS

As described above, perlates may be specified by name, or the contents of an unnamed perlate may be passed directly. Naming a file or cache_id is preferable because Perlate will then compile each perlate only once. For files, 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 require unusual care for several reasons. First, you must take care to free their content to avoid wasting memory, even if the perlate aborts via die(). Second, you must take care to initialize it to the value you expect every time the perlate executes, even if you need it initialized to undef; this is necessary because a perlate's namespace (package) is reused when possible, which means that a global variable's value will usually (but not always) persist between repeated executions. Third, recursive templates need to save and restore the values of global variables. If you really need a global variable, always use the "local" keyword because it addresses all of these issues. If you need a variable to keep a persistent value, give it an explicit package name that you control, such as the package name of the caller, so it doesn't break if Perlate changes the name of the execution's namespace. (Perlate tries to reuse the same namespace, but never guarantees it. The logic for deciding whether to reuse it will probably change between versions.) A concise way to declare such variables looks like this:

        local our $foo;

Errors and warnings usually report the line number they occur 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 line numbers as seen by Perl consistent with the perlate, 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. Also send me a message if you can verify that this works under Apache 2 and/or threading so I can remove this paragraph.

Recursive perlates are supported and have no known caveats.

INSTALLATION

This module has no dependencies besides Perl itself. Follow your favorite standard installation procedure.

VERSION AND HISTORY

    Version 0.94 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.

    * Version 0.94, released 2007-12-04. Fixed botched release.

    * Version 0.92, released 2007-12-03. Added options skip_path and cache_id. Moved repository to Git. Added Text::Perlate::Apache.

    * Version 0.91, released 2007-05-23. Renamed the rawperl option to raw. Renamed the module from Template::Perlate to Text::Perlate. Fixed problem preventing comments and code from sharing one tag.

    * Version 0.90, released 2007-03-02.

SEE ALSO

The source repository is at git://git.devpit.org/Text-Perlate/

Text::Perlate::Apache provides a direct Apache handler.

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!

COPYRIGHT AND LICENSE

 This may be distributed under the terms below (BSD'ish) or under the GPL.
 
 Copyright (C) 2006-2007 by 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 AUTHORS 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 AUTHORS 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.

1 POD Error

The following errors were encountered while parsing the POD:

Around line 277:

You can't have =items (as at line 283) unless the first thing after the =over is an =item