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

NAME

Data::Xslate - Templatize your data.

SYNOPSIS

    use Data::Xslate;
    
    my $xslate = Data::Xslate->new();
    
    my $output = $xslate->render( $input );

Given this input data structure:

    {
        color_names => ['red', 'blue', 'orange'],
        email => {
            message => 'Do you like the color <: $user.color_name :>?',
            subject => 'Hello <: $user.name :>!',
            to      => '=user.email',
        },
        'email.from=' => 'george@example.com',
        user => {
            color_id => 2,
            color_name => '<: node("color_names")[$color_id] :>',
            email => '<: $login :>@example.com',
            login => 'john',
            name  => 'John',
        },
    }

This data will be output:

    {
        color_names => ['red', 'blue', 'orange'],
        email => {
            from => 'george@example.com',
            message => 'Do you like the color orange?',
            subject => 'Hello John!',
            to => 'john@example.com',
        },
        user => {
            color_id => '2',
            color_name => 'orange',
            email => 'john@example.com',
            login => 'john',
            name => 'John',
        },
    }

DESCRIPTION

This module provides a syntax for templatizing data structures.

Templating

The most powerful feature by far is templating, where you can use Text::Xslate in your values.

    {
        foo => 'green',
        bar => 'It is <: $foo :>!',
    }
    # { foo=>'green', bar=>'It is green!' }

There is a lot you can do with this beyond simply including values from other keys:

    {
        prod => 1,
        memcached_host => '<: if $prod { :>memcached.example.com<: } else { :>127.0.0.1<: } :>',
    }
    # { prod=>1, memcached_host=>'memcached.example.com' }

Values in arrays are also processed for templating:

    {
        ceo_name => 'Sara',
        employees => [
            '<: $ceo_name :>',
            'Fred',
            'Alice',
        ],
    }
    # {
    #     ceo_name => 'Sara',
    #     employees => [
    #         'Sara',
    #         'Fred',
    #         'Alice',
    #     ],
    # }

As well as using array values in a template:

    { foo=>'<: $bar.1 :>', bar=>[4,5,6] }
    # { foo=>5, bar=>[4,5,6] }

Data structures of any arbitrary depth and complexity are handled correctly, and keys from any level can be referred to following the "Scope" rules.

Substitution

Substituion allows you to retrieve a value from one key and use it as the value for the current key. To do this your hash or array value must start with the "substitution_tag" (defaults to =):

    {
        foo => 14,
        bar => '=foo',
    }
    # { foo=>14, bar=>14 }

Templating could be used instead of substitution:

    {
        foo => 14,
        bar => '<: $foo :>',
    }

But, templating only works with strings. Substitutions become vital when you want to substitute an array or hash:

    {
        foo => [1,2,3],
        bar => '=foo',
    }
    # { foo=>[1,2,3], bar=>[1,2,3] }

The keys in substitution follow the "Scope" rules.

Nested Keys

When setting a key value the key can point deeper into the structure by separating keys with the "key_separator" (defaults to a dot, .), and ending the key with the "nested_key_tag" (defaults to =). Consider this:

    { a=>{ b=>1 }, 'a.b=' => 2 }
    # { a=>{ b=>2 } }

So, nested keys are a way to set values in other data structures. This feature is very handy when you are merging data structures from different sources and one data structure will override a subset of values in the other.

Key Paths

When referring to other values in "Templating", "Substitution", or "Nested Keys" you are specifying a path made up of keys for this module to walk and find a value to retrieve.

So, when you specify a key path such as foo.bar you are looking for a hash with the key foo who's value is a hash and then retrieving the value of the bar key in it.

Arrays are fully supported in these key paths so that if you specify a key path such as bar.0 you are looking for a hash with the bar key whose value is an array, and then the first value in the array is fetched.

Note that the above examples assume that "key_separator" is a dot (.), the default.

Scope

When using either "Substitution" or "Templating" you specify a key to be acted on. This key is found using scope-aware rules where the key is searched for in a similar fashion to how you'd expect when dealing with lexical variables in programming.

For example, you can refer to a key in the same scope:

    { a=>1, b=>'=a' }

You may refer to a key in a lower scope:

    { a=>{ b=>1 }, c=>'=a.b' }

You may refer to a key in a higher scope:

    { a=>{ b=>'=c' }, c=>1 }

You may refer to a key in a higher scope that is nested:

    { a=>{ b=>'=c.d' }, c=>{ d=>1 } }

The logic behind this is pretty flexible, so more complex use cases will just work like you would expect.

If you'd rather avoid this scoping you can prepend any key with the "key_separator" (defaults to a dot, .), and it will be looked for at the root of the config data only.

In the case of templating a special node function is provided which will allow you to retrieve an absolute key. For example these two lines would do the same thing (printing out a relative key value):

    <: $foo.bar :>
    <: node("foo.bar") :>

But if you wanted to refer to an absolute key you'd have to do this:

    <: node(".foo.bar") :>

ARGUMENTS

Any arguments you pass to new, which this class does not directly handle, will be used when creating the underlying Text::Xslate object. So, any arguments which Text::Xslate supports may be set. For example:

    my $xslate = Data::Xslate->new(
        substitution_tag => ']]', # A Data::Xslate argument.
        verbose          => 2,    # A Text::Xslate argument.
    );

substitution_tag

The string to look for at the beginning of any string value which signifies "Substitution". Defaults to =. This is used in data like this:

    { a=>{ b=>2 }, c => '=a.b' }
    # { a=>{ b=>2 }, c => 2 }

nested_key_tag

The string to look for at the end of any key which signifies "Nested Keys". Defaults to =. This is used in data like this:

    { a=>{ b=>2 }, 'a.c=' => 3 }
    # { a=>{ b=>2, c=>3 } }

key_separator

The string which will be used between keys. The default is a dot (.) which looks like this:

    { a=>{ b=>2 }, c => '=a.b' }

Whereas, for example, if you changed the key_separator to a forward slash it would look like this:

    { a=>{ b=>2 }, c => '=a/b' }

Which looks rather good with absolute keys:

    { a=>{ b=>2 }, c => '=/a/b' }

METHODS

render

    my $data_out = $xslate->render( $data_in );

Processes the data and returns new data. The passed in data is not modified.

SUPPORT

Please submit bugs and feature requests to the Data-Xslate GitHub issue tracker:

https://github.com/bluefeet/Data-Xslate/issues

AUTHORS

    Aran Clary Deltac <bluefeet@gmail.com>
    Mohammad S Anwar <mohammad.anwar@yahoo.com>

ACKNOWLEDGEMENTS

Thanks to ZipRecruiter for encouraging their employees to contribute back to the open source ecosystem. Without their dedication to quality software development this distribution would not exist.

LICENSE

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