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

NAME

HTML::Template::Compiled - Template System Compiles HTML::Template files to Perl code

VERSION

our $VERSION = "0.57";

SYNOPSIS

  use HTML::Template::Compiled;
  my $htc = HTML::Template::Compiled->new(filename => 'test.tmpl');
  $htc->param(
    BAND => $name,
    ALBUMS = [
      { TITLE => $t1, YEAR => $y1 },
      { TITLE => $t2, YEAR => $y2 },
    ],
  );
  print $htc->output;

  test.tmpl:
  Band: <TMPL_VAR BAND>
  <TMPL_LOOP ALBUMS>
  Title: <TMPL_VAR TITLE> (<TMPL_VAR YEAR>)
  </TMPL_LOOP>

DESCRIPTION

HTML::Template::Compiled (HTC) is a template system which uses the same template syntax as HTML::Template and the same perl API. Internally it works different, because it turns the template into perl code, and once that is done, generating the output is much faster than with HTML::Template (4-5 times at the moment, at least with my tests). It also can generate perl files so that the next time the template is loaded it doesn't have to be parsed again. The best performance gain is probably reached in applications running under mod_perl, for example.

If you don't use caching at all, HTC will be even slower than H::T (but still a bit faster than Template-Toolkit. See the examples/bench.pl.

HTC will use a lot of memory because it keeps all template objects in memory. If you are on mod_perl, and have a lot of templates, you should preload them at server startup to be sure that it is in shared memory. At the moment HTC is not tested for keeping all data in shared memory (e.g. when a copy-on-write occurs), but i'll test that soon. For preloading you can now use HTML::Template::Compiled->preload($dir).

HTC does not implement all features of HTML::Template (yet), and it has got some additional features which are explained below.

HTC will complain if you have a closing tag that does not fit the last opening tag. To get the line number, set the line_numbers-option (See "OPTIONS" below)

