NAME

Dist::Zilla::Role::TextTemplater::Manual - TextTemplater role user manual

VERSION

Version v0.8.7, released on 2018-02-27 21:17 UTC.

WHAT?

Dist-Zilla-Role-TextTemplater is a Dist::Zilla role, a replacement for standard role TextTemplate. Both roles have the same great Text::Template engine under the hood, but this one provides better control over the engine and much better error reporting.

This is TextTemplater role user manual. Read this if you are using a TextTemplater-based plugin.

If you want to have text templating capabilities in your Dist::Zilla plugin, read the module documentation. General topics like getting source, building, installing, bug reporting and some others are covered in the README.

SYNOPSIS

In your dist.ini:

[APlugin]
    delimiters = (* *)
    package    = MY
    prepend    = use strict;
    prepend    = use warnings;
    … ; Other APlugin-specific options.

(It is assumed you are using Text-Templater-based plugin named APlugin.)

DESCRIPTION

For sake of brevity in this manual the term APlugin means "any TextTemplater-based plugin" or "any plugin which consumes TextTemplater role".

TextTemplater is a Dist::Zilla role. It cannot be directly used by the end user. However, the role provides the same behavior and options for all TextTemplater-based plugins (including APlugin, of course). Describing common behavior and options in single place makes documenting APlugin simpler.

TextTemplater is just a bridge between APlugin and the great Text::Template templating engine, so reading Text::Template documentation is highly recommended for better understanding of gory details.

Philosophy

Must read this first: "Philosophy" in Text::Template.

Template

Template is text with (zero or more) embedded Perl code fragments:

…plain text {{ Perl code fragment }} plain text again…

TextTemplater evaluates code fragments in order of appearance and replaces each fragment with the result of its evaluation. For example, template

2 + 2 = {{ 2 + 2 }}.

is processed to

2 + 2 = 4.

The example above is trivial, but Perl code fragments can be arbitrary complex: full Perl power is at your service.

As stated above, template is just text. It could be a source file, a value of an option from your dist.ini, or whatever else — it depends on APlugin. TextTemplater processes ("fills in") the provided template, while providing the template is APlugin responsibility.

Gory details: "Template Parsing" in Text::Template. However, take into account that TextTemplater default delimiters are likely "alternative delimiters" for Text::Template, so backslash escaping does not work.

Delimiters

In order to be recognized a Perl code fragment must be separated from surrounding plain text by the pair of delimiters: opening delimiter and closing delimiter. TextTemplater default opening delimiter is {{, default closing delimiter is }}, they are used in all the code fragment examples in this manual.

Note: APlugin can override TextTemplater default, though. Also, user can set desired delimiters in the delimiters option.

Gory details: "Alternative Delimiters" in Text::Template.

Predefined Variables

There are few predefined variables which can be used in Perl code fragments. TextTemplater defines two variables, and one is defined by Text::Temlate.

Note: APlugin may define more variables or cancel definitions of $plugin and $dist.

$dist

Reference to Dist::Zilla object. Primary purpose of the variable is providing access to the distribution properties, like

This is {{$dist->name}} version {{$dist->version}}…

but $dist gives full access to Dist::Zilla object:

The list of installed modules: {{ join( ", ",
map( { $_->name } @{ $dist->find_files( ":InstallModules" ) } )
); }}.
$plugin

Reference to the plugin. The variable is provided for compatibility with GatherDir::Template plugin. The variable can be used for debug or error reporting, e. g.:

{{ …; $plugin->log_debug( … ); …; }}
{{ …; if ( … ) { $plugin->log_fatal( … ); }; … }}
$OUT

Gory details: "The $OUT variable" in Text::Template.

Package

By default all the code fragments in a template are evaluated in the context of the same private package ("private" is not the package name). The package called "private" because it is created specially for processing of this template, code fragments of another template are evaluated in the context of another private package.

Default behavior can be changed by package option. If value of the option is not empty, all templates share the same package. Use it carefully because one template can affect another template implicitly.

Note: APlugin can set another default or ignore package option specified by user.

Gory details: "PACKAGE" in Text::Template. Note that default behavior (when package is not explicitly set) in Text::Template and TextTemplate differs.

Prepend

If every your Perl code fragment starts with the same prologue (e. g. use strict;), you can let the template engine insert this prologue automatically. Just specify your prologue in the "prepend" option.

Gory details: "PREPEND feature and using strict in templates" in Text::Template.

OPTIONS

The role provides three options: delimiters, package and prepend. Options can be specified by user in the APlugin section of the dist.ini file:

[APlugin]
    delimiters = (* *)
    package    = MY
    prepend    = use strict;

delimiters

Pair of delimiters to separate code fragments from surrounding text, see "Delimiters".

The value should consist of two whitespace-separated delimiters: opening delimiter and closing delimiter. Leading and trailing whitespaces are ignored.

package

Name of package to evaluate code fragments in, see "Package".

prepend

Perl code to automatically prepend to the beginning of every code fragment, see "Prepend".

Option may be specified several times. Every value will be a separate line of code.

prepend = use strict;
prepend = use warnings;
prepend = use utf8;

WHY?

