Template::Trivial - Simple (yet powerful) and fast substitution templates


Template-Trivial documentation Contained in the Template-Trivial distribution.

Index


Code Index:

NAME

Top

Template::Trivial - Simple (yet powerful) and fast substitution templates

SYNOPSIS

Top

  use Template::Trivial;

  my $tmpl = new Template::Trivial( templates => '/path/to/templates' );
  $tmpl->define( main => 'main.tmpl',
                 list => 'list.tmpl' );
  $tmpl->define_from_string( item => '<li>{ITEM}' );

  for $i ( 1 .. 3 ) {
      $tmpl->assign( ITEM    => "Thingy $_" );
      $tmpl->parse( '.ITEMS' => 'item' );
  }

  $tmpl->parse(LIST => 'list' );
  $tmpl->parse(MAIN => 'main' );

  ## print out
  print $tmpl->to_string('MAIN');

DESCRIPTION

Top

Template::Trivial is heavily inspired by the excellent and stable CGI::FastTemplate written by Jason Moore. We introduce a slightly modified syntax, fewer features, and a slight execution improvment over CGI::FastTemplate.

Philosophy

The design goals of Template::Trivial were:

Quick Start

For those wanting to dig in, here is an absolute barebones reference. The rest of the document is just details.

That's Template::Trivial in a nutshell. Here is a complete example:

Write some templates and put them in files:

main.tmpl
    <html>
    {HEAD}
    {BODY}
    </html>

head.tmpl
    <head>
    <title>{TITLE}</title>
    </head>

body.tmpl
    <body>
    <h2>{TITLE}</h2>
    This is a {TEST}.
    </body>

Now, write the program to use the templates:

    use Template::Trivial;

    my $tmpl = new Template::Trivial;
    $tmpl->define( main => 'main.tmpl',
                   head => 'head.tmpl',
                   body => 'body.tmpl' );
    $tmpl->assign(TITLE => "This is the title");
    $tmpl->assign(TEST  => "Testing 1 2 3...");
    $tmpl->parse(HEAD => 'head');
    $tmpl->parse(BODY => 'body');
    $tmpl->parse(MAIN => 'main');
    print $tmpl->to_string('MAIN');

That's it. Here's a play-by-play:

Create the Template::Trivial object:

    my $tmpl = new Template::Trivial;

Tell the object where to find the templates and give aliases for the templates. The aliases are the same pattern as variables except lowercase letters:

    $tmpl->define( main => 'main.tmpl',
                   head => 'head.tmpl',
                   body => 'body.tmpl' );

Assign some variable data:

    $tmpl->assign(TITLE => "This is the title");
    $tmpl->assign(TEST  => "Testing 1 2 3...");

Parse the 'head' template (which points to head.tmpl). When this template is parsed, its contents will be saved in the 'HEAD' template variable, which the 'main' template uses:

    $tmpl->parse(HEAD => 'head');

So the 'HEAD' variable is now:

    <head>
    <title>This is the title</title>
    </head>

Parse the 'body' template. This works just like 'head'; it must be processed before 'main' is processed, since 'main' depends on 'BODY' to be already defined:

    $tmpl->parse(BODY => 'body');

So the 'BODY' variable is now:

    <body>
    <h2>This is the title</h2>
    This is a Testing 1 2 3....
    </body>

Now parse the "top" template 'main':

    $tmpl->parse(MAIN => 'main')

We recall that the 'main' template was:

    <html>
    {HEAD}
    {BODY}
    </html>

The parse method replaces the 'HEAD' and 'BODY' variables with their contents:

    <html>
    <head>
    <title>This is the title</title>
    </head>

    <body>
    <h2>This is the title</h2>
    This is a Testing 1 2 3....
    </body>

    </html>

This new string is assigned to the variable 'MAIN' in the parse method.

Print out our results:

    print $tmpl->to_string('MAIN');

Core Methods

The following methods are specified in order of how they might appear in a real program (i.e., in the order you might use them).

new

Create a new template object.

    my $tmpl = new Template::Trivial;

new optionally takes the following arguments:

    strict => 0
    templates => '/path/to/templates'

templates

Tells the template object where to look for templates you define in from_file.

    $tmpl->templates('/path/to/templates');

This may also be set in the constructor. The default value is the empty string ''.

strict

Will emit a warning when any of the following conditions occur:

  - a template alias in 'define' does not match the lowercase regular
    expression pattern: /^[a-z][a-z0-9_-]*?$/
  - a file in a 'define' statement is not a regular file or character
    special device
  - a variable in 'assign' does not match the uppercase regular
    expression pattern: /^[A-Z][A-Z0-9_-]*?$/
  - a variable in 'assign_from_file' does not match the uppercase
    regular expression pattern: /^[A-Z][A-Z0-9_-]*?$/
  - a file in an 'assign_from_file' statement is not a regular file
    or character special device
  - a variable in 'append' does not match the uppercase regular
    expression pattern: /^[A-Z][A-Z0-9_-]*?$/
  - an undefined variable is encountered in a template during 'parse'
  - an undefined variable is encountered in 'to_string'

