File Coverage

blib/lib/Dancer2/Template/TemplateToolkit.pm
Criterion Covered Total %
statement 49 49 100.0
branch 9 16 56.2
condition 4 11 36.3
subroutine 12 12 100.0
pod 1 4 25.0
total 75 92 81.5


line stmt bran cond sub pod time code
1             # ABSTRACT: Template toolkit engine for Dancer2
2              
3             $Dancer2::Template::TemplateToolkit::VERSION = '0.400000';
4             use Moo;
5 8     8   23243 use Carp qw<croak>;
  8         20  
  8         53  
6 8     8   2657 use Dancer2::Core::Types;
  8         26  
  8         416  
7 8     8   378 use Dancer2::FileUtils qw<path>;
  8         16  
  8         95  
8 8     8   66005 use Scalar::Util ();
  8         18  
  8         382  
9 8     8   46 use Template;
  8         16  
  8         159  
10 8     8   1416  
  8         47070  
  8         3885  
11             with 'Dancer2::Core::Role::Template';
12              
13             has '+engine' => ( isa => InstanceOf ['Template'], );
14              
15             my $self = shift;
16             my $charset = $self->charset;
17 6     6   70 my %tt_config = (
18 6         21 ANYCASE => 1,
19             ABSOLUTE => 1,
20             length($charset) ? ( ENCODING => $charset ) : (),
21             %{ $self->config },
22             );
23 6 50       37  
  6         52  
