File Coverage

blib/lib/Dist/Zilla/Role/TextTemplater.pm
Criterion Covered Total %
statement 112 113 99.1
branch 31 34 91.1
condition 7 11 63.6
subroutine 21 21 100.0
pod 4 4 100.0
total 175 183 95.6


line stmt bran cond sub pod time code
1             # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2             #
3             # file: lib/Dist/Zilla/Role/TextTemplater.pm
4             #
5              
6             #pod =encoding UTF-8
7             #pod
8             #pod =head1 COPYRIGHT AND LICENSE
9             #pod
10             #pod Copyright © 2015 Van de Bugger
11             #pod
12             #pod This file is part of perl-Dist-Zilla-Role-TextTemplater.
13             #pod
14             #pod perl-Dist-Zilla-Role-TextTemplater is free software: you can redistribute it and/or modify it
15             #pod under the terms of the GNU General Public License as published by the Free Software Foundation,
16             #pod either version 3 of the License, or (at your option) any later version.
17             #pod
18             #pod perl-Dist-Zilla-Role-TextTemplater is distributed in the hope that it will be useful, but
19             #pod WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
20             #pod PARTICULAR PURPOSE. See the GNU General Public License for more details.
21             #pod
22             #pod You should have received a copy of the GNU General Public License along with
23             #pod perl-Dist-Zilla-Role-TextTemplater. If not, see <http://www.gnu.org/licenses/>.
24             #pod
25             #pod =cut
26              
27             # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
28              
29             #pod =for :this This is C<Dist::Zilla::Role::TextTemplater> module documentation. Read this if you want to
30             #pod have text templating capabilities in your Dist::Zilla plugin.
31             #pod
32             #pod =for :those If you are using a C<TextTemplater>-based plugin, read the
33             #pod L<manual|Dist::Zilla::Role::TextTemplater::Manual>. General topics like getting source, building, installing, bug
34             #pod reporting and some others are covered in the F<README>.
35             #pod
36             #pod =head1 SYNOPSIS
37             #pod
38             #pod =for test_synopsis my ( $result, $template, $file );
39             #pod
40             #pod package Dist::Zilla::Plugin::YourPlugin;
41             #pod use Moose;
42             #pod use namespace::autoclean;
43             #pod with 'Dist::Zilla::Role::Plugin';
44             #pod with 'Dist::Zilla::Role::TextTemplater';
45             #pod
46             #pod sub method {
47             #pod my $self = shift( @_ );
48             #pod ...;
49             #pod $result = $self->fill_in_string( $template );
50             #pod ...;
51             #pod };
52             #pod
53             #pod sub another_method {
54             #pod my $self = shift( @_ );
55             #pod ...;
56             #pod $self->fill_in_file( $file );
57             #pod ...;
58             #pod };
59             #pod
60             #pod __PACKAGE__->meta->make_immutable;
61             #pod 1;
62             #pod
63             #pod =head1 DESCRIPTION
64             #pod
65             #pod The role provides a consuming plugin with C<fill_in_string> and C<fill_in_file> methods and bunch
66             #pod of accompanying attributes and F<dist.ini> options.
67             #pod
68             #pod =cut
69              
70             package Dist::Zilla::Role::TextTemplater;
71              
72 1     1   1207165 use Moose::Role;
  1         1  
  1         7  
73 1     1   3210 use namespace::autoclean;
  1         2  
  1         5  
74 1     1   49 use version 0.77;
  1         23  
  1         6  
75              
76             # ABSTRACT: Have text templating capabilities in your Dist::Zilla plugin
77             our $VERSION = 'v0.8.5_01'; # TRIAL VERSION
78              
79             with 'Dist::Zilla::Role::ErrorLogger' => { -version => 'v0.6.0' }; # Need `log_errors_in_file`.
80              
81 1     1   96 use Carp qw{ croak };
  1         1  
  1         53  
82 1     1   4 use Dist::Zilla::File::InMemory;
  1         1  
  1         21  
83 1     1   4 use Dist::Zilla::File::OnDisk;
  1         1  
  1         20  
84 1     1   3 use List::Util qw{ min max };
  1         1  
  1         48  
85 1     1   4 use Text::Template qw{};
  1         2  
  1         1076  