Example:

    $tmpl->strict(0);

The strict option may be set in the constructor. It defaults to '1'.

define

Defines a mapping of template aliases to filenames.

    $tmpl->define( main => 'main.tmpl',
                   head => '/usr/opt/tmpl/head.tmpl',
                   body => 'body.tmpl', );

The path specified by templates will be prepended to the filenames specified in define, except when the filename begins with a slash '/', in which case the absolute path will be used.

define_from_string

Defines a mapping of template names to the contents of a string.

    $tmpl->define_from_string( footer => "created on ${DATE}" );

This is a quick way for a programmer to make a template without writing one to file. Useful for testing or "locking away" parts of a template set. See Philosophy.

assign

Assigns the specified string to the specified template variable.

    $tmpl->assign( FOO => 'this is foo' );

or using a "here" document:

    $tmpl->assign( FOO => <<_BLECH_ );
    This is a longer foo
    with multiple lines.
    _BLECH_

Subsequent assignments to the same template will override previous assignments.

You can make multiple assignments in one call:

    $tmpl->assign( FOO => 'foo string',
                   BAR => 'bar string' );

You can also append a string to an existing variable by prepending a dot to the variable:

    $tmpl->assign('.FOO' => ' and more foo');

but this is accomplished more cleanly with the append method (below). This usage is deprecated and is included chiefly for CGI::FastTemplate compatibility (and partly for nostalgia).

assign_from_file

Assigns the contents of a specified file to the specified variable. Paths are relative to the value of the templates method. from_file may be used multiple times, or may take several list arguments:

    $tmpl->assign_from_file( FOO => 'foo.txt',
                             BAR => 'bar.txt' );

is the same as:

    $tmpl->assign_from_file( FOO => 'foo.txt' );
    $tmpl->assign_from_file( BAR => 'bar.txt' );

If the filename begins with a slash, the value of templates will not be prepended:

    $tmpl->assign_from_file( MAH => '/path/to/mah.txt' );

parse

Parses the specified template and saves its results in the specified variable.

    $tmpl->parse( MAIN => 'main' );

Multiple variable/alias pairs may be specified:

    $tmpl->parse( JOE => 'joe',
		  BOB => 'bob_file');

but the templates are not guaranteed to be parsed in the order specified. Because of this, you should not put codependent templates in the same parse statement.

to_string

Returns the contents of a template variable as a string. Useful for assignment or printing.

    print $tmpl->to_string('FOO');

That concludes this example.

TO DO

Top

We'd like to be as complete as CGI::FastTemplate sometime, but we wanted to get this out the door. Here are some features to look for around Q1 or Q2 of 2004.

SEE ALSO

Top

CGI::FastTemplate(3).

AUTHOR

Top

Scott Wiersdorf, <scott@perlcode.org>

COPYRIGHT AND LICENSE

Top


Template-Trivial documentation Contained in the Template-Trivial distribution.

package Template::Trivial;

use 5.00503;
use strict;
use warnings;

use vars qw($VERSION);
$VERSION = '0.08';

use vars qw($STRICT);           ## template stricture
use vars qw($TMPL_DIR);         ## template directory
use vars qw(%VARIABLES);        ## template variables (e.g., FOO, BAR)
use vars qw(%TEMPLATE_NAME);    ## template aliases (e.g., foo, bar)
use vars qw(%TEMPLATE_CACHE);   ## template contents

my $VAR_RE  = qr(^[A-Z][A-Z0-9_-]*?$)o;
my $TMPL_RE = qr(^[a-z][a-z0-9_-]*?$)o;
my $TVAR_RE = qr!\{([A-Z][A-Z0-9_-]*?)\}!o;

sub new {
    my $class = shift;
    my $proto = ref($class) || $class;
    my $self  = { };
    my %parms = @_;

    bless $self, $proto;

    $STRICT = ( defined $parms{strict} 
		? $parms{strict} 
		: 1 );
    $TMPL_DIR = ( defined $parms{templates} 
		  ? $parms{templates}
		  : '' );
    %VARIABLES      = ();
    %TEMPLATE_NAME  = ();
    %TEMPLATE_CACHE = ();

    return $self;
}

sub strict {
    my $self = shift;
    $STRICT = ( @_ ? shift : $STRICT );
}