TextTemplate role from Dist::Zilla distribution v5.037 has the same great Text::Template engine under the hood, but lacks of control and has awful error reporting.

Error Reporting

Let us consider an example. For sake of example simplicity, it contains only one file, dist.ini. Two files, lib/Assa.pm and lib/Assa.pod, are generated on-the-fly with GenerateFile plugin.

Have a look at dist.ini:

name     = Assa
version  = 0.001
abstract = Example
[GenerateFile/lib/Assa.pm]
    filename = lib/Assa.pm
    content  = package Assa; 1;
[GenerateFile/lib/Assa/Manual.pod]
    filename = lib/Assa/Manual.pod
    content  = =head1 NAME
    content  =
    content  = {{$dst->name} - {{$dist->abstract}}
    content  =
    content  = Version {{$dist->version}}.
    content  =
    content  = {{$dist->license->notice}}
[TemplateFiles]
    filename = lib/Assa.pm
    filename = lib/Assa/Manual.pod
[MetaResources::Template]
    homepage = https://example.org/release/{{$dist->name}}
    license  = {{$dist->license->url}}

(Do you see a typo? How many? Note this is a small example, real files are much larger.) Now let us build the distribution:

$ dzil build
[DZ] beginning to build Assa
[TemplateFiles] Filling in the template returned undef for:
[TemplateFiles] =head1 NAME
[TemplateFiles]
[TemplateFiles] {{$dst->name} - {{$dist->abstract}}
[TemplateFiles]
[TemplateFiles] Version {{$dist->version}}.
[TemplateFiles]
[TemplateFiles] {{$dist->license->notice}}

[TemplateFiles] Filling in the template returned undef for:
[TemplateFiles] =head1 NAME
[TemplateFiles]
[TemplateFiles] {{$dst->name} - {{$dist->abstract}}
[TemplateFiles]
[TemplateFiles] Version {{$dist->version}}.
[TemplateFiles]
[TemplateFiles] {{$dist->license->notice}}
 at /home/vdb/.usr/opt/local-lib/lib/perl5/x86_64-linux-thread-multi/Moose/Meta/Method/Delegation.pm line 110.

Oops. What's happened? Where? Why? All we have is a highly unclear error message

Filling in the template returned undef for:

and file content printed twice. (Yep, if the file had 1000 lines, we would have it printed twice too.) We do not ever have a file name and have to guess it by the content. Good bug hunting, dude.

Ok, let us fix the problem (mistyped closing delimiter in the first line of file lib/Assa/Manual.pod) and build the distribution again:

$ dzil build
[DZ] beginning to build Assa
Can't call method "name" on an undefined value at template line 3.

Oops. Error message much is better now, but where the problem is? There are many templates in the project: lib/Assa.pm, lib/Assa/Manual.pod, and even resources in META.yml — all are generated from templates. Where is the problem? Good bug hunting for us all.

Such error reporting is simply unacceptable. I am a human, I often make mistakes, and I want the tool clearly warns me what and where the problem is, so I can fix it quickly. For example, in the first case I want to see:

$ dzil build
[DZ] beginning to build Assa
[Templates] Unmatched opening delimiter at lib/Assa/Manual.pod line 3.
[Templates] lib/Assa/Manual.pod:
[Templates]     1: =head1 NAME
[Templates]     2:
[Templates]     3: {{$dst->name} - {{$dist->abstract}}
[Templates]        ^^^ Unmatched opening delimiter at lib/Assa/Manual.pod line 3. ^^^
[Templates]     4:
[Templates]     5: Version {{$dist->version}}.
[Templates]        ... skipped 2 lines ...
Aborting...

In the second case:

$ dzil build
[DZ] beginning to build Assa
[Templates] Can't call method "name" on an undefined value at lib/Assa/Manual.pod line 3.
[Templates] Bad code fragment begins at lib/Assa/Manual.pod line 3.
[Templates] lib/Assa/Manual.pod:
[Templates]     1: =head1 NAME
[Templates]     2:
[Templates]     3: {{$dst->name}} - {{$dist->abstract}}
[Templates]        ^^^ Can't call method "name" on an undefined value at lib/Assa/Manual.pod line 3. ^^^
[Templates]        ^^^ Bad code fragment begins at lib/Assa/Manual.pod line 3. ^^^
[Templates]     4:
[Templates]     5: Version {{$dist->version}}.
[Templates]        ... skipped 2 lines ...
Aborting...

TextTemplater makes it real. All I need is using TextTemplater-based plugins: Templates, MetaResources::Template (starting from v0.002).

Engine Control

TextTemplater allows the end-user to specify delimiters, package and prepend engine options in dist.ini file, while TextTemplate allows to specify prepend only programmatically, and does not allow to specify delimiters and package.

SEE ALSO

Dist::Zilla
Dist::Zilla::Role::TextTemplater
Text::Template

AUTHOR

Van de Bugger <van.de.bugger@gmail.com>

COPYRIGHT AND LICENSE

Copyright (C) 2015, 2016, 2018 Van de Bugger

License GPLv3+: The GNU General Public License version 3 or later <http://www.gnu.org/licenses/gpl-3.0.txt>.

This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law.