The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.
= DESIGN GOALS

* Be Useful
* Support as much of Perl's Template Toolkit (TT2) as feasible
* Avoid cruft and scope explosion.
* Make runtime fast as possible.
* Actually complete the project and become stable.


= OVERVIEW

Jemplate leverages TT2 by using Template::Parser, but replacing the
backend (Template::Directive) with Jemplate::Directive to produce
JavaScript code instead of Perl code.

The typical usage envisioned is that you compile your templates into one
big JavaScript file. Then you import this document and the Jemplate.js
runtime support module in your html.


= Perl API

- Jemplate::Parser->new->parse($template_text);

Parse a single template and return a JavaScript function (as a
string scalar).

- Jemplate->compile_template_files(@template_file_paths);

Take a list of template file paths and compile them into a module of
functions. Returns the text of the module.

- Jemplate->compile_template_content($template_content, $template_name);

Take a template string and its name and return the compiled code.

- Jemplate->compile_module($module_path, \@template_file_paths);

Similar to `compile_templates`, but prints the result to the
$module_path. Returns 1 if successful, undef if error.

- Jemplate->compile_module_cached($module_path, \@template_file_paths);

Similar to `compile_module`, but only compiles if one of the templates
is newer than the module. Returns 1 if successful compile, 0 if no
compile due to cache, undef if error.


= JavaScript API

- Jemplate.process(templateFileName[, dataObject][, outputTarget]);

Returns a string containing the rendering of the template.
templateFileName is something like `my-widget.tt` and dataObject is just
a JavaScript "hash" of data values.

The optional outputTarget can be a string or a function. If it is a
function, the function is called with the result, and `true` is returned.

If it is a string beginning with '#' followed by a word, then the word
is used to locate the DOM element with that id, and the innerHTML of the
element is replaced with the result. (`true` is returned)

If outputTarget is anything else, an exception will be thrown.


= TESTING

Currently we have automated tests in the `t/` directory that prove that
compilation is correct. These tests use Perl's Test::Base data driven
test framework.

There is also a JavaScript runtime testing suite in the `tests/`
directory that you can run by simply loading the index.html file into
any supported browser. These tests use a JavaScript port of the
Test.Base framework.

We also have a more adhoc `examples/` directory with stuff that you need to
run by hand.


= FEATURE CHECKLIST

This is basically a copy of the Template Toolkit Quick Reference Card by
Andrew Ford. This provides a really nice roadmap for Jemplate.

The original is here: http://refcards.com/refcards/tt2/index.html

Index:

   (-) Not done yet but planned.
   (+) Completed feature.
   (=) Partially completed feature.
   (x) Not appropriate for Jemplate.

Each bullet consists of a pair of symbols. The first is for the feature
completion, the second is for the testing of the feature.

== Syntax

=== Directives

    ++ [% [GET] var %]
    ++ [% CALL var %]
    ++ [% [SET] var = value ... %] 
    ++ [% DEFAULT var = value ... %] 
    -- [% META attr = value ... %] 

    -- [% INSERT filename %] 
    ++ [% INCLUDE template [var = value ...] %] 
    ++ [% PROCESS template [var = value ...] %] 
    ++ [% WRAPPER template [var = value ...] %] text... [% END %] 
    ++ [% BLOCK [name] %] content... [% END %] 
    ++ [% FILTER filter %] text... [% END %] 
    +- [% MACRO name[(varlist)] directive %] 
    -- [% USE plugin[(param, ...)] %] 
    xx [% PERL %] code... [% END %] 
    xx [% RAWPERL %] code... [% END %] 
    ++ [% JAVASCRIPT %] code... [% END %]

    ++ [% FOREACH var = list %] ... [% END %] 
    ++ [% WHILE cond %] ... [% END %] 
    ++ [% IF cond %] ... [% ELSIF cond %] ... [% ELSE %] [% END %] 
    ++ [% SWITCH var %] ... [% CASE [{value|DEFAULT}] %] ... [% END %] 
    -- [% TRY %] ... [% CATCH [type] %] ... [% FINAL %] ... [% END %] 
    ++ [% THROW type info ... %] 
    ++ [% NEXT %] 
    ++ [% LAST %] 
    ++ [% RETURN %] 
    ++ [% STOP %] 
    