sub templates {
    my $self = shift;

    if( @_ ) {  ## new assignment
	$TMPL_DIR = shift;
	if( $TMPL_DIR && $TMPL_DIR !~ m!/$! ) {
	    $TMPL_DIR .= '/';
	}
    }

    return $TMPL_DIR;
}

sub define {
    my $self    = shift;
    my %defines = @_;

    for my $tmpl ( keys %defines ) {
	my $path = ( $defines{$tmpl} =~ m!^/!o
		     ? $defines{$tmpl}
		     : $TMPL_DIR . $defines{$tmpl} );

	if( $STRICT ) {
	    warn "Illegal template alias name '$tmpl'\n"
	      unless $tmpl =~ $TMPL_RE;

	    unless( -f $path || -c _ ) {
		warn "File '$path' ($tmpl) is not a file\n";
		next;
	    }
	}

	$TEMPLATE_NAME{$tmpl} = $path;

	## redefining a template clears it from the cache
	delete $TEMPLATE_CACHE{$tmpl}
	  if exists $TEMPLATE_CACHE{$tmpl};
    }
}

## FIXME: add an alias or two for define_from_string method

sub define_from_string {
    my $self = shift;
    my %defines = @_;

    for my $tmpl ( keys %defines ) {
	$TEMPLATE_CACHE{$tmpl} = $defines{$tmpl};
    }
}

sub assign {
    my $self = shift;
    my %assign = @_;

    for my $var ( keys %assign ) {
	my $append = $var =~ s/^\.//o;

	if( $STRICT ) {
	    warn "Illegal variable name '$var'\n"
	      unless $var =~ $VAR_RE;
	}

	if( $append ) {
	    $VARIABLES{$var} .= $assign{".$var"};
	}
	else {
	    $VARIABLES{$var} = $assign{$var};
	}
    }
}

sub assign_from_file {
    my $self = shift;
    my %assign = @_;

    for my $var ( keys %assign ) {
	my $append = $var =~ s/^\.//o;

	my $path = ( $assign{$var} =~ m!^/!
		     ? $assign{$var}
		     : $TMPL_DIR . $assign{$var} );

	if( $STRICT ) {
	    warn "Illegal variable name '$var'\n"
	      unless $var =~ $VAR_RE;

	    unless( -f $path || -c _ ) {
		warn "File '$path' is not a file\n";
		next;
	    }
	}

	open FILE, "$path"
	  or do {
	      warn "Could not open '$path': $!\n";
	      next;
	  };
	local($/) = undef;
	if( $append ) {
	    $VARIABLES{$var} .= <FILE>;
	}
	else {
	    $VARIABLES{$var} = <FILE>;
	}
	close FILE;
    }
}

sub append {
    my $self   = shift;
    my %assign = @_;

    for my $var ( keys %assign ) {
	if( $STRICT ) {
	    warn "Illegal key name '$var'\n"
	      unless $var =~ $VAR_RE;
	}

	$VARIABLES{$var} .= $assign{$var};
    }
}

## FIXME: append_from_file?
## FIXME: any defaults for to_string('MAIN'), etc.? How about
## FIXME: parse('MAIN') implies parse('MAIN => 'main')?

sub parse {
    my $self  = shift;
    my %parse = @_;

    while( my($var, $tmpl) = each %parse ) {
	my $append  = $var =~ s/^\.//o;
	my $file;

	## find the template in our cache
	unless( defined $TEMPLATE_CACHE{$tmpl} ) {
	    open TMPL, "$TEMPLATE_NAME{$tmpl}"
	      or do {
		  warn "Could not open template ($tmpl) '$TEMPLATE_NAME{$tmpl}': $!\n";
		  next;
	      };
	    local($/) = undef;
	    $TEMPLATE_CACHE{$tmpl} = <TMPL>;
	    close TMPL;
	}

	$file = $TEMPLATE_CACHE{$tmpl};

	## parse the template
	$file =~ s{$TVAR_RE}{
	    	    if( exists $VARIABLES{$+} ) {
				$VARIABLES{$+};
	    	    }
	    	    else {
				if( $STRICT ) {
		    		    warn "Unknown variable '$+' found.\n";
				}
				"{$+}";  ## put it back how it was
	    	    }
		}xge;

	if( $append ) {
	    $VARIABLES{$var} .= $file;
	}
	else {
	    $VARIABLES{$var} = $file;
	}
    }
}

sub to_string {
    my $self = shift;

    if( $STRICT ) {
	unless( $_[0] && exists $VARIABLES{$_[0]} && $_[0] =~ $VAR_RE ) {
	    warn "Undefined or unknown variable '$_[0]' found.\n";
	    return undef;
	}
    }

    return ( defined $VARIABLES{$_[0]} ? $VARIABLES{$_[0]}: '' );
}

## FIXME: clear methods?

1;
__END__