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, likeThis is {{$dist->name}} version {{$dist->version}}…
but
$dist
gives full access toDist::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
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.