NAME

Template::Plex - Templates in (P)erl using (Lex)ical Aliasing

SYNOPSIS

Import plex and plx into you package:

    use Template::Plex;

Setup variables/data you want to alias:

    my $vars={
            size=>"large",
            slices=>8,
            people=>[qw<Kim Sam Harry Sally>
            ]
    };
    local $"=", ";

Write a template:

    #Contents of my_template.plex

    Ordered a $size pizza with $slices slices to share between @$people and
    myself.  That averages @{[$slices/(@$people+1)]} slices each.

Load the template with plex:

    my $template= plex "my_template.plex", \%vars;

Render it:

    my $output=$template->render;   

    #OUTPUT
    Ordered a large pizza with 8 slices to share between Kim, Sam, Harry,
    Sally and myself.  That averages 1.6 slices each.     
    

Change values and render it again:

    $vars->{size}="extra large";
    $vars->{slices}=12;
    
    $output=$template->render;

    #OUTPUT
    Ordered a extra large pizza with 12 slices to share between Kim, Sam,
    Harry, Sally and myself.  That averages 2.4 slices each.

DESCRIPTION

This module facilitates the use of perl (not embedded perl) as a text processing template language and system capable of loading, caching and rendering powerful templates.

It does this by implementing a handful of subroutines to perform template loading/management (i.e. plex and plx) and also includes a couple of convenience routines to make processing simpler (i.e. block and jmap).

String::Util string filtering routines are also made available in templates for the most common of filtering tasks. Of course you can use any modules you like within the template, or define your own subroutines within the template. The template is just perl!

Conceptually, a Template::Plex template is just a string in perl's double quoted context, with the outer operators removed:

    #PERL
    "This is a perl string interpolating @{[ map uc, qw<a b c d>]}"

    #  or

    qq{This is a perl string interpolating @{[ map uc, qw<a b c d>]}}
    

    #PLEX template. Same as PERL syntax, without the outer double quotes
    This is a perl string interpolating @{[ map uc, qw<a b c d>]};

    #OUTPUT is the same for all of the above:
    This is a perl string interpolating A B C D

The 'lexical' part of this modules refers to ability of variables to be aliased into the template (more on this later). It improves the style and usage of variables in a template while also allowing sub templates to access/override variables using lexical scoping.

The synopsis example only scratches the surface in terms of what is possible. For more examples, checkout the examples directory in this distribution. I hope to add more in the future

FEATURES

The following are snippets of templates demonstrating some of the feature:

MOTIATION

API

plex

    plex $path, $variables_hash, %options
    

Creates a new instance of a template, loaded from a scalar, file path or an existing file handle.

plx

    plex $path, $variables_hash, %options

Arguments are the same as plex. Similar to the plex subroutine, however it loads, caches and immediately executes the template. Somewhat equivalent to:

    state $template=plex ...;
    $template->render;

The template is cached so that next time plx is called from the same file/line, it reuses the code.

Makes using recursive templates very easy:

    eg
            @{[ plx "path to sub template"]}

Does have the slight overhead of generating cache keys and actually performing the cache lookup compared to manually caching using plex

render

    $obj->render($fields);

This object method renders a template object created by plex into a string. It takes an optional argument $fields which is a reference to a hash containing field variables. fields is aliased into the template as %fields which is directly accessible in the template

    eg
            my $more_data={
                    name=>"John",
            };
            my $string=$template->render($more_data);
            
            #Template:
            My name is $fields{John}

Note that the lexically aliased variables setup in plex or plx are independent to the %fields variable and can both be used simultaneously in a template

include

    @{[include("path")}]

    where $path is path to template file to inject

Used in templates only.

This is a special directive that substitutes the text similar to @{[include("path")]} with the contents of the file pointed to by path. This is a preprocessing step which happens before the template is prepared for execution

This API is only available in templates. If root was included in the options to plex, then it is prepended to path if defined.

When a template is loaded by plex the processing of this is subject to the no_include option. If no_include is specified, any template text that contains the @{[include("path")}] text will result in a syntax error

pl

