HTML::DynamicTemplate Table of Contents: * NAME - HTML::DynamicTemplate * SYNOPSIS * DESCRIPTION * USAGE o Template variables + Template directive $SET() + Template directive $DEFINE() + Template directive $INCLUDE() o Examples o Performance comments * METHODS o Constructors + new o Object methods + clear + has_defined + get + render + set + set_recursion_limit o Abstract methods + callback_ARRAY + callback_HASH + callback_SCALAR + callback_GLOB * CREDITS o Authors and contacts o Legalese ------------------------------------------------------------------------ NAME HTML::DynamicTemplate - HTML template class. ------------------------------------------------------------------------ SYNOPSIS use HTML::DynamicTemplate; my $template = new HTML::DynamicTemplate ('path/to/template'); $template->set_recursion_limit($integer); # template variables can be set from perl or # within the template itself # $template->set( BACKGROUND_PIC => '../some/pic.gif' ); $template->set( NAME_1 => $value_1, NAME_2 => $value_2, NAME_3 => \@some_array, BODY => 'background=$BACKGROUND_PIC link=blue', CALLBACK => sub{ return "some html or template \$VARS" } ); $template->set( \%other_vars ); $value = $template->get('VAR'); # clear all variables or just clear some # $template->clear(); $template->clear( \@variables ); # obtain & print the substituted template... # print $template->render(); print $template->render(@variables); # Create specialised DataTemplate objects by subclassing # and overriding the special callback_* routines. # who said perl doesn't have inner classes??? ;-) # { package DataTemplate; @DataTemplate::ISA = qw/ HTML::DynamicTemplate /; sub callback_ARRAY { my( $this, $name, $array_ref ) = @_; # some cool stuff here... return 'some html or template $VARS' if $name eq 'DATA'; } } my $data_tmpl = new DataTemplate ('/templates/data.tmpl'); $data_tmpl->set('DATA', \@my_data ); print $data_tmpl->render(); path/to/template ---------------- $DEFINE(HEADING, "My Page") $INCLUDE(/some/common/header) $DEFINE(SCOPED_VAR, "temporary value") $INCLUDE(/some/other/template) $SET(AUTHOR, "Matt Harrison") $INCLUDE(/some/common/footer) ... some/common/header __________________ $HEADING
... ------------------------------------------------------------------------ DESCRIPTION HTML::DynamicTemplate is a class implementing a HTML/text template in perl. The objective of the class is to provide a mechanism by which to effectively decouple the design elements of a page from the dynamic content, but also to provide for the generalisation of dynamic content generation through the use of extensible objects. In this sense, the class strives to avoid the temptation to let the swiss-knifing perl hacker introduce a word of perl in a html page, and keep the pedantic web-page designers out of our (my) lovely code ;-), all the while keeping the power of perl through the use of template variables as references to perl code or arbitrarily-complex data structures. Significant features include the ability to set template variables from within perl code and the templates themselves, the ability to recursively include/substitute other templates and template variables, the tremendously useful ability to define template variables as perl references and callback subroutines, and the provision of an object-oriented interface to promote the use of inheritance and polymorphism. These features allow the programmer/designer to maintain a consistent look and feel across multiple pages, while keeping a common code base, and to change either/both the content and layout of a site easily and independently. ------------------------------------------------------------------------ USAGE HTML::DynamicTemplate uses 4 syntactic constructions within HTML source files: template variables, of the form '$VARIABLE'; the template variable-setting constructs $SET and $DEFINE; and the template-including directive $INCLUDE. All variable and directive names are specified in uppercase. This is enforced. A second concession to make is to be sure to escape quotes (") and closing parantheses ()) as HTML entities. Lastly, anything that LOOKS like a template variable -- it has a '$' followed by uppercase chars ( /$\w+/ ) -- will be substituted or removed. Therefore, to get a literal $THIS in your html you have to escape the '$' as html. sorry. Note also that the renderer doesn't care if template variables/directives occur within HTML comments, though the result of the substitution will still be within html comments. Template variables <-- This is standard HTML with an embedded variable reference which is substituted with the value of the template variable 'HIGHLIGHT' when the template is rendered. Every instance of the text '$HIGHLIGHT' in the given template, and all those recursively included from this one will be replaced with this value. Template variables may be set and re-set from within perl by the method set(), or from within the template itself by the template directives $SET() and $DEFINE(), described below. Variables themselves may also contain other template variable references ie $SET(FOO, ``some text $BAR'') -- this works as you would expect, though in the case of $DEFINE(), be aware of circular references. Infinite recursion conditions are monitored in any case. Template directive $SET() $SET(PAGE_TITLE, "What's New?") $SET(HIGHLIGHT, "color=red size=+1") $SET(PAGE_BODY, "background=$BACKGROUND link=$LINK_COLOUR") Template variables are set within perl code using the set() method or within the template itself with the $SET() directive. This is useful when setting variables for use by all included templates. For setting page-specific default values which can be overriden by other templates/code, see the $DEFINE directive. Template directive $DEFINE() $DEFINE(TABLE_TITLE, 'Table I') $DEFINE(TITLE, "Page $PAGE_NO $PAGE_DESC") In a similar fashion to $SET(), template variables may also be set within templates using the $DEFINE directive. $DEFINE operates like $SET, within the important exception that variables defined with $DEFINE are scoped to the template in which they were defined and to all templates $INCLUDE-ed from this one. The $DEFINE directive is analogous to the perl function 'local', with an important exception - $DEFINE-d variables are overriden by variables which have been $SET or set(). The main purpose of $DEFINE is to provide page-specific default values. In most cases it is more useful to $DEFINE variables so they can be overriden by $SET directives or perl code. eg: $DEFINE(TITLE, "DefaultTitle") $TITLE If the above $DEFINE() directive were $SET(), the value of $TITLE could never be altered from ``DefaultTitle'' because it occurs immediately prior to the use of $TITLE. Template directive $INCLUDE() $INCLUDE(templates/example.tmpl) $INCLUDE($PATH_TEMPLATES/$TABLE_TEMPLATE) Additionally, templates may be recursively included by another template by the $INCLUDE directive. Template paths may also be variable references, as in $INCLUDE($BANNER_AD). Any variable references found in included templates will be substituted as in the original template. The extension '.tmpl' for html templates is arbitrary but useful. Examples For example, a simple but effective usage of this class from a script may be to have a set or sets of template variables defined in an external, centralised configuration file and to initialise template object(s) from this - eg: /main/conf/file _______________ # note: valid perl! $DEFAULT = { TEXT_COLOUR => 'white', BACKGROUND => 'some_pic.png', ... }; script ______ { # load template vars into private namespace package Vars; do('/main/conf/file') or die; } my $template = new HTML::DynamicTemplate ( $main_template ); $template->set( $Vars::DEFAULT ); ... print $template->render(); As stated previously, DynamicTemplate endeavours to keep perl and it's pseudo-guises out of html. However, all of perl's power is avaliable through defining template variables as either references to perl primitives or references to (callback) subroutines. A template variable may be defined from perl by the following: $template->set('VAR', \&my_subroutine ); # OR $template->set('VAR', sub{ my $template = shift; my $value = $template->get('SOME_VAR'); $template->set('A_NEW_VAR', "here is a new $value"); return 'some tasteful text, html, or $TEMPLATE_VAR\'s'; } ); This subroutine will be called each time the text '$VAR' appears in any template or included template. The return value will first be evaluated for other template directives, and then will be substituted in place of '$VAR'. Template variables may also be set to a hash, array, scalar or typeglob reference causes a special callback_* routine to be called, where '*' is the type of reference. See the section on the callback_* routines later in this document. A simple but expressive use of this callback functionality creates a RDBMS-backed dynamic web page (minus error checking and fluff): use DBI; use HTML::DynamicTemplate; # init template + callbacks my $main_tmpl = new HTML::DynamicTemplate ('./page_template.tmpl'); $main_tmpl->set( \%page_defaults ); $main_tmpl->set( 'MY_CALLBACK', sub{ my $tmpl = shift; my $value = $tmpl->get('SOME_COLUMN_VALUE'); return reformatted( $value ); } ); # DB code my $dbh = new DBI (); $dbh->connect( $db_connect_params ); my $sth = $dbh->prepare("SELECT * FROM BLAH"); $sth->execute(); # instantiate and print result template(s) while ( my $result_row = $sth->fetchrow_hashref() ) { my $entry = $main_tmpl->new('./result_template.tmpl'); $entry->set( $result_row ); print $entry->render(); } Key to this approach is the use of template variables within './result_template' which have the same names as the column names returned from the database. This allows each row result to be passed directly to a template object or template objects. Data which needs 'massaging' for presentation are defined in terms of an extra template variable in 'result_template' which is mapped to a callback subroutine as shown above. This allows for clean and extensible cgi scripts where most of the ugly html code is mapped to a series of template callback subroutines, with the true html framework stored in a html template file. In some ways, this model is anologous to the event-driven programming of GUI toolkits, such as the AWT from java, where the event of enountering a template variable in a html template (the 'gui') 'fires' the mapped response. Note that a template object reference is passed as the first argument to each callback subroutine (wherever it resides), allowing the application programmer to control other template variables through the use of get() and set() routines, and to change other state information. The use of closures to preserve private data is also effective. eg: { my $counter = 0; $template->set( 'COUNT', sub{ return ++$counter; } ); } With care and forethought, even your dynamic content-generation code can be easily reused across objects, applications and scripts. Performance comments DynamicTemplate sans comments and pod weighs in at about 9Kb. Parsing/Rendering of about 100Kb of a fairly complicated set of templates (text only; complicated in the sense that they use many variables and directives) takes about 18 msec on a moderate (celeron 500) machine. Every effort to keep things clean and brisk has been made - however please by all means send me suggestions on improvements. ------------------------------------------------------------------------ METHODS Constructors new usage new( $template_filename ) $template_filename - A path to a HTML template file. Constructor for the template. Returns a reference to a HTML::DynamicTemplate object based on the specified template file, or an exception if the template file cannot be opened. NOTE: This constructor allows the use of the Class->new() syntax as well as the $object->new() syntax to create new objects. However, $object->new() ie: calling new() on an existing object creates and new object and then clones all aspects of the calling object except for the HTML source given by the argument $template_filename or \$source. This means that the code... my $new_tmpl = $template->new("/some/template.tmpl"); ...creates a new object and then (shallow) copies its set of template variables into a NEW hash, as well as $template's other settings. This is a convenience for the case where you want 2 or more copies of an object with the same template variables defined, but want to use them for independent html templates (As a side note, the $SET() and $DEFINE() namespaces are completely separate - the hash for $DEFINE() variables is dynamic and exists only at rendering time...it can never be copied or inherited ). usage new( \$source ) \$source - a scalar reference to a string containing HTML with embedded template variables. Alternative constructor, which takes a scalar reference to HTML source. Returns an exception if passed a non-SCALAR reference. Otherwise identical in effect to new( $template_filename ). Object methods clear usage clear() Clears template variables. Useful when processing table row templates. usage clear( @variables ) @variables - List of variables to clear Clears only the template variables specified by @variables. Note that template variable names are always given in uppercase. usage clear( \@variables ) \@variables - List of template variables to clear Same as for clear( @variables ), but argument is passed as a reference, which is faster if @variables contains many elements. has_defined usage $boolean = $this->has_defined('TEMPLATE_VAR') $boolean - boolean true or false Return a boolean value indicating whether this template has the template variable $TEMPLATE_VAR. : that boolean true is returned even if $TEMPLATE_VAR is itself false or undefined, a la perl exists(). get usage $value = $this->get( $var_name ) $value - The value of the template variable $var_name. $var_name - A template variable name Returns the current value of the template variable given by $var_name. Returns undef if the template variable name is non-existent and returns boolean false if the template variable given by $var_name exists but has no value (is false or undefined). Note that $value may contain any valid perl scalar, including references to CODE, HASHes, ARRAYs, SCALARs etc.. usage get() This usage returns a reference to the hash of all currently-defined template variables. Note that template variables are always uppercase and are true for the regular expression /^\w+$/. render usage $HTML = $this->render() $HTML - A chunk of HTML as a string, with all template variables removed or substituted. Renders the current template object to 'pure' html, performing all template variable substitutions and template directives as found in the source template. Template variables and directives are described in the section 'USAGE'. Returns html with all template variables substituted and removed. Returns a blob of 'pure' html (Can html ever be pure? ;-) ). usage $HTML = $this->render( @variables ) @variables - List of template variable names to use in rendering, removing - but not substituting - others. $HTML - A chunk of HTML as a string, with all template variables removed or substituted. Renders template by performing variable substitutions on only those variable names specified in @variables. Otherwise identical to render(). Elements in @variables must be uppercase. set usage $overwritten = $this->set( 'NAME' => $value ) $overwritten = $this->set( %parameters ) $overwritten - number of template variables redefined. $value - Any perl scalar. see description. %parameters - Hash of template variable names mapped to values, as in $value. Sets template variable to given value. $value can be just about any legal perl scalar. Any non-reference $value will be substituted verbatim in the given template wherever the text '$NAME' is found. $value may of course contain other template variables or template directives (note that $SET() directives used from within a template cannot contain another $SET(), though can contain $INCLUDE and $VAR subtitutions. set() can set anything to anything ). If $value contains a reference to code or a subroutine, then that code will be called for each instance of $NAME in a template. If $value contains any other reference type, then one of the various callback_*() routines will be called. see previous description of template variables. usage $overwritten = $this->set( \%parameters ) $overwritten - number of template variables redefined. %parameters - Hash of template variable names mapped to values, as in $value. Adds to the set of template variables given by %variables to the current set. Otherwise identical in effect to set( %hash ). This usage throws an exception if passed a non-HASH reference. set_recursion_limit usage set_recursion_limit( $depth ) $depth - An integer value indicating the depth to recursively include templates (via $INCLUDE). A default recursion limit for template includes is implemented to prevent infinite recursions. Use this method to override the default value (10). Abstract methods HTML::DynamicTemplate includes a set of 'abstract' methods for application programmers to override by subclassing. Each of these methods are called by HTML::DynamicTemplate whenever a template variable containing a (non-CODE) reference is encountered in a html template (during a call to render() ). CODE references are called directly, and the returned value substituted in place of the template variable. In the case of other types of references, HTML::DynamicTemplate calls the appropriate callback_* method, where the '*' is one of SCALAR, ARRAY, HASH, and GLOB as determined from the type of reference. There is currently no allowance for a callback method for objects. For instance, setting a template variable to an array reference eg: $template->set( 'SOME_VAR', \@list ); The callback_ARRAY() method will be called for each incidence of the template variable $SOME_VAR in the html template encapsulated by $template ( see new() ), because it contains an ARRAY reference. The current implementations for all of the callback_* routines in HTML::DynamicTemplate return the empty string ``''. Of course, there is no obligation to override all of the callback_* routines, as the default implementation for all the callback_* routines return the empty string ``''. Overriding the default implementation of one or more of the callback_* methods may be as simple as: # a perl 'inner class' ;-) { package RowTemplate; @RowTemplate::ISA = qw/ HTML::DynamicTemplate /; sub callback_ARRAY { my( $this, $name, $value ) = @_; # your implementation here... return 'some html'; } } ... # somewhere else... my $row_tmpl = new RowTemplate ($filename); An object created from a derived class can of course be used as any other HTML::DynamicTemplate object, except for it's behaviour with template variables which contain array references, thanks to the power of object polymorphism. Method arguments All callback methods will be called with the following arguments: @_ = ( $this_template_obj, $variable_name, $value_reference ) where: $this_template_obj -> 'this' or 'self' or whatever you call your object refs $variable_name -> the name of the template variable $value_reference -> value of the template variable, a reference by definition. The overridden method can return any valid html, including html with other template variables. This return value is substituted into the 'calling' html template. callback_ARRAY usage protected abstract $HTML = $this->callback_ARRAY( 'VAR_NAME', \@array ) $HTML - A chunk of html as a string, possibly containing other embedded template variables. 'VAR_NAME' - The template variable name that refers to the array reference \@array. \@array - The reference to the array of data referred to by the template variable 'VAR_NAME'. Only called when a template variable contains an ARRAY reference. Default implementation returns the empty string ``''. callback_HASH usage protected abstract $HTML = $this->callback_HASH( 'VAR_NAME', \%hash ) $HTML - A chunk of html as a string, possibly containing other embedded template variables. 'VAR_NAME' - The template variable name that refers to the hash reference \%hash. \%hash - The reference to the hash of data referred to by the template variable 'VAR_NAME'. Only called when a template variable contains a reference to a HASH. Default implementation returns the empty string ``''. callback_SCALAR usage protected abstract $HTML = $this->callback_SCALAR( 'VAR_NAME', \$scalar ) $HTML - A chunk of html as a string, possibly containing other embedded template variables. 'VAR_NAME' - The template variable name that refers to the scalar reference \$scalar. \$scalar - The reference to the scalar referred to by the template variable 'VAR_NAME'. Only called when a template variable contains a reference to a scalar. Default implementation returns the empty string ``''. callback_GLOB usage protected abstract $HTML = $this->callback_GLOB( 'VAR_NAME', \*glob ) $HTML - A chunk of html as a string, possibly containing other embedded template variables. 'VAR_NAME' - The template variable name that refers to the typeglob reference \*glob. \*glob - The reference to the typeglob referred to by the template variable 'VAR_NAME'. Since you may even want to do something innovative with typeglob references, voila. i don't see why you couldn't pass open filehandles or open sockets, though i haven't tried, yet. Default implementation returns the empty string ``''. ------------------------------------------------------------------------ CREDITS Authors and contacts Matt Harrison ; Brian Ng ; Brian Slesinsky This module is based on an original version of a module by Brian Ng, which in turn was based on an original work by Brian Slesinsky. Almost all of Brian Ng's version was rewritten by Matt Harrison to include a superset of the functionality present in the original, in order to support things like callbacks, references, and nested variables in template variables. This new module forms the delivery backbone of an as yet publically-unreleased bioinformatics project. This module is fully backwardly compatible with Brian's module as far as i am aware. Please feel free to contact me, matt harrison, for technical comments and/or suggestions for improvement, stupid things i've done or whatever. Questions about usage not covered by the document are probably also welcome. Enjoy. Legalese Copyright 2000 Matt Harrison; all rights reserved. Written during the month of april 2000, Matt Harrison. Some pieces of code were taken verbatim from Brian's module - this code is his. This program is free software; you are free to redistribute it and/or modify it under the same terms as Perl itself. The authors make no claim of warranty, express, implied or even vaguely hinted at. This means: you use it at your own risk.