=== Special variables

    -- template    outermost template being processed - methods: name, modtime 
    -- component   innermost template being processed - methods: name, modtime 
    ++ loop        loop iterator - methods: count, first, last, max, prev, next
    -- error       exception object 
    -- content     captured output for WRAPPER 
    -- global      top level namespace 

=== Virtual methods 

==== Scalar variables 

    ++ chunk(size)     negative size chunks from end 
    ++ defined         is value defined? 
    ++ hash            treat as single-element hash with key value 
    ++ length          length of string representation 
    ++ list            treat as single-item list 
    ++ match(re)       true if value matches re 
    ++ repeat(n)       repeated n times 
    ++ replace(re, sub)    replace instances of re with sub 
    ++ search(re)      returns list of matching subpatterns 
    ++ size            returns 1, as if a single-item list 
    ++ split(re)       split string on re 

==== Hash variables 

    ++ each            list of alternating keys/values 
    ++ exists(key)     does key exist? 
    +- import(hash2)   import contents of hash2 
    +- import          import into current namespace hash 
    +- item            retrieve value using string
    ++ keys            list of keys 
    ++ list            returns alternating key, value 
    ++ nsort           keys sorted numerically 
    ++ size            number of pairs 
    ++ sort            keys sorted alphabetically 
    ++ values          list of values 

==== List variables 

    ++ first           first item in list 
    ++ grep(re)        items matching re 
    ++ join(str)       items joined with str 
    ++ last            last item in list 
    ++ max             maximum index number (i.e. size - 1) 
    ++ merge(list [, list...])     combine lists 
    ++ nsort           items sorted numerically 
    ++ pop             remove first item from list 
    ++ push(item)      add item to end of list 
    ++ reverse         items in reverse order 
    ++ shift           remove last item from list 
    ++ size            number of elements 
    ++ slice(from, to)     subset of list 
    ++ sort            items sorted lexically 
    ++ sort(key)       list of hashes sorted lexically by key "key"
    ++ splice(off, len [,list])    modifies list 
    ++ unique          unique items (retains order) 
    ++ unshift(item)   add item to start of list 

=== Standard filters 

    ++ collapse        collapses whitespace to a single space 
    -- eval(text)      evaluate as template text 
    -- evaltt(text)    evaluate as template text 
    -- evalperl(text)  evaluate text as Perl code 
    -- format(str)     format as per printf() 
    ++ html            performs HTML escaping on ‘<’, ‘>’, ‘&’ 
    ++ html_break      convert empty lines to HTML linebreaks 
    ++ html_entity     performs HTML escaping 
    ++ html_line_break     convert newlines to ‘<br>’ 
    ++ html_para convert   blank lines to HTML paras 
    ++ indent(pad)     indent by pad string or width 
    -- latex(outfmt)   process through LATEX 
    ++ lcfirst         lower case first character 
    ++ lower           convert to lower case 
    ++ null            output to the bit bucket 
    xx perl(text)      evaluate text as Perl code 
    xx redirect(file)  redirect output to file 
    -- remove(re)      removes occurrences of re 
    ++ repeat(n)       repeat n times 
    ++ replace(re, sub)    replace re with sub 
    xx stderr          redirect output to STDERR 
    xx stdout(binmode)     redirect output to STDERR in mode binmode 
    ++ trim            removes leading and trailing whitespace 
    ++ truncate(len)   truncate to length len 
    ++ ucfirst         capitalize first character 
    ++ upper           convert to upper case 
    ++ uri             performs URI-escaping 

=== Standard plugins 