block

    block { ... }
    pl { ... }

By default this is only exported into a templates namespace. A subroutine which executes a block just like the built in do. However it always returns an empty string.

When used in a template in the @{[]} construct, arbitrary statements can be executed. However, as an empty string is returned, perl's interpolation won't inject anything at that point in the template.

If you DO want the last statement returned into the template, use the built in

do.

    eg
            
            @{[
                    # This will assign a variable for use later in the template
                    # but WILL NOT inject the value 1 into template when rendered
                    pl {
                            $i=1;
                    }

            ]}


            @{[
                    # This will assign a variable for use later in the tamplate
                    # AND immediately inject '1' into the template when rendered
                    do {
                            $i=1
                    }

            ]}

plex_clear

    plex_clear;

Subject to change. Clears all compiled templates from the current level.

jmap

    jmap {block} $delimiter, $array_ref;

Performs a join using $delimiter between each item in the $array_ref after they are processed through block

$delimiter is optional with the default being an empty string

Very handy for rendering lists:

    eg
            <ul>
                    @{[jmap {"<li>$_</li>"} "\n", $items]}
            </ul>

skip

    Template with potential output
    @{[ block {
            skip if $flag;
            }
    ]}
    Any more potential output

This subroutine prevents the current template from generating rendered output. Instead it will return an empty string. Variables can still be manipulated by template before the skip call.

Useful to conditionally skip the body of a template, but configure the variable hash for preprocessing in a @{[block{...}]} structure

FILTERS

There is no special syntax for filters as in other template languages. Filters are simply subroutines and you chain them the usual way in perl:

            @{[ third_filer second_filter first_filter @data]}

To get you started, the string filters from String::Util are imported into the template namespace. This includes:

    collapse     crunch     htmlesc    trim      ltrim
    rtrim        define     repeat     unquote   no_space
    nospace      fullchomp  randcrypt  jsquote   cellfill
    crunchlines  file_get_contents

Please consult the String::Util documentation for details

TIPS ON USAGE

Potential Pitfalls

More on Input Variables

If the variables to apply to the template completely change (note: variables not values), then the aliasing setup during a plex call will not reflect what you want.

However the render method call allows a hash ref containing values to be used. The hash is aliased to the %fields variable in the template.

    my $new_variables={name=>data};
    $template->render($new_variables);

However to use this data the template must be constructed to access the fields directly:

    my $template='my name is $fields{name} and I am $fields{age}';

Note that the %field is aliased so any changes to it is reflected outside the template

Interestingly the template can refer to the lexical aliases and the direct fields at the same time. The lexical aliases only refer to the data provided at preparation time, while the %fields refer to the latest data provided during a render call:

    my $template='my name is $fields{name} and I am $age

    my $base_data={name=>"jimbo", age=>10};

    my $override_data={name=>"Eva"};

    my $template=plex $template, $base_data;

    my $string=$template->render($override_data);
    #string will be "my name is Eva and I am 10

As an example, this could be used to 'template a template' with global, slow changing variables stored as the aliased variables, and the fast changing, per render data being supplied as needed.

Security

This module uses eval to generate the code ref for rendering. This means that your template, being perl code, is being executed. If you do not know what is in your templates, then maybe this module isn't for you.

Aliasing means that the template has access to variables outside of it. That's the whole point. So again if you don't know what your templates are doing, then maybe this module isn't for you

ISSUES

Currently caching of templates when using plx is primitive. It works, but management will likely change. Manual caching with state $template=plex ... gives you better control and performance

Debugging templates could be much better

Unless specifically constructed to write to file, templates are completely processed in memory.

plx caching will not be effective with literal templates unless they are stored in an anonymous array.

SEE ALSO

Yet another template module right?

Do a search on CPAN for 'template' and make a cup of coffee.

REPOSITORY and BUG REPORTING

Please report any bugs and feature requests on the repo page: GitHub

AUTHOR

Ruben Westerberg, drclaw@mac.com

COPYRIGHT AND LICENSE

Copyright (C) 2022 by Ruben Westerberg

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, or under the MIT license