NOTE: If you don't need any of the additional features listed below and if you don't need the speed (in many cases it's probably not worth trading speed for memory), then you might be better off with just using HTML::Template.

NOTE2: If you have any questions, bug reports, send them to me and not to Sam Tregar. This module is developed by me at the moment, independently from HTML::Template, although I try to get most of the tests from it passing for HTC. See "RESOURCES" for current information.

FEATURES FROM HTML::TEMPLATE

TMPL_VAR
TMPL_LOOP
TMPL_(IF|UNLESS|ELSE)
TMPL_INCLUDE
HTML_TEMPLATE_ROOT
ESCAPE=(HTML|URL)
DEFAULT=...
__first__, __last__, __inner__, __odd__, __counter__
<!-- TMPL_VAR NAME=PARAM1 -->
case insensitive var names

use option case_sensitive => 0 to use this feature

filters
vars that are subrefs
scalarref, arrayref, filehandle
global_vars

new (roughly tested)

ADDITIONAL FEATURES

TMPL_ELSIF
TMPL_WITH
TMPL_COMMENT

see "TMPL_COMMENT"

TMPL_NOPARSE

see "TMPL_NOPARSE"

TMPL_SWITCH, TMPL_CASE

see "TMPL_SWITCH"

Generating perl code
more variable access

see "VARIABLE ACCESS"

rendering objcets

see "RENDERING OBJECTS"

output to filehandle
Dynamic includes

see "INCLUDE"

TMPL_IF DEFINED

Check for definedness instead of truth: <TMPL_IF DEFINED NAME="var">

asp/jsp-like templates

For those who like it (i like it because it is shorter than TMPL_), you can use <% %> tags and the <%= tag instead of <%VAR (which will work, too):

 <%IF blah%>  <%= VARIABLE%>  <%/IF%>

MISSING FEATURES

There are some features of H::T that are missing and that I don't plan to implement. I'll try to list them here.

die_on_bad_params

I don't think I'll implement that in the near future.

DIFFERENT DEFAULTS

At the moment there are three defaults that differ from HTML::Template:

case_sensitive

default is 1. Set it via $HTML::Template::Compiled::CASE_SENSITIVE_DEFAULT = 0 Note (again): this will slow down templating a lot.

subref variables

default is 0. Set it via $HTML::Template::Compiled::ENABLE_SUB = 1

search_path_on_include

default is 1. Set it via $HTML::Template::Compiled::SEARCHPATH = 0

To be compatible with all use:

  use HTML::Template::Compiled compatible => 1;

ESCAPING

Like in HTML::Template, you have ESCAPE=HTML and ESCAPE=URL. (ESCAPE=1 will follow.) Additionally you have ESCAPE=DUMP, which by default will generate a Data::Dumper output. You can change that output by setting a different dumper function, see "OPTIONS" dumper.

You can also chain different escapings, like ESCAPE=DUMP|HTML.

INCLUDE

Additionally to

  <TMPL_INCLUDE NAME="file.htc">

you can do an include of a template variable:

  <TMPL_INCLUDE VAR="file_include_var">
  $htc->param(file_include_var => "file.htc");

Here the VAR= part is necessary to distinguish from a static include.

VARIABLE ACCESS

With HTC, you have more control over how you access your template parameters. An example:

  my %hash = (
    SELF => '/path/to/script.pl',
    LANGUAGE => 'de',
    BAND => 'Bauhaus',
    ALBUMS => [
    {
      NAME => 'Mask',
      SONGS => [ { NAME => 'Hair of the Dog' }, ... ],
    },
    ],
    INFO => {
      BIOGRAPHY => '...',
      LINK => '...'
    },
  );

Now in the TMPL_LOOP ALBUMS you would like to access the path to your script, stored in $hash{SELF}. in HTML::Template you have to set the option global_vars, so you can access $hash{SELF} from everywhere. Unfortunately, now NAME is also global, which isn't a problem in this simple example, but in a more complicated template this is impossible. With HTC, you wouldn't use global_vars here, but you can say:

  <TMPL_VAR .SELF>

to access the root element, and you could even say .INFO.BIOGRAPHY or ALBUMS.0.SONGS.0.NAME

RENDERING OBJECTS

This is still experimental. You have been warned.

Additionally to feeding a simple hash do HTC, you can feed it objects. To do method calls you can use '->' in the template or define a different string if you don't like that.

  my $htc = HTML::Template::Compiled->new(
    ...
    method_call => '.', # default ->
    deref       => '/', # default .
  );

  $htc->param(
    VAR => "blah",
    OBJECT => bless({...}, "Your::Class"),
  );

  <TMPL_VAR NAME="OBJECT.fullname">
  <TMPL_WITH OBJECT>
  Name: <TMPL_VAR _.fullname>
  </TMPL_WITH>

fullname will call the fullname method of your Your::Class object. You have to use _ here because with using only fullname HTC couldn't know if you want to dereference a hash or do a method call.

The default values might change in the future depending on what people use most, so at the moment it's the best to always set the options.

And please don't set deref and method call to the same value - this won't work.

DEBUGGING

For printing out the contents of all the parameters you can do:

  <TMPL_LOOP ALBUMS>
  Dump: <TMPL_VAR _ ESCAPE=DUMP|HTML>
  </TMPL_LOOP>

The special name _ gives you the current parameter and ESCAPE=DUMP will by default generate a Data::Dumper output of the current variable, in this case it will dump out the contents of every album in a loop. To correctly display that in html |HTML will escape html entities.

TMPL_WITH

If you have a deep leveled hash you might not want to write THE.FULL.PATH.TO.YOUR.VAR always. Jump to your desired level once and then you need only one level. Compare:

  <TMPL_WITH DEEP.PATH.TO.HASH>
  <TMPL_VAR NAME>: <TMPL_VAR AGE>
  </TMPL_WITH>

  <TMPL_VAR DEEP.PATH.TO.HASH.NAME>: <TMPL_VAR DEEP.PATH.TO.HASH.AGE>

TMPL_LOOP

The special name _ gives you the current paramater. In loops you can use it like this:

 <tmpl_loop foo>
  Current item: <tmpl_var _ >
 </tmpl_loop>

TMPL_COMMENT

For debugging purposes you can temporarily comment out regions:

  <tmpl_var wanted>
    <tmpl_comment outer>
      <tmpl_comment inner>
        <tmpl_var unwanted>
      </tmpl_comment inner>
      <tmpl_var unwanted>
  </tmpl_comment outer>

  $htc->param(unwanted => "no thanks", wanted => "we want this");

The output is (whitespaces stripped):

  we want this
  <tmpl_var unwanted>
  <tmpl_var unwanted>

HTC will ignore anything between COMMENT directives. This is useful for debugging, and also for documentation inside the template which should not be outputted.

TMPL_NOPARSE

Anything between

  <tmpl_noparse>...</tmpl_noparse>

will not be recognized as template directives. Same syntax as TMPL_COMMENT. It will output the content, though.

TMPL_SWITCH

The SWITCH directive has the same syntax as VAR, IF etc. The CASE directive takes a simple string or a comma separated list of strings. Yes, without quotes. I might add that if someone finds it useful.

 <tmpl_switch language>(or <tmpl_switch name=language>)
  <tmpl_case de>echt cool
  <tmpl_case en>very cool
  <tmpl_case es>superculo
  <tmpl_case fr,se>don't speak french or swedish
  <tmpl_case default>sorry, no translation for cool in language <%=lang%> available
  <tmpl_case>(same as default)
 </tmpl_switch>

OPTIONS

path

Path to template files

search_path_on_include

Search the list of paths spcified with path when including a tmplate. Default is 1 (different from HTML::Template).

cache_dir

Path to caching directory (you have to create it before)

filename

Template to parse

scalarref

Reference to a scalar with your template content. It's possible to cache scalarrefs, too, if you have Digest::MD5 installed. Note that your cache directory might get filled with files from earlier versions. Clean the cache regularly.

Don't cache scalarrefs if you have dynamic strings. Your memory might get filled up fast! Use the (still undocumented) option

  cache => 0

to disable memory caching.

arrayref

Reference to array containing lines of the template content (newlines have to be included)

filehandle

Filehandle which contains the template content. Note that HTC will not cache templates created like this.

loop_context_vars

Vars like __first__, __last__, __inner__, __odd__, __counter__

global_vars

If set to 1, every outer variable can be accessed from anywhere in the enclosing scope.

deref

Define the string you want to use for dereferencing, default is . at the moment:

 <TMPL_VAR hash.key>
method_call

Define the string you want to use for method calls, default is -> at the moment:

 <TMPL_VAR object->method>
 
line_numbers

For debugging: prints the line number of the wrong tag, e.g. if you have a /TMPL_IF that does not have an opening tag.

case_sensitive

default is 1, set it to 0 to use this feature like in HTML::Template. Note that this can slow down your program a lot.

dumper
  my $t = HTML::Template::Compiled->new(
    ...
    dumper = sub { my_cool_dumper($_[0]) },
  );
  ---
  <TMPL_VAR var ESCAPE=DUMP>
 

This will call my_cool_dumper() on var.

Alternatively you can use the DHTML plugin which is using Data::TreeDumper and Data::TreeDumper::Renderer::DHTML. You'll get a dumper like output which you can collapse and expand, for example. See Data::TreeDumper and Data::TreeDumper::Renderer::DHTML for more information. Example:

  my $t = HTML::Template::Compiled->new(
    ...
    dumper = 'DHTML',
  );
 

For an example see examples/dhtml.html.

out_fh
  my $t = HTML::Template::Compiled->new(
    ...
    out_fh => 1,
  );
  ...
  $t->output($fh); # or output(\*STDOUT) or even output()

This option is fixed, so if you create a template with out_fh, every output of this template will print to a specified (or default STDOUT) filehandle.

filter

Filter template code before parsing.

  my $t = HTML::Template::Compiled->new(
    ...
    filter => sub { myfilter( ${$_[0]} ) },
    # or
    filter => [ {
        sub => sub { myfilter( ${$_[0]} ) },
        format => 'scalar', # or array
      },
      ...
    ],
  );
formatter

With formatter you can spcify how an object should be rendered. This is useful if you don't want object methods to be called, but only a given subset of methods.

  my $htc = HTML::Template::Compiled->new(
  ...
  formatter => {
    'Your::Class' => {
      fullname => sub {
        $_[0]->first . ' ' . $_[0]->last
      },
      first => Your::Class->can('first'),
      last => Your::Class->can('last'),
      },
    },
    formatter_path => '/', # default '/'
  );
  # $obj is a Your::Class object
  $htc->param(obj => $obj);
  # Template:
  # Fullname: <tmpl_var obj/fullname>
formatter_path

see formatter. Defaults to '/'

debug

If set to 1 you will get the generated perl code on standard error

METHODS

clear_cache ([DIR])

Class method. It will clear the memory cache either of a specified cache directory:

  HTML::Template::Compiled->clear_cache($cache_dir);

or all memory caches:

  HTML::Template::Compiled->clear_cache();
clear_filecache

Class- or object-method. Removes all generated perl files from a given directory.

  # clear a directory
  HTML::Template::Compiled->clear_filecache('cache_directory');
  # clear this template's cache directory (and not one template file only!)
  $htc->clear_filecache();
preload

Class method. Will preload all template files from a given cachedir into memory. Should be done, for example in a mod_perl environment, at server startup, so all templates go into shared memory

  HTML::Template::Compiled->preload($cache_dir);

If you don't do preloading in mod_perl, memory usage might go up if you have a lot of templates.

clear_params

Empty all parameters.

EXPORT

None.

CACHING

You create a template almost like in HTML::Template:

  my $t = HTML::Template::Compiled->new(
    path => 'templates',
    loop_context_vars => 1,
    filename => 'test.html',
    # for testing without cache comment out
    cache_dir => "cache",
  );

The next time you start your application and create a new template, HTC will read all generated perl files, and a call to the constructor like above won't parse the template, but just use the loaded code. If your template file has changed, though, then it will be parsed again.

You can set $HTML::Template::Compiled::NEW_CHECK to the amount of seconds you want to wait until the template is expired. So $HTML::Template::Compiled::NEW_CHECK = 60 * 10; will check after 10 minutes if the tmpl file was modified. Set it to a very high value will then ignore any changes, until you delete the generated code.

TODO

fix path option, query, implement expressions, ...

BUGS

At the moment files with no newline at the end of the last line aren't correctly parsed.

Probably many more bugs I don't know yet =)

Why another Template System?

You might ask why I implement yet another templating system. There are so many to choose from. Well, there are several reasons.

I like the syntax of HTML::Template *because* it is very restricted. It's also easy to use (template syntax and API). However, there are some things I miss I try to implement here.

I think while HTML::Template is quite good, the implementation can be made more efficient (and still pure Perl). That's what I'm trying to achieve.

I use it in my web applications, so I first write it for myself =) If I can efficiently use it, it was worth it.

RESOURCES

See http://htcompiled.sf.net/ for current releases not yet on CPAN and for cvs access.

SEE ALSO

HTML::Template

HTML::Template::JIT

Template - Toolkit

http://www.tinita.de/projects/perl/

AUTHOR

Tina Mueller

CREDITS

Sam Tregar big thanks for ideas and letting me use his HTML::Template test suite

Bjoern Kriews for original idea and contributions

Ronnie Neumann, Martin Fabiani, Kai Sengpiel, Sascha Kiefer from perl-community.de for ideas and beta-testing

perlmonks.org and perl-community.de for everyday learning

Corion, Limbic~Region, tye, runrig and others from perlmonks.org

COPYRIGHT AND LICENSE

Copyright (C) 2005 by Tina Mueller

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.8.3 or, at your option, any later version of Perl 5 you may have available.