24             my $start_tag = $self->config->{'start_tag'};
25             my $stop_tag = $self->config->{'stop_tag'} || $self->config->{end_tag};
26 6         24 $tt_config{'START_TAG'} = $start_tag
27 6   33     63 if defined $start_tag && $start_tag ne '[%';
28 6 50 33     27 $tt_config{'END_TAG'} = $stop_tag
29             if defined $stop_tag && $stop_tag ne '%]';
30 6 50 33     22  
31             Scalar::Util::weaken( my $ttt = $self );
32             my $include_path = $self->config->{include_path};
33 6         177 $tt_config{'INCLUDE_PATH'} ||= [
34 6         26 ( defined $include_path ? $include_path : () ),
35             sub { [ $ttt->views ] },
36             ];
37 22     22   6802  
38 6 50 50     82 my $tt = Template->new(%tt_config);
39             $Template::Stash::PRIVATE = undef if $self->config->{show_private_variables};
40 6         128 return $tt;
41 6 50       105139 }
42 6         177  
43             my ( $self, $template, $tokens ) = @_;
44              
45             my $content = '';
46 14     14 1 47 my $charset = $self->charset;
47             my @options = length($charset) ? ( binmode => ":encoding($charset)" ) : ();
48 14         30 $self->engine->process( $template, $tokens, \$content, @options )
49 14         51 or croak 'Failed to render template: ' . $self->engine->error;
50 14 50       82  
51 14 50       231 return $content;
52             }
53              
54 14         99125 # Override *_pathname methods from Dancer2::Core::Role::Template
55             # Let TT2 do the concatenation of paths to template names.
56             #
57             # TT2 will look in a its INCLUDE_PATH for templates.
58             # Typically $self->views is an absolute path, and we set ABSOLUTE=> 1 above.
59             # In that case TT2 does NOT iterate through what is set for INCLUDE_PATH
60             # However, if its not absolute, we want to allow TT2 iterate through the
61             # its INCLUDE_PATH, which we set to be $self->views.
62              
63             my ( $self, $view ) = @_;
64             return $self->_template_name($view);
65             }
66              
67 18     18 0 1625 my ( $self, $layout ) = @_;
68 18         83 return path(
69             $self->layout_dir,
70             $self->_template_name($layout),
71             );
72 4     4 0 13 }
73 4         64  
74             my ( $self, $pathname ) = @_;
75             my $exists = eval {
76             # dies if pathname can not be found via TT2's INCLUDE_PATH search
77             $self->engine->service->context->template( $pathname );
78             1;
79             };
80 7     7 0 237 $self->log_cb->( debug => $@ ) if ! $exists;
81 7         12 return $exists;
82             }
83 7         107  
84 3         48167 1;
85              
86 7 100       754  
87 7         52 =pod
88              
89             =encoding UTF-8
90              
91             =head1 NAME
92              
93             Dancer2::Template::TemplateToolkit - Template toolkit engine for Dancer2
94              
95             =head1 VERSION
96              
97             version 0.400000
98              
99             =head1 SYNOPSIS
100              
101             To use this engine, you may configure L<Dancer2> via C<config.yaml>:
102              
103             template: "template_toolkit"
104              
105             Or you may also change the rendering engine on a per-route basis by
106             setting it manually with C<set>:
107              
108             # code code code
109             set template => 'template_toolkit';
110              
111             Most configuration variables available when creating a new instance of a
112             L<Template>::Toolkit object can be declared inside the template toolkit
113             section on the engines configuration in your config.yml file. For example:
114              
115             engines:
116             template:
117             template_toolkit:
118             start_tag: '<%'
119             end_tag: '%>'
120              
121             (Note: C<start_tag> and C<end_tag> are regexes. If you want to use PHP-style
122             tags, you will need to list them as C<< <\? >> and C<< \?> >>.)
123             See L<Template::Manual::Config> for the configuration variables.
124              
125             In addition to the standard configuration variables, the option C<show_private_variables>
126             is also available. Template::Toolkit, by default, does not render private variables
127             (the ones starting with an underscore). If in your project it gets easier to disable
128             this feature than changing variable names, add this option to your configuration.
129              
130             show_private_variables: true
131              
132             B<Warning:> Given the way Template::Toolkit implements this option, different Dancer2
133             applications running within the same interpreter will share this option!
134              
135             =head1 DESCRIPTION
136              
137             This template engine allows you to use L<Template>::Toolkit in L<Dancer2>.
138              
139             =head1 METHODS
140              
141             =head2 render($template, \%tokens)
142              
143             Renders the template. The first arg is a filename for the template file
144             or a reference to a string that contains the template. The second arg
145             is a hashref for the tokens that you wish to pass to
146             L<Template::Toolkit> for rendering.
147              
148             =head1 ADVANCED CUSTOMIZATION
149              
150             L<Template>::Toolkit allows you to replace certain parts, like the internal
151             STASH (L<Template::Stash>). In order to do that, one usually passes an object of another
152             implementation such as L<Template::Stash::AutoEscaping> into the constructor.
153              
154             Unfortunately that is not possible when you configure L<Template>::Toolkit from
155             your Dancer2 configuration file. You cannot instantiate a Perl object in a yaml file.
156             Instead, you need to subclass this module, and use the subclass in your configuration file.
157              
158             A subclass to use the aforementioned L<Template::Stash::AutoEscaping> might look like this:
159              
160             package Dancer2::Template::TemplateToolkit::AutoEscaping;
161             # or MyApp::
162            
163             use Moo;
164             use Template::Stash::AutoEscaping;
165            
166             extends 'Dancer2::Template::TemplateToolkit';
167            
168             around '_build_engine' => sub {
169             my $orig = shift;
170             my $self = shift;
171            
172             my $tt = $self->$orig(@_);
173            
174             # replace the stash object
175             $tt->service->context->{STASH} = Template::Stash::AutoEscaping->new(
176             $self->config->{STASH}
177             );
178            
179             return $tt;
180             };
181            
182             1;
183              
184             You can then use this new subclass in your config file instead of C<template_toolkit>.
185              
186             # in config.yml
187             engines:
188             template:
189             TemplateToolkit::AutoEscaping:
190             start_tag: '<%'
191             end_tag: '%>'
192             # optional arguments here
193             STASH:
194              
195             The same approach should work for SERVICE (L<Template::Service>), CONTEXT (L<Template::Context>),
196             PARSER (L<Template::Parser>) and GRAMMAR (L<Template::Grammar>). If you intend to replace
197             several of these components in your app, it is suggested to create an app-specific subclass
198             that handles all of them at the same time.
199              
200             =head2 Template Caching
201              
202             L<Template>::Tookit templates can be cached by adding the C<COMPILE_EXT> property to your
203             template configuration settings:
204              
205             # in config.yml
206             engines:
207             template:
208             template_toolkit:
209             start_tag: '<%'
210             end_tag: '%>'
211             COMPILE_EXT: '.tcc' # cached file extension
212              
213             Template caching will avoid the need to re-parse template files or blocks each time they are
214             used. Cached templates are automatically updated when you update the original template file.
215              
216             By default, cached templates are saved in the same directory as your template. To save
217             cached templates in a different directory, you can set the C<COMPILE_DIR> property in your
218             Dancer2 configuration file.
219              
220             Please see L<Template::Manual::Config/Caching_and_Compiling_Options> for further
221             details and more caching options.
222              
223             =head1 SEE ALSO
224              
225             L<Dancer2>, L<Dancer2::Core::Role::Template>, L<Template::Toolkit>.
226              
227             =head1 AUTHOR
228              
229             Dancer Core Developers
230              
231             =head1 COPYRIGHT AND LICENSE
232              
233             This software is copyright (c) 2022 by Alexis Sukrieh.
234              
235             This is free software; you can redistribute it and/or modify it under
236             the same terms as the Perl 5 programming language system itself.
237              
238             =cut