NAME

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

SYNOPSIS

    use Template::Plex;

    #Data for templates to alias and access
    my $base_data={
            name=>"James",
            age=>"12",
            fruit=>"banana"
    };


    #The actual template text
    #
    my $inline_template='$name\'s age $age and favourite fruit is $fruit'

    #Preparing the template in Template::Plex object
    #
    my $t=plex [$inline_template], $base_data, %options;


    #Render with the values aliased in $base_data
    $t->render;
    #
    #=>     James's age is 12 and favourite fruit is banana

    #Update the data in the hash used during preparation.
    #
    $base_data->{qw<name,fruit>}=qw<John apple>;


    #Rendering again will use updated aliased values
    #
    $t->render;
    #
    #=>     John's age is 12 and favourite fruit is apple

DESCRIPTION

This module is a mechanism to facilitate the use of perl (not embedded perl) as a text processing template language.

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

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

    #  or

    qq{This is 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 is a perl string interpolating @{[ map uc, qw<a b c d>]};

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

Because of the powerful and flexible interpolation of strings in perl, you can do just about anything in a Plex template. After all the template is just perl.

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.

Some feature highlights:

To get started after installation, copy the following lines into perl and execute:

    use strict;
    use warnings;
    use feature "say";
    use Template::Plex;
    my %vars=(name=>"Susan", age=>99);
    my $template=plex ['this is ${name}\'s inline template. $age young'], \%vars;
    say $template->render;
    
    @vars{qw<name age>}=qw<Richard 23>;
    say $template->render;

For more examples, checkout the examples directory in this distribution.

MOTIATION

TODO

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.

Multi Argument Version

If 2 or more arguments are provided, the template is loaded and prepared and returned. The returned template can be rendered by calling the render method on it.

Single Argument Version

If only the first argument is supplied, the template is loaded, prepared, and rendered immediately. The rendered text is returned. This is useful when using sub templates, as the variables and options are already available from the top level template.

The arguments are detailed below:

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 in plex 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 @{[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

PLEX TEMPLATE SYNTAX \w EXAMPLES

Well, its just perl. Seriously. But if you haven't grasped the concept just yet, a Template::Plex template is a perl program with the two following constraints:

This is best illustrated by example. Suppose the following text is stored in a file or in the __DATA__ section:

    The pot of gold at the end of the rainbow has $amount gold coins
    As for the rainbow, the colors are:
    @{[ map ucfirst."\n", @$colors ]}
    Good day!

Everything in the text is valid syntax in double quote operator, but the outer double quote operator is omitted.

Or in other words, the template looks like plain text, but with double quoted added, it is valid perl code.

Neat!

Following sections show example of particular scenarios

Access to Existing Scalars, Arrays and Hashes

If $variables_hash was supplied during a plex call, the top level elements will be aliased and accessible as normal scalars in the template.

    This template uses a scalar $name that was lexically aliased
    Here the same variable can be accessed via $fields{name}        
    Calling render with an hash argument will override the $fields{name}
    AReallylong${word}WithAVariable

    access the array element $array->[$index]
    Accessing element $hash->{key} just for fun

Executing a single (or list) of Statements

To achieve this, a neat trick is to dereference an inline reference to an anonymous array. That is @{[...]}. The contents of the array is then the result of the statements. Sounds like a mouthful, but it is only a couple of braces and lets you do some powerful things:

    Calling a subrotine @{[ my_sub() ]}
    Doing math a + b = @{[ $a+$b ]}
    Building an array @{[ uc("red"),uc("blue")]}
    Mapping @{[ join "\n", map uc, @items]}
    

Executing Multiple Statements

When a single statement won't do, the do{} construct executes a block, which can have any number of statements and returns the last statement executed into the template

    Executing multiple statments @{[ do {
            my $a=1; 
            $a++; 
            ($a,-$a)

    } ]} in this template

Using/Requiring Modules

Again standard perl syntax for the win

    Template will call hi res time 
    The time is: @{[ time ]}
    @{[ do {
            BEGIN {
                    use Time::HiRes qw<time>;
            }
    }
    ]}

Declaring Variables

Variables can be declared in the @{[..}] container.

my variables will only be visible within the @{[..]} block it was defined.

    eg      #render a mini single line template with my variable
            @{[ do {
                    my $a=time;
                    $a+=23;
                    "Time is: $a";  
            } }]

our variables can be used instead of my variables and are visible throughout the current template, including recursively used templates

    eg
            @{[ do {
                    our $a=time;
                    "";
            } }]
            
            Template package variable is $a

            @{[ do {
                    $a+=23:
                    ""
            } ]}
            Updated template package variable is $a

Sub templates loaded with include and recursive plex calls will have direct access to package variables created in the template. A new unique package is created for each top level use of plex to prevent name collisions.

TIPS ON USAGE

Points to note

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

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