86              
87             # --------------------------------------------------------------------------------------------------
88              
89             # It is a `my` variable, not a sub to keep consumer namespace clean.
90              
91             my $tt_param = sub {
92             my ( $name, $args ) = @_;
93             return Text::Template::_param( $name, %$args ); ## no critic ( ProtectPrivateSubs )
94             };
95              
96             # --------------------------------------------------------------------------------------------------
97              
98             #pod =attr delimiters
99             #pod
100             #pod Pair of opening delimiter and closing delimiter to denote code fragments in template.
101             #pod
102             #pod Attribute introduces F<dist.ini> option with the same name. Option value will be split on
103             #pod whitespaces (result should be two items) to initialize the attribute.
104             #pod
105             #pod C<Str|ArrayRef[Str]>, read-only. Default value is C<[ '{{', '}}' ]>.
106             #pod
107             #pod See C<DELIMITERS> option of L<Text::Template/"fill_in">.
108             #pod
109             #pod Note: Our default delimiters are "alternative delimiters" for C<Text::Template>. It means escaping
110             #pod delimiters with backslash does not work. See L<Text::Template/"Alternative Delimiters">.
111             #pod
112             #pod =cut
113              
114             has delimiters => (
115             is => 'ro',
116             isa => 'Str|ArrayRef[Str]',
117             lazy => 1,
118             default => sub { [ '{{', '}}' ] },
119             trigger => sub {
120             my ( $self, $new ) = @_;
121             if ( not ref( $new ) ) {
122             $new =~ s{\A\s+}{}x; # Drop leading ws, or `split` may leave the first item empty.
123             $new = [ split( qr{\s+}x, $new ) ];
124             @$new == 2
125             or croak "\"delimiters\" value must be Str of *two* whitespace-separated words";
126             $self->{ delimiters } = $new;
127             } else {
128             @$new == 2
129             or croak "\"delimiters\" value must be ArrayRef with *two* elements";
130             };
131             },
132             );
133              
134             # --------------------------------------------------------------------------------------------------
135              
136             #pod =attr package
137             #pod
138             #pod Name of package to evaluate code fragments in.
139             #pod
140             #pod Attribute introduces F<dist.ini> option with the same name.
141             #pod
142             #pod C<Str>, read-only, optional.
143             #pod
144             #pod See C<PACKAGE> option of L<Text::Template/"fill_in">.
145             #pod
146             #pod =cut
147              
148             has package => (
149             is => 'ro',
150             isa => 'Str',
151             init_arg => 'package',
152             );
153              
154             # --------------------------------------------------------------------------------------------------
155              
156             #pod =attr prepend
157             #pod
158             #pod Perl code to prepend to the beginning of every code fragment.
159             #pod
160             #pod Attribute introduces F<dist.ini> multi-value option with the same name.
161             #pod
162             #pod C<ArrayRef[Str]>, read-only, auto dereferenced. Default value is empty array. Consumers may specify
163             #pod alternative default by defining C<_build_prepend> method.
164             #pod
165             #pod See C<PREPEND> option of L<Text::Template/"fill_in">.
166             #pod
167             #pod =cut
168              
169             has prepend => (
170             is => 'ro',
171             isa => 'ArrayRef[Str]',
172             builder => '_build_prepend',
173             auto_deref => 1,
174             );
175              
176             sub _build_prepend {
177 30     30   73266 return [];
178             };
179              
180             # --------------------------------------------------------------------------------------------------
181              
182             #pod =method tt_broken
183             #pod
184             #pod This method is called if a code fragment dies. It formats error message(s) and sends it to the log
185             #pod by calling C<log_error>.
186             #pod
187             #pod See C<BROKEN> option of L<Text::Template/"fill_in">.
188             #pod
189             #pod =cut
190              
191             sub tt_broken {
192 12     12 1 27 my ( $self, %args ) = @_;
193             #
194             # Parse arguments.
195             #
196 12         412 my $tfile = $self->tt_file->name; # Template filename.
197 12         392 my $tline = $args{ lineno }; # Template line where the broken code fragment begins.
198 12         41 my $tmesg = sprintf( 'Bad code fragment begins at %s line %d.', $tfile, $tline );
199 12         14 my $emesg = $args{ error }; # Actual error message.
200 12 100       145 my $eline = $emesg =~ m{ \s at \s \Q$tfile\E \s line \s (\d+)}x ? $1 : 0;
201             # Line of actual error (if it is in template file, zero otherwise).
202 12         30 chomp( $emesg );
203             #
204             # Report errors.
205             #
206 12         46 $self->log_error( $emesg );
207 12         3276 $self->log_error( ' ' . $tmesg );
208             # ^ `croak` when reporting call stack, indents it with tab. Let's do the same. However,
209             # tab has unpredictable width, so let us indent 'call stack' by four spaces.
210             #
211             # Now save errors to report in the template file.
212             #
213 12 100       2401 if ( $eline ) {
214 11         14 push( @{ $self->tt_errors }, $eline => $emesg );
  11         387  
215             };
216 12 100       34 if ( $tline != $eline ) {
217             # Do not report beginning of the bad code fragment if actual error occurred in the
218             # same file and line.
219 5         5 push( @{ $self->tt_errors }, $tline => $tmesg );
  5         142  
220             };
221 12         33 return $emesg;
222             };
223              
224             around tt_broken => sub {
225             my ( $orig, $self, @args ) = @_;
226             ++ $self->{ tt_broken_count };
227             my $rc = $self->$orig( @args );
228             if ( $self->tt_broken_count >= $self->tt_broken_limit ) {
229             $self->log_error( [
230             'Too many errors in %s, only first %d are reported.',
231             $self->tt_file->name,
232             $self->tt_broken_count,
233             ] );
234             $rc = undef;
235             };
236             return $rc;
237             };
238              
239             # --------------------------------------------------------------------------------------------------
240              
241             #pod =attr tt_file
242             #pod
243             #pod File being processed (either actual file or temporary C<InMemory> file when processing a string).
244             #pod Available only during template processing. May be used in C<tt_broken> method.
245             #pod
246             #pod C<Object>, read-only, not an init arg.
247             #pod
248             #pod =cut
249              
250             has tt_file => (
251             isa => 'Object',
252             is => 'ro',
253             init_arg => undef,
254             );
255              
256             # --------------------------------------------------------------------------------------------------
257              
258             #pod =attr tt_errors
259             #pod
260             #pod Errors detected in template file, in format suitable for C<log_errors_in_file> (defined in
261             #pod C<ErrorLogger> role). May be used in C<tt_broken> method.
262             #pod
263             #pod C<ArrayRef>, read-write, not an init arg.
264             #pod
265             #pod =cut
266              
267             has tt_errors => (
268             isa => 'ArrayRef',
269             is => 'rw',
270             init_arg => undef,
271             );
272              
273             # --------------------------------------------------------------------------------------------------
274              
275             #pod =attr tt_broken_count
276             #pod
277             #pod Number of C<tt_broken> calls. The counter is increased before C<tt_broken> call.
278             #pod
279             #pod C<Int>, read-only, not an init arg.
280             #pod
281             #pod =cut
282              
283             has tt_broken_count => (
284             is => 'ro',
285             isa => 'Int',
286             init_arg => undef,
287             default => 0,
288             );
289              
290             # --------------------------------------------------------------------------------------------------
291              
292             #pod =attr tt_broken_limit
293             #pod
294             #pod If number of completed C<tt_broken> calls equals or exceeds this limit, processing stops.
295             #pod
296             #pod C<Int>, read-only, not an init arg, default value 10.
297             #pod
298             #pod There is no (official) way to change the attribute value now. Let me know if you need it.
299             #pod
300             #pod =cut
301              
302             has tt_broken_limit => (
303             is => 'ro',
304             isa => 'Int',
305             init_arg => undef,
306             default => 10,
307             );
308              
309              
310             # --------------------------------------------------------------------------------------------------
311              
312             #pod =method mvp_multivalue_args
313             #pod
314             #pod The method tells C<Dist::Zilla> that C<prepend> is a multi-value option.
315             #pod
316             #pod =cut
317              
318             around mvp_multivalue_args => sub {
319             my ( $orig, $self ) = @_;
320             return ( $self->$orig(), qw{ prepend } );
321             };
322              
323             # --------------------------------------------------------------------------------------------------
324              
325             #pod =method tt_fill_in
326             #pod
327             #pod $file = Dist::Zilla::File::OnDisk( ... ); # or
328             #pod $file = Dist::Zilla::File::InMemory( ... ); # or
329             #pod $file = Dist::Zilla::File::FromCode( ... );
330             #pod
331             #pod $result = $self->fill_in_string( $file, \%variables, \%extra_args );
332             #pod $result = $self->fill_in_string( $file );
333             #pod
334             #pod Internal working horse of the role.
335             #pod
336             #pod The method creates C<Text::Template> object, enforces C<Text::Template> to respect C<filename>
337             #pod argument (see L<FILENAME parameter has no
338             #pod effect|https://rt.cpan.org/Ticket/Display.html?id=106093>), takes care about warnings, then calls
339             #pod C<fill_in> method on the object, making C<Text::Template> compilation errors (if found) more
340             #pod user-friendly.
341             #pod
342             #pod C<< $file->content >> is passed to the C<Text::Template> constructor. C<\%variables>,
343             #pod C<\%extra_args>, and C<package>, C<prepend>, C<broken> attributes are combined and passed to both
344             #pod C<Text::Template> constructor and C<fill_in> method.
345             #pod
346             #pod C<\%variables> become C<hash> C<Text::Template> option (see L<Text::Template/"HASH"> for details).
347             #pod Variables C<plugin> (reference to object executing the method, i. e. C<$self>) and C<dist>
348             #pod (reference to C<Dist::Zilla>, i. e. C<< $self->zilla >>) are added to C<\%variables> automatically,
349             #pod if they are not exist.
350             #pod
351             #pod C<package>, C<prepend>, C<broken> attributes become same-name C<Text::Template> options.
352             #pod C<\%extra_args> is expanded to list and passed last, so caller can override any option specified by
353             #pod C<tt_fill_in> (except C<filename>), for example:
354             #pod
355             #pod $self->tt_fill_in( $file, undef, { package => 'MY' } );
356             #pod
357             #pod will execute template code fragments in context of C<MY> package regardless of C<package>
358             #pod attribute. Another, a bit more complicated example:
359             #pod
360             #pod $self->tt_fill_in( $file, undef, { hash => { } } );
361             #pod
362             #pod processes template with no predefined variables: C<plugin> and C<dist> are added to C<\%variables>,
363             #pod but entire C<\%variables> is overridden by C<hash> extra argument.
364             #pod
365             #pod C<tt_fill_in> takes special care about package: by default nested C<tt_fill_in> calls use the same
366             #pod package as the outermost call. Of course, if C<package> extra argument is explicitly specified in
367             #pod inner call, it takes priority over default package.
368             #pod
369             #pod When defining variables with either C<\%variables> argument or C<hash> extra argument, remember that
370             #pod C<Text::Template> dereferences all the references. It especially important if you want to pass
371             #pod a reference to template:
372             #pod
373             #pod $array = [ … ]; $hash = { … };
374             #pod $self->tt_fill_in(
375             #pod $file,
376             #pod { array => \$array, hash => \$hash, plugin => \$self },
377             #pod );
378             #pod
379             #pod In template, C<$array> will be a reference to array, C<$hash> — reference to hash, C<$plugin> —
380             #pod reference to plugin. If you forget to take references, e. g.:
381             #pod
382             #pod $self->tt_fill_in(
383             #pod $file,
384             #pod { array => $array, hash => $hash, plugin => $self },
385             #pod );
386             #pod
387             #pod template will have C<@array> (not C<$array>) — array, C<%hash> (not C<$hash>) — hash, and
388             #pod C<$plugin> will be (oops!) undefined.
389             #pod
390             #pod Scalars can be passed either by reference or value:
391             #pod
392             #pod $self->tt_fill_in(
393             #pod $file,
394             #pod { str1 => "string", str2 => \"string" },
395             #pod );
396             #pod
397             #pod If C<$file> is mutable (i. e. does C<Dist::Zilla::Role::MutableFile> role), file content will be
398             #pod updated with result of template processing.
399             #pod
400             #pod See L<Text::Template/"HASH"> for more details.
401             #pod
402             #pod =cut
403              
404             sub tt_fill_in {
405 36     36 1 8974 my ( $self, $file, $hash, $args ) = @_;
406 36         155 $self->log_debug( [ 'processing %s', $file->name ] );
407 36 100       8016 my %hash = (
408             plugin => \( $self ),
409             dist => \( $self->zilla ),
410             $hash ? %$hash : (),
411             );
412             my %args = (
413             hash => \%hash,
414             delimiters => $self->delimiters,
415             ( package => $self->package ) x !! $self->package,
416             ( prepend => join( "\n", $self->prepend ) ) x !! $self->prepend,
417             broken => sub {
418 12     12   3855 my ( %args ) = @_; ## no critic ( ProhibitReusedNames )
419 12         62 return $args{ arg }->tt_broken( %args );
420             },
421 36 100       1278 broken_arg => $self,
422             $args ? %$args : (),
423             );
424 36         57 my ( $result, $errors ); {
425             # Original version of the code simply called `Text::Template::fill_in_string` function.
426             # However, this trivial approach does not work good because of `Text::Template` bug: it
427             # ignores `filename` argument, see <https://rt.cpan.org/Ticket/Display.html?id=106093>.
428             # It seems it will not be fixed soon. The bug can be workarounded by setting
429             # `Text::Template` object property `FILENAME`. In order to do it, we need access to
430             # `Text::Template` object, that means we have to create it manually, and then call
431             # `fill_in` method on it.
432 36         48 local $Text::Template::ERROR = undef;
  36         64  
433 36         178 my $tt = Text::Template->new( type => 'STRING', source => $file->content, %args );
434 36 50 33     5451 if ( defined( $tt ) and not defined( $Text::Template::ERROR ) ) {
435 36         88 my $package = $tt_param->( 'package', \%args );
436 36 100 66     479 if ( not defined( $package ) or $package eq '' ) {
437             # If package was not explicitly specified, create a private package.
438 29         205 $package = Dist::Zilla::Role::TextTemplater::_Package->new();
439             };
440             # Save package (either explicitly specified or auto-generated) in `package`
441             # attribute, to let recursive `fill_in_string` calls utilize the same package.
442 36         444 local $self->{ package } = "$package";
443 36         68 local $self->{ tt_file } = $file; # Will be used in `broken`.
444 36         60 local $self->{ tt_errors } = [];
445 36         70 local $self->{ tt_broken_count } = 0;
446 36         88 $tt->{ FILENAME } = $file->name; # Workaround for the bug.
447             {
448 36         1325 local $SIG{ __WARN__ } = sub { # TODO: Create an attribute?
449 4     4   317 my $msg = "$_[ 0 ]"; # Stringify message, it could be an object.
450 4         11 chomp( $msg );
451 4         15 $self->log( $msg );
452 36         260 };
453 36         115 $result = $tt->fill_in( %args, package => "$package" );
454             }
455             # `Text::Template` doc says:
456             # If the `BROKEN` function returns undef, `Text::Template` will immediately abort
457             # processing the template and return the text that it has accumulated so far.
458             # It seems it is not true, `fill_in` returns `undef`, not text accumulated so far.
459 36 100       8602 if ( defined( $Text::Template::ERROR ) ) {
460             # There are only few error message which can be generated by "Text::Template":
461             # Unmatched close brace at line $lineno
462             # End of data inside program text that began at line $prog_start
463             # Couldn't open file $fn: $!
464             # The latter cannot occur because we always fill in strings, never files.
465             # The problem is that these error messages does not include template name. Let us
466             # try to make them more user-friendly.
467 2         6 my $open = qr{\QEnd of data inside program text that began\E}x;
468 2         5 my $close = qr{\QUnmatched close brace\E}x;
469 2         40 my $known = qr{\A (?: ($open) | $close ) \s at \s line \s (\d+) \z }x;
470 2 50       14 if ( $Text::Template::ERROR =~ $known ) {
471 2         4 my ( $type, $line ) = ( $1, $2 );
472 2 100       5 my $msg = $type ? 'Unmatched opening delimiter' : 'Unmatched closing delimiter';
473             # ^ `Text::Template` error message "End of data inside program text that
474             # began at…" is too long at too complicated. Let us replace it with
475             # simpler one.
476 2         5 $Text::Template::ERROR =
477             sprintf( '%s at %s line %d.', $msg, $file->name, $line );
478 2         86 push( @{ $self->tt_errors }, $line => $Text::Template::ERROR );
  2         56  
479             };
480             };
481 36         1194 $errors = $self->tt_errors;
482             };
483 36 100       249 if ( defined( $Text::Template::ERROR ) ) {
484 2         11 $self->log_error( $Text::Template::ERROR );
485             };
486             };
487 36 100       711 if ( @$errors ) {
488 11         36 $self->log_errors_in_file( $file, @$errors );
489             };
490 36         20759 $self->abort_if_error();
491 25 100       870 if ( $file->does( 'Dist::Zilla::Role::MutableFile' ) ) {
492 24         1651 $file->content( $result );
493             };
494 25         11813 return $result;
495             };
496              
497             # --------------------------------------------------------------------------------------------------
498              
499             #pod =method fill_in_string
500             #pod
501             #pod $template = '…';
502             #pod $result = $self->fill_in_string( $template, \%variables, \%extra_args );
503             #pod $result = $self->fill_in_string( $template );
504             #pod
505             #pod The primary method of the role.
506             #pod
507             #pod The C<fill_in_string> interface is compatible with the same-name method of C<TextTemplate> role, so
508             #pod this role can be used as a drop-in replacement for C<TextTemplate>. However, method is
509             #pod implemented slightly differently, it may cause subtle differences in behaviour.
510             #pod
511             #pod The method creates temporary C<Dist::Zilla::File::InMemory> object with name C<"template"> (it can
512             #pod be overridden by C<filename> extra argument, though) and calls C<tt_fill_in> method, passing down
513             #pod temporary file, C<\%variables> and C<\%extra_args>.
514             #pod
515             #pod =cut
516              
517             sub fill_in_string {
518 29     29 1 8046 my ( $self, $string, $hash, $args ) = @_;
519 29   100     121 return $self->tt_fill_in(
520             Dist::Zilla::File::InMemory->new(
521             name => $tt_param->( 'filename', $args ) || 'template',
522             content => $string,
523             ),
524             $hash,
525             $args,
526             );
527             };
528              
529             # --------------------------------------------------------------------------------------------------
530              
531             #pod =method fill_in_file
532             #pod
533             #pod $file = Dist::Zilla::File::OnDisk->new( { … } ); # or
534             #pod $file = Dist::Zilla::File::InMemory->new( { … } ); # or
535             #pod $file = Dist::Zilla::File::FromCode->new( { … } ); # or
536             #pod $file = Path::Tiny->new( 'filename' ); # or
537             #pod $file = Path::Class::File->new( 'filename' ); # or
538             #pod $file = 'filename.ext';
539             #pod
540             #pod $result = $self->fill_in_file( $file, \%variables, \%extra_args );
541             #pod $result = $self->fill_in_file( $file );
542             #pod
543             #pod Similar to C<fill_in_string>, but the first argument is not a template but a file object or file
544             #pod name to read template from. File can be any of C<Dist::Zilla> file types (file is read with
545             #pod C<content> method) or C<Path::Tiny> file (file is read with C<slurp_utf8> method), or
546             #pod C<Path::Class::File> (read by C<< slurp( iomode => '<:encoding(UTF-8)' ) >>) or just a file name
547             #pod (temporary C<Dist::Zilla::File::OnDisk> object is created internally).
548             #pod
549             #pod Note that C<filename> extra argument is ignored, file name cannot be overridden.
550             #pod
551             #pod The method returns result of template processing. If the file is mutable (i. e. does
552             #pod C<Dist::Zilla::Role::MutableFile>) file content is also updated.
553             #pod
554             #pod B<Note:> C<Dist::Zilla::Role::MutableFile> introduced in C<Dist::Zilla> version 5.000. In earlier
555             #pod versions there is no C<Dist::Zilla::Role::MutableFile> role and so, file content is never updated.
556             #pod
557             #pod =cut
558              
559             sub fill_in_file {
560 7     7 1 9822 my ( $self, $file, $hash, $args ) = @_;
561 7         25 my $class = blessed( $file );
562 7 100       22 if ( $class ) {
563 6 100 66     101 if ( $file->isa( 'Moose::Object' ) and $file->does( 'Dist::Zilla::Role::File' ) ) {
    100          
    50          
564             # Do noting.
565             } elsif ( $file->isa( 'Path::Tiny' ) ) {
566 1         5 $file = Dist::Zilla::File::InMemory->new(
567             name => "$file",
568             content => $file->slurp_utf8(),
569             );
570             } elsif ( $file->isa( 'Path::Class::File' ) ) {
571 1         4 $file = Dist::Zilla::File::InMemory->new(
572             name => "$file",
573             content => $file->slurp( iomode => '<:encoding(UTF-8)' ),
574             );
575             } else {
576 0         0 croak "fill_in_file: unsupported file class: $class";
577             };
578             } else {
579 1         38 $file = Dist::Zilla::File::OnDisk->new(
580             name => "$file",
581             );
582             };
583 7         1505 return $self->tt_fill_in( $file, $hash, $args );
584             };
585              
586             # --------------------------------------------------------------------------------------------------
587              
588             # Helper class to create private packages. Actual creation and deletion is implemented in
589             # `Text::Template`, this class just adds automatical package deletion.
590              
591             {
592             ## no critic ( ProhibitMultiplePackages )
593             package Dist::Zilla::Role::TextTemplater::_Package;
594              
595 1     1   7 use strict;
  1         1  
  1         17  
596 1     1   3 use warnings;
  1         1  
  1         45  
597              
598             use overload '""' => sub {
599 58     58   64 my ( $self ) = @_;
600 58         229 return $self->{ name };
601 1     1   3 };
  1         1  
  1         9  
602              
603             sub new {
604 29     29   36 my ( $class ) = @_;
605 29         91 my $self = {
606             name => Text::Template::_gensym(), ## no critic ( ProtectPrivateSubs )
607             };
608 29         165 return bless( $self, $class );
609             };
610              
611             sub DESTROY {
612 29     29   30 my ( $self ) = @_;
613 29         84 Text::Template::_scrubpkg( $self->{ name } ); ## no critic ( ProtectPrivateSubs )
614 29         429 return;
615             };
616              
617             }
618              
619             # --------------------------------------------------------------------------------------------------
620              
621             1;
622              
623             # --------------------------------------------------------------------------------------------------
624              
625             #pod =note C<Text::Template> option spelling
626             #pod
627             #pod C<Text::Template> allows a programmer to use different spelling of options: all-caps, first-caps,
628             #pod all-lowercase, with and without leading dash, e. g.: C<HASH>, C<Hash>, C<hash>, C<-HASH>, C<-Hash>,
629             #pod C<-hash>. This is documented feature.
630             #pod
631             #pod C<Text::Template> recommends to pick a style and stick with it. (BTW, C<Text::Template>
632             #pod documentation itself uses all-caps spelling.) This role picked all-lowercase style. This choice
633             #pod have subtle consequences. Let us consider an example:
634             #pod
635             #pod $self->fill_in_string( $template, undef, { PACKAGE => 'MY' } );
636             #pod
637             #pod Extra option C<PACKAGE> may or may not have effect, depending on value of C<package> attribute (i.
638             #pod e. presence or absence C<package> option in F<dist.ini> file), because (this is not documented)
639             #pod spellings are not equal: different spellings have different priority. If C<PACKAGE> and C<package>
640             #pod are specified simultaneously, C<package> wins, C<PACKAGE> loses.
641             #pod
642             #pod This feature gives you a choice. If you want to ignore option specified by the user in F<dist.ini>
643             #pod and provide your value, use all-lowercase option name. If you want to provide default which can be
644             #pod overridden by the user, use all-caps options name.
645             #pod
646             #pod =cut
647              
648             # --------------------------------------------------------------------------------------------------
649              
650             #pod =note C<filename> option
651             #pod
652             #pod When C<Text::Template> reads template from a file, it uses the actual file name in error messages,
653             #pod e. g.:
654             #pod
655             #pod Undefined subroutine &foo called at dir/filename.ext line n
656             #pod
657             #pod where I<dir/filename.ext> is the name of file containing the template. When C<Text::Template>
658             #pod processes a string, it uses word "template" instead of file name, e. g.:
659             #pod
660             #pod Undefined subroutine &foo called at template line n
661             #pod
662             #pod The option C<filename> allows the caller to override it:
663             #pod
664             #pod $self->fill_in_file( $file, undef, { filename => 'Assa.txt' } );
665             #pod
666             #pod Error message would look like:
667             #pod
668             #pod Undefined subroutine &foo called at Assa.txt line n
669             #pod
670             #pod It may seem this does not make much sense, but in our case (C<Dist::Zilla> and its plugins)
671             #pod C<Text::Template> always processes strings and never reads files, because reading files is a duty
672             #pod of C<Dist::Zilla::File::OnDisk> class. Thus, using C<filename> option is critical to provide good
673             #pod error messages. Actually, C<fill_in_file> implementation looks like
674             #pod
675             #pod $self->fill_in_string(
676             #pod $file->content,
677             #pod undef,
678             #pod { filename => $file->name },
679             #pod );
680             #pod
681             #pod There are two problems with the option, though:
682             #pod
683             #pod =over
684             #pod
685             #pod =item *
686             #pod
687             #pod C<Text::Template> does not document this option.
688             #pod
689             #pod I believe it is a mistake and option should be documented.
690             #pod
691             #pod =item *
692             #pod
693             #pod C<Text::Template> ignores this option.
694             #pod
695             #pod I am sure this is a bug and hope it will be fixed eventually. I am afraid it will not be fixed
696             #pod soon, though.
697             #pod
698             #pod Meanwhile, C<TextTemplater> implements a workaround to let the option work, so C<TextTemplater>
699             #pod consumers can utilize the C<filename> option.
700             #pod
701             #pod =back
702             #pod
703             #pod =cut
704              
705             # --------------------------------------------------------------------------------------------------
706              
707             #pod =head1 SEE ALSO
708             #pod
709             #pod =for :list
710             #pod = L<Dist::Zilla>
711             #pod = L<Dist::Zilla::Role>
712             #pod = L<Dist::Zilla::Plugin>
713             #pod = L<Dist::Zilla::Role::TextTemplate>
714             #pod = L<Text::Template>
715             #pod
716             #pod =cut
717              
718             # doc/what.pod #
719              
720             #pod =encoding UTF-8
721             #pod
722             #pod =head1 WHAT?
723             #pod
724             #pod C<Dist-Zilla-Role-TextTemplater> is a C<Dist::Zilla> role, a replacement for standard role C<TextTemplate>. Both
725             #pod roles have the same great C<Text::Template> engine under the hood, but this one provides better
726             #pod control over the engine and much better error reporting.
727             #pod
728             #pod =cut
729              
730             # end of file #
731             # doc/why.pod #
732              
733             #pod =encoding UTF-8
734             #pod
735             #pod =head1 WHY?
736             #pod
737             #pod C<TextTemplate> role from C<Dist::Zilla> distribution v5.037 has the same great C<Text::Template>
738             #pod engine under the hood, but lacks of control and has I<awful> error reporting.
739             #pod
740             #pod =head2 Error Reporting
741             #pod
742             #pod Let us consider an example. For sake of example simplicity, it contains only one file, F<dist.ini>.
743             #pod Two files, F<lib/Assa.pm> and F<lib/Assa.pod>, are generated on-the-fly with C<GenerateFile>
744             #pod plugin.
745             #pod
746             #pod Have a look at F<dist.ini>:
747             #pod
748             #pod name = Assa
749             #pod version = 0.001
750             #pod abstract = Example
751             #pod [GenerateFile/lib/Assa.pm]
752             #pod filename = lib/Assa.pm
753             #pod content = package Assa; 1;
754             #pod [GenerateFile/lib/Assa/Manual.pod]
755             #pod filename = lib/Assa/Manual.pod
756             #pod content = =head1 NAME
757             #pod content =
758             #pod content = {{$dst->name} - {{$dist->abstract}}
759             #pod content =
760             #pod content = Version {{$dist->version}}.
761             #pod content =
762             #pod content = {{$dist->license->notice}}
763             #pod [TemplateFiles]
764             #pod filename = lib/Assa.pm
765             #pod filename = lib/Assa/Manual.pod
766             #pod [MetaResources::Template]
767             #pod homepage = https://example.org/release/{{$dist->name}}
768             #pod license = {{$dist->license->url}}
769             #pod
770             #pod
771             #pod (Do you see a typo? How many? Note this is a small example, real files are much larger.) Now let us
772             #pod build the distribution:
773             #pod
774             #pod $ dzil build
775             #pod [DZ] beginning to build Assa
776             #pod [TemplateFiles] Filling in the template returned undef for:
777             #pod [TemplateFiles] =head1 NAME
778             #pod [TemplateFiles]
779             #pod [TemplateFiles] {{$dst->name} - {{$dist->abstract}}
780             #pod [TemplateFiles]
781             #pod [TemplateFiles] Version {{$dist->version}}.
782             #pod [TemplateFiles]
783             #pod [TemplateFiles] {{$dist->license->notice}}
784             #pod
785             #pod [TemplateFiles] Filling in the template returned undef for:
786             #pod [TemplateFiles] =head1 NAME
787             #pod [TemplateFiles]
788             #pod [TemplateFiles] {{$dst->name} - {{$dist->abstract}}
789             #pod [TemplateFiles]
790             #pod [TemplateFiles] Version {{$dist->version}}.
791             #pod [TemplateFiles]
792             #pod [TemplateFiles] {{$dist->license->notice}}
793             #pod at /home/vdb/.usr/opt/local-lib/lib/perl5/x86_64-linux-thread-multi/Moose/Meta/Method/Delegation.pm line 110.
794             #pod
795             #pod
796             #pod Oops. What's happened? Where? Why? All we have is a highly unclear error message
797             #pod
798             #pod Filling in the template returned undef for:
799             #pod
800             #pod and file content printed twice. (Yep, if the problem file had 1000 lines, we would have it printed
801             #pod twice too.) We do not ever have a file name and have to guess it by the content. Good bug hunting,
802             #pod dude.
803             #pod
804             #pod Ok, let us fix the problem (mistyped closing delimiter in the first line of file
805             #pod F<lib/Assa/Manual.pod>) and build the distribution again:
806             #pod
807             #pod $ dzil build
808             #pod [DZ] beginning to build Assa
809             #pod Can't call method "name" on an undefined value at template line 3.
810             #pod
811             #pod
812             #pod Oops. Error message much is better now, but where the problem is? There are many templates in the
813             #pod project: F<lib/Assa.pm>, F<lib/Assa/Manual.pod>, and even resources in F<META.yml> — all are
814             #pod generated from templates. Where is the problem? Good bug hunting for us all.
815             #pod
816             #pod Such error reporting is simply unacceptable. I am a human, I often make mistakes, and I want the
817             #pod tool clearly warns me I<what> and I<where> the problem is, so I can fix it quickly. For example,
818             #pod in the first case I want to see:
819             #pod
820             #pod $ dzil build
821             #pod [DZ] beginning to build Assa
822             #pod [Templates] Unmatched opening delimiter at lib/Assa/Manual.pod line 3.
823             #pod [Templates] lib/Assa/Manual.pod:
824             #pod [Templates] 1: =head1 NAME
825             #pod [Templates] 2:
826             #pod [Templates] 3: {{$dst->name} - {{$dist->abstract}}
827             #pod [Templates] ^^^ Unmatched opening delimiter at lib/Assa/Manual.pod line 3. ^^^
828             #pod [Templates] 4:
829             #pod [Templates] 5: Version {{$dist->version}}.
830             #pod [Templates] ... skipped 2 lines ...
831             #pod Aborting...
832             #pod
833             #pod
834             #pod In the second case:
835             #pod
836             #pod $ dzil build
837             #pod [DZ] beginning to build Assa
838             #pod [Templates] Can't call method "name" on an undefined value at lib/Assa/Manual.pod line 3.
839             #pod [Templates] Bad code fragment begins at lib/Assa/Manual.pod line 3.
840             #pod [Templates] lib/Assa/Manual.pod:
841             #pod [Templates] 1: =head1 NAME
842             #pod [Templates] 2:
843             #pod [Templates] 3: {{$dst->name}} - {{$dist->abstract}}
844             #pod [Templates] ^^^ Can't call method "name" on an undefined value at lib/Assa/Manual.pod line 3. ^^^
845             #pod [Templates] ^^^ Bad code fragment begins at lib/Assa/Manual.pod line 3. ^^^
846             #pod [Templates] 4:
847             #pod [Templates] 5: Version {{$dist->version}}.
848             #pod [Templates] ... skipped 2 lines ...
849             #pod Aborting...
850             #pod
851             #pod
852             #pod C<TextTemplater> makes it real. All I need is using C<TextTemplater>-based plugins: C<Templates>,
853             #pod C<MetaResources::Template> (starting from v0.002).
854             #pod
855             #pod =head2 Engine Control
856             #pod
857             #pod C<TextTemplater> allows the end-user to specify C<delimiters>, C<package> and C<prepend> engine
858             #pod options in F<dist.ini> file, while C<TextTemplate> allows to specify C<prepend> only
859             #pod programmatically, and does I<not> allow to specify C<delimiters> and C<package>.
860             #pod
861             #pod =cut
862              
863             # end of file #
864              
865              
866             # end of file #
867              
868             __END__
869              
870             =pod
871              
872             =encoding UTF-8
873              
874             =head1 NAME
875              
876             Dist::Zilla::Role::TextTemplater - Have text templating capabilities in your Dist::Zilla plugin
877              
878             =head1 VERSION
879              
880             Version v0.8.5_01, released on 2016-10-11 20:06 UTC.
881             This is a B<trial release>.
882              
883             =head1 WHAT?
884              
885             C<Dist-Zilla-Role-TextTemplater> is a C<Dist::Zilla> role, a replacement for standard role C<TextTemplate>. Both
886             roles have the same great C<Text::Template> engine under the hood, but this one provides better
887             control over the engine and much better error reporting.
888              
889             This is C<Dist::Zilla::Role::TextTemplater> module documentation. Read this if you want to
890             have text templating capabilities in your Dist::Zilla plugin.
891              
892             If you are using a C<TextTemplater>-based plugin, read the
893             L<manual|Dist::Zilla::Role::TextTemplater::Manual>. General topics like getting source, building, installing, bug
894             reporting and some others are covered in the F<README>.
895              
896             =head1 SYNOPSIS
897              
898             =head1 DESCRIPTION
899              
900             The role provides a consuming plugin with C<fill_in_string> and C<fill_in_file> methods and bunch
901             of accompanying attributes and F<dist.ini> options.
902              
903             =head1 OBJECT ATTRIBUTES
904              
905             =head2 delimiters
906              
907             Pair of opening delimiter and closing delimiter to denote code fragments in template.
908              
909             Attribute introduces F<dist.ini> option with the same name. Option value will be split on
910             whitespaces (result should be two items) to initialize the attribute.
911              
912             C<Str|ArrayRef[Str]>, read-only. Default value is C<[ '{{', '}}' ]>.
913              
914             See C<DELIMITERS> option of L<Text::Template/"fill_in">.
915              
916             Note: Our default delimiters are "alternative delimiters" for C<Text::Template>. It means escaping
917             delimiters with backslash does not work. See L<Text::Template/"Alternative Delimiters">.
918              
919             =head2 package
920              
921             Name of package to evaluate code fragments in.
922              
923             Attribute introduces F<dist.ini> option with the same name.
924              
925             C<Str>, read-only, optional.
926              
927             See C<PACKAGE> option of L<Text::Template/"fill_in">.
928              
929             =head2 prepend
930              
931             Perl code to prepend to the beginning of every code fragment.
932              
933             Attribute introduces F<dist.ini> multi-value option with the same name.
934              
935             C<ArrayRef[Str]>, read-only, auto dereferenced. Default value is empty array. Consumers may specify
936             alternative default by defining C<_build_prepend> method.
937              
938             See C<PREPEND> option of L<Text::Template/"fill_in">.
939              
940             =head2 tt_file
941              
942             File being processed (either actual file or temporary C<InMemory> file when processing a string).
943             Available only during template processing. May be used in C<tt_broken> method.
944              
945             C<Object>, read-only, not an init arg.
946              
947             =head2 tt_errors
948              
949             Errors detected in template file, in format suitable for C<log_errors_in_file> (defined in
950             C<ErrorLogger> role). May be used in C<tt_broken> method.
951              
952             C<ArrayRef>, read-write, not an init arg.
953              
954             =head2 tt_broken_count
955              
956             Number of C<tt_broken> calls. The counter is increased before C<tt_broken> call.
957              
958             C<Int>, read-only, not an init arg.
959              
960             =head2 tt_broken_limit
961              
962             If number of completed C<tt_broken> calls equals or exceeds this limit, processing stops.
963              
964             C<Int>, read-only, not an init arg, default value 10.
965              
966             There is no (official) way to change the attribute value now. Let me know if you need it.
967              
968             =head1 OBJECT METHODS
969              
970             =head2 tt_broken
971              
972             This method is called if a code fragment dies. It formats error message(s) and sends it to the log
973             by calling C<log_error>.
974              
975             See C<BROKEN> option of L<Text::Template/"fill_in">.
976              
977             =head2 mvp_multivalue_args
978              
979             The method tells C<Dist::Zilla> that C<prepend> is a multi-value option.
980              
981             =head2 tt_fill_in
982              
983             $file = Dist::Zilla::File::OnDisk( ... ); # or
984             $file = Dist::Zilla::File::InMemory( ... ); # or
985             $file = Dist::Zilla::File::FromCode( ... );
986              
987             $result = $self->fill_in_string( $file, \%variables, \%extra_args );
988             $result = $self->fill_in_string( $file );
989              
990             Internal working horse of the role.
991              
992             The method creates C<Text::Template> object, enforces C<Text::Template> to respect C<filename>
993             argument (see L<FILENAME parameter has no
994             effect|https://rt.cpan.org/Ticket/Display.html?id=106093>), takes care about warnings, then calls
995             C<fill_in> method on the object, making C<Text::Template> compilation errors (if found) more
996             user-friendly.
997              
998             C<< $file->content >> is passed to the C<Text::Template> constructor. C<\%variables>,
999             C<\%extra_args>, and C<package>, C<prepend>, C<broken> attributes are combined and passed to both
1000             C<Text::Template> constructor and C<fill_in> method.
1001              
1002             C<\%variables> become C<hash> C<Text::Template> option (see L<Text::Template/"HASH"> for details).
1003             Variables C<plugin> (reference to object executing the method, i. e. C<$self>) and C<dist>
1004             (reference to C<Dist::Zilla>, i. e. C<< $self->zilla >>) are added to C<\%variables> automatically,
1005             if they are not exist.
1006              
1007             C<package>, C<prepend>, C<broken> attributes become same-name C<Text::Template> options.
1008             C<\%extra_args> is expanded to list and passed last, so caller can override any option specified by
1009             C<tt_fill_in> (except C<filename>), for example:
1010              
1011             $self->tt_fill_in( $file, undef, { package => 'MY' } );
1012              
1013             will execute template code fragments in context of C<MY> package regardless of C<package>
1014             attribute. Another, a bit more complicated example:
1015              
1016             $self->tt_fill_in( $file, undef, { hash => { } } );
1017              
1018             processes template with no predefined variables: C<plugin> and C<dist> are added to C<\%variables>,
1019             but entire C<\%variables> is overridden by C<hash> extra argument.
1020              
1021             C<tt_fill_in> takes special care about package: by default nested C<tt_fill_in> calls use the same
1022             package as the outermost call. Of course, if C<package> extra argument is explicitly specified in
1023             inner call, it takes priority over default package.
1024              
1025             When defining variables with either C<\%variables> argument or C<hash> extra argument, remember that
1026             C<Text::Template> dereferences all the references. It especially important if you want to pass
1027             a reference to template:
1028              
1029             $array = [ … ]; $hash = { … };
1030             $self->tt_fill_in(
1031             $file,
1032             { array => \$array, hash => \$hash, plugin => \$self },
1033             );
1034              
1035             In template, C<$array> will be a reference to array, C<$hash> — reference to hash, C<$plugin> —
1036             reference to plugin. If you forget to take references, e. g.:
1037              
1038             $self->tt_fill_in(
1039             $file,
1040             { array => $array, hash => $hash, plugin => $self },
1041             );
1042              
1043             template will have C<@array> (not C<$array>) — array, C<%hash> (not C<$hash>) — hash, and
1044             C<$plugin> will be (oops!) undefined.
1045              
1046             Scalars can be passed either by reference or value:
1047              
1048             $self->tt_fill_in(
1049             $file,
1050             { str1 => "string", str2 => \"string" },
1051             );
1052              
1053             If C<$file> is mutable (i. e. does C<Dist::Zilla::Role::MutableFile> role), file content will be
1054             updated with result of template processing.
1055              
1056             See L<Text::Template/"HASH"> for more details.
1057              
1058             =head2 fill_in_string
1059              
1060             $template = '…';
1061             $result = $self->fill_in_string( $template, \%variables, \%extra_args );
1062             $result = $self->fill_in_string( $template );
1063              
1064             The primary method of the role.
1065              
1066             The C<fill_in_string> interface is compatible with the same-name method of C<TextTemplate> role, so
1067             this role can be used as a drop-in replacement for C<TextTemplate>. However, method is
1068             implemented slightly differently, it may cause subtle differences in behaviour.
1069              
1070             The method creates temporary C<Dist::Zilla::File::InMemory> object with name C<"template"> (it can
1071             be overridden by C<filename> extra argument, though) and calls C<tt_fill_in> method, passing down
1072             temporary file, C<\%variables> and C<\%extra_args>.
1073              
1074             =head2 fill_in_file
1075              
1076             $file = Dist::Zilla::File::OnDisk->new( { … } ); # or
1077             $file = Dist::Zilla::File::InMemory->new( { … } ); # or
1078             $file = Dist::Zilla::File::FromCode->new( { … } ); # or
1079             $file = Path::Tiny->new( 'filename' ); # or
1080             $file = Path::Class::File->new( 'filename' ); # or
1081             $file = 'filename.ext';
1082              
1083             $result = $self->fill_in_file( $file, \%variables, \%extra_args );
1084             $result = $self->fill_in_file( $file );
1085              
1086             Similar to C<fill_in_string>, but the first argument is not a template but a file object or file
1087             name to read template from. File can be any of C<Dist::Zilla> file types (file is read with
1088             C<content> method) or C<Path::Tiny> file (file is read with C<slurp_utf8> method), or
1089             C<Path::Class::File> (read by C<< slurp( iomode => '<:encoding(UTF-8)' ) >>) or just a file name
1090             (temporary C<Dist::Zilla::File::OnDisk> object is created internally).
1091              
1092             Note that C<filename> extra argument is ignored, file name cannot be overridden.
1093              
1094             The method returns result of template processing. If the file is mutable (i. e. does
1095             C<Dist::Zilla::Role::MutableFile>) file content is also updated.
1096              
1097             B<Note:> C<Dist::Zilla::Role::MutableFile> introduced in C<Dist::Zilla> version 5.000. In earlier
1098             versions there is no C<Dist::Zilla::Role::MutableFile> role and so, file content is never updated.
1099              
1100             =head1 NOTES
1101              
1102             =head2 C<Text::Template> option spelling
1103              
1104             C<Text::Template> allows a programmer to use different spelling of options: all-caps, first-caps,
1105             all-lowercase, with and without leading dash, e. g.: C<HASH>, C<Hash>, C<hash>, C<-HASH>, C<-Hash>,
1106             C<-hash>. This is documented feature.
1107              
1108             C<Text::Template> recommends to pick a style and stick with it. (BTW, C<Text::Template>
1109             documentation itself uses all-caps spelling.) This role picked all-lowercase style. This choice
1110             have subtle consequences. Let us consider an example:
1111              
1112             $self->fill_in_string( $template, undef, { PACKAGE => 'MY' } );
1113              
1114             Extra option C<PACKAGE> may or may not have effect, depending on value of C<package> attribute (i.
1115             e. presence or absence C<package> option in F<dist.ini> file), because (this is not documented)
1116             spellings are not equal: different spellings have different priority. If C<PACKAGE> and C<package>
1117             are specified simultaneously, C<package> wins, C<PACKAGE> loses.
1118              
1119             This feature gives you a choice. If you want to ignore option specified by the user in F<dist.ini>
1120             and provide your value, use all-lowercase option name. If you want to provide default which can be
1121             overridden by the user, use all-caps options name.
1122              
1123             =head2 C<filename> option
1124              
1125             When C<Text::Template> reads template from a file, it uses the actual file name in error messages,
1126             e. g.:
1127              
1128             Undefined subroutine &foo called at dir/filename.ext line n
1129              
1130             where I<dir/filename.ext> is the name of file containing the template. When C<Text::Template>
1131             processes a string, it uses word "template" instead of file name, e. g.:
1132              
1133             Undefined subroutine &foo called at template line n
1134              
1135             The option C<filename> allows the caller to override it:
1136              
1137             $self->fill_in_file( $file, undef, { filename => 'Assa.txt' } );
1138              
1139             Error message would look like:
1140              
1141             Undefined subroutine &foo called at Assa.txt line n
1142              
1143             It may seem this does not make much sense, but in our case (C<Dist::Zilla> and its plugins)
1144             C<Text::Template> always processes strings and never reads files, because reading files is a duty
1145             of C<Dist::Zilla::File::OnDisk> class. Thus, using C<filename> option is critical to provide good
1146             error messages. Actually, C<fill_in_file> implementation looks like
1147              
1148             $self->fill_in_string(
1149             $file->content,
1150             undef,
1151             { filename => $file->name },
1152             );
1153              
1154             There are two problems with the option, though:
1155              
1156             =over
1157              
1158             =item *
1159              
1160             C<Text::Template> does not document this option.
1161              
1162             I believe it is a mistake and option should be documented.
1163              
1164             =item *
1165              
1166             C<Text::Template> ignores this option.
1167              
1168             I am sure this is a bug and hope it will be fixed eventually. I am afraid it will not be fixed
1169             soon, though.
1170              
1171             Meanwhile, C<TextTemplater> implements a workaround to let the option work, so C<TextTemplater>
1172             consumers can utilize the C<filename> option.
1173              
1174             =back
1175              
1176             =head1 WHY?
1177              
1178             C<TextTemplate> role from C<Dist::Zilla> distribution v5.037 has the same great C<Text::Template>
1179             engine under the hood, but lacks of control and has I<awful> error reporting.
1180              
1181             =head2 Error Reporting
1182              
1183             Let us consider an example. For sake of example simplicity, it contains only one file, F<dist.ini>.
1184             Two files, F<lib/Assa.pm> and F<lib/Assa.pod>, are generated on-the-fly with C<GenerateFile>
1185             plugin.
1186              
1187             Have a look at F<dist.ini>:
1188              
1189             name = Assa
1190             version = 0.001
1191             abstract = Example
1192             [GenerateFile/lib/Assa.pm]
1193             filename = lib/Assa.pm
1194             content = package Assa; 1;
1195             [GenerateFile/lib/Assa/Manual.pod]
1196             filename = lib/Assa/Manual.pod
1197             content = =head1 NAME
1198             content =
1199             content = {{$dst->name} - {{$dist->abstract}}
1200             content =
1201             content = Version {{$dist->version}}.
1202             content =
1203             content = {{$dist->license->notice}}
1204             [TemplateFiles]
1205             filename = lib/Assa.pm
1206             filename = lib/Assa/Manual.pod
1207             [MetaResources::Template]
1208             homepage = https://example.org/release/{{$dist->name}}
1209             license = {{$dist->license->url}}
1210              
1211             (Do you see a typo? How many? Note this is a small example, real files are much larger.) Now let us
1212             build the distribution:
1213              
1214             $ dzil build
1215             [DZ] beginning to build Assa
1216             [TemplateFiles] Filling in the template returned undef for:
1217             [TemplateFiles] =head1 NAME
1218             [TemplateFiles]
1219             [TemplateFiles] {{$dst->name} - {{$dist->abstract}}
1220             [TemplateFiles]
1221             [TemplateFiles] Version {{$dist->version}}.
1222             [TemplateFiles]
1223             [TemplateFiles] {{$dist->license->notice}}
1224              
1225             [TemplateFiles] Filling in the template returned undef for:
1226             [TemplateFiles] =head1 NAME
1227             [TemplateFiles]
1228             [TemplateFiles] {{$dst->name} - {{$dist->abstract}}
1229             [TemplateFiles]
1230             [TemplateFiles] Version {{$dist->version}}.
1231             [TemplateFiles]
1232             [TemplateFiles] {{$dist->license->notice}}
1233             at /home/vdb/.usr/opt/local-lib/lib/perl5/x86_64-linux-thread-multi/Moose/Meta/Method/Delegation.pm line 110.
1234              
1235             Oops. What's happened? Where? Why? All we have is a highly unclear error message
1236              
1237             Filling in the template returned undef for:
1238              
1239             and file content printed twice. (Yep, if the problem file had 1000 lines, we would have it printed
1240             twice too.) We do not ever have a file name and have to guess it by the content. Good bug hunting,
1241             dude.
1242              
1243             Ok, let us fix the problem (mistyped closing delimiter in the first line of file
1244             F<lib/Assa/Manual.pod>) and build the distribution again:
1245              
1246             $ dzil build
1247             [DZ] beginning to build Assa
1248             Can't call method "name" on an undefined value at template line 3.
1249              
1250             Oops. Error message much is better now, but where the problem is? There are many templates in the
1251             project: F<lib/Assa.pm>, F<lib/Assa/Manual.pod>, and even resources in F<META.yml> — all are
1252             generated from templates. Where is the problem? Good bug hunting for us all.
1253              
1254             Such error reporting is simply unacceptable. I am a human, I often make mistakes, and I want the
1255             tool clearly warns me I<what> and I<where> the problem is, so I can fix it quickly. For example,
1256             in the first case I want to see:
1257              
1258             $ dzil build
1259             [DZ] beginning to build Assa
1260             [Templates] Unmatched opening delimiter at lib/Assa/Manual.pod line 3.
1261             [Templates] lib/Assa/Manual.pod:
1262             [Templates] 1: =head1 NAME
1263             [Templates] 2:
1264             [Templates] 3: {{$dst->name} - {{$dist->abstract}}
1265             [Templates] ^^^ Unmatched opening delimiter at lib/Assa/Manual.pod line 3. ^^^
1266             [Templates] 4:
1267             [Templates] 5: Version {{$dist->version}}.
1268             [Templates] ... skipped 2 lines ...
1269             Aborting...
1270              
1271             In the second case:
1272              
1273             $ dzil build
1274             [DZ] beginning to build Assa
1275             [Templates] Can't call method "name" on an undefined value at lib/Assa/Manual.pod line 3.
1276             [Templates] Bad code fragment begins at lib/Assa/Manual.pod line 3.
1277             [Templates] lib/Assa/Manual.pod:
1278             [Templates] 1: =head1 NAME
1279             [Templates] 2:
1280             [Templates] 3: {{$dst->name}} - {{$dist->abstract}}
1281             [Templates] ^^^ Can't call method "name" on an undefined value at lib/Assa/Manual.pod line 3. ^^^
1282             [Templates] ^^^ Bad code fragment begins at lib/Assa/Manual.pod line 3. ^^^
1283             [Templates] 4:
1284             [Templates] 5: Version {{$dist->version}}.
1285             [Templates] ... skipped 2 lines ...
1286             Aborting...
1287              
1288             C<TextTemplater> makes it real. All I need is using C<TextTemplater>-based plugins: C<Templates>,
1289             C<MetaResources::Template> (starting from v0.002).
1290              
1291             =head2 Engine Control
1292              
1293             C<TextTemplater> allows the end-user to specify C<delimiters>, C<package> and C<prepend> engine
1294             options in F<dist.ini> file, while C<TextTemplate> allows to specify C<prepend> only
1295             programmatically, and does I<not> allow to specify C<delimiters> and C<package>.
1296              
1297             =for test_synopsis my ( $result, $template, $file );
1298              
1299             package Dist::Zilla::Plugin::YourPlugin;
1300             use Moose;
1301             use namespace::autoclean;
1302             with 'Dist::Zilla::Role::Plugin';
1303             with 'Dist::Zilla::Role::TextTemplater';
1304              
1305             sub method {
1306             my $self = shift( @_ );
1307             ...;
1308             $result = $self->fill_in_string( $template );
1309             ...;
1310             };
1311              
1312             sub another_method {
1313             my $self = shift( @_ );
1314             ...;
1315             $self->fill_in_file( $file );
1316             ...;
1317             };
1318              
1319             __PACKAGE__->meta->make_immutable;
1320             1;
1321              
1322             =head1 SEE ALSO
1323              
1324             =over 4
1325              
1326             =item L<Dist::Zilla>
1327              
1328             =item L<Dist::Zilla::Role>
1329              
1330             =item L<Dist::Zilla::Plugin>
1331              
1332             =item L<Dist::Zilla::Role::TextTemplate>
1333              
1334             =item L<Text::Template>
1335              
1336             =back
1337              
1338             =head1 AUTHOR
1339              
1340             Van de Bugger <van.de.bugger@gmail.com>
1341              
1342             =head1 COPYRIGHT AND LICENSE
1343              
1344             Copyright © 2015 Van de Bugger
1345              
1346             This file is part of perl-Dist-Zilla-Role-TextTemplater.
1347              
1348             perl-Dist-Zilla-Role-TextTemplater is free software: you can redistribute it and/or modify it
1349             under the terms of the GNU General Public License as published by the Free Software Foundation,
1350             either version 3 of the License, or (at your option) any later version.
1351              
1352             perl-Dist-Zilla-Role-TextTemplater is distributed in the hope that it will be useful, but
1353             WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
1354             PARTICULAR PURPOSE. See the GNU General Public License for more details.
1355              
1356             You should have received a copy of the GNU General Public License along with
1357             perl-Dist-Zilla-Role-TextTemplater. If not, see <http://www.gnu.org/licenses/>.
1358              
1359             =cut