Refer to documentation for details of individual plugins. 

    -- Autoformat      autoformatting with Text::Autoformat 
    -- CGI             interface to CGI.pm 
    -- Datafile        data stored in plain text files 
    -- Date            generates formatted time and date strings 
    -- Directory       interface to directory contents 
    -- DBI             interface to DBI 
    -- Dumper          interface to Data::Dumper 
    -- File            provides general file abstraction 
    -- Format          provides printf-like formatting 
    -- GD::*           provide access to GD graphics library 
    -- HTML            generic HTML generation 
    -- Iterator        iterator creation 
    -- Pod             interface to Pod::POM (POD Object Model) 
    -- String          OO string manipulation interface 
    -- Table           table formatting 
    -- Url             URL construction 
    -- Wrap            simple paragraph wrapping 
    -- XML.DOM         interface to XML Document Object Model 
    -- XML.RSS         interface to XML::RSS 
    -- XML.Simple      interface to XML::Simple 
    -- XML.Style       simple stylesheet transforms of XML 
    -- XML.XPath       interface to XML::XPath 

== Configuration Options

    ++ START_TAG       start of directive token ([%) 
    ++ END_TAG         end of directive token (%]) 
    xx TAG_STYLE       set pre-defined START_TAG/END_TAG style 
    ++ PRE_CHOMP       remove whitespace before directives (0) 
    ++ POST_CHOMP      remove whitespace after directives (0) 
    ++ TRIM remove     leading and trailing whitespace (0) 
    -- INTERPOLATE     interpolate embedded variables (0) 
    ++ ANYCASE         allow lower case directive keywords (0) 

=== Template files and blocks 

    -- INCLUDE_PATH    search path for templates 
    xx DELIMITER       delimiter for separating paths (:) 
    xx ABSOLUTE        allow absolute file names (0) 
    xx RELATIVE        allow relative filenames (0) 
    -- DEFAULT         default template 
    -- BLOCKS          hash array pre-defining template blocks 
    -- AUTO_RESET      reset BLOCK definitions each time (1) 
    -- RECURSION       permit recursion in templates (0) 

=== Template variables 

    -- PRE_DEFINE      hash array of variables and values to pre-define 
    -- VARIABLES       synonym for PRE_DEFINE 

=== Runtime processing options 

    -- EVAL_PERL       process PERL/RAWPERL blocks (0) 
    ++ PRE_PROCESS     template(s) to process before main template 
    +- POST_PROCESS    template(s) to process after main template 
    -- PROCESS         template(s) to process instead of main template 
    -- ERROR           name of error template or reference to hash 
                       array mapping error types to templates 
    -- OUTPUT          default output location or handler 
    -- OUTPUT_PATH     directory into which output files can be written 
    == DEBUG           raise 'undef' error on access to undefined variables 

=== Caching and Compiling Options 

    xx CACHE_SIZE      max compiled templates to cache (undef, i.e. cache all) 
    xx COMPILE_EXT     extension for compiled template files (undef) 
    xx COMPILE_DIR     directory for compiled template files (undef) 

=== Plugins and Filters 

    -- PLUGINS         reference to a hash array mapping plugin
                       names to Perl packages. 
    -- PLUGIN_BASE     base class(es) under which plugins may be found 
    -- LOAD_PERL       load Perl modules if plugin not found (0) 
    -- FILTERS         hash array mapping filter names to filter
                       subroutines or factories. 

=== Compatibility, Customisation and Extension 

    xx V1DOLLAR        backwards compatibility flag 
    -- LOAD_TEMPLATES  list of template providers 
    -- LOAD_PLUGINS    list of plugin providers 
    -- LOAD_FILTERS    list of filter providers 
    -- TOLERANT        set providers to tolerate errors as declinations (0) 
    -- SERVICE         custom service obj (Template::Service) 
    ++ CONTEXT         custom context obj (Template::Context) 
    ++ STASH           custom stash object (Template::Stash) 
    -- PARSER          custom parser object (Template::Parser) 
    -- GRAMMAR         custom grammar obj(Template::Grammar) 

== Command line tools 

    -- tpage           tpage processes supplied templates and sends output
                       to STDOUT
    -- ttree           processes directory hierarchies of templates