File Coverage

blib/lib/Dancer2/Core/Role/Template.pm
Criterion Covered Total %
statement 68 72 94.4
branch 19 26 73.0
condition 7 9 77.7
subroutine 17 18 94.4
pod 7 9 77.7
total 118 134 88.0


line stmt bran cond sub pod time code
1             # ABSTRACT: Role for template engines
2              
3             $Dancer2::Core::Role::Template::VERSION = '0.400000';
4             use Dancer2::Core::Types;
5 114     114   72584 use Dancer2::FileUtils 'path';
  114         287  
  114         979  
6 114     114   931697 use Carp 'croak';
  114         307  
  114         6123  
7 114     114   684 use Ref::Util qw< is_ref >;
  114         250  
  114         5319  
8 114     114   1097  
  114         735  
  114         4776  
9             use Moo::Role;
10 114     114   710 with 'Dancer2::Core::Role::Engine';
  114         287  
  114         1037  
11              
12             {
13             before_template_render => 'engine.template.before_render',
14             after_template_render => 'engine.template.after_render',
15 101     101 0 794 before_layout_render => 'engine.template.before_layout_render',
16             after_layout_render => 'engine.template.after_layout_render',
17             }
18             }
19              
20              
21              
22 26     26 0 58 requires 'render';
  26         102  
23              
24 0     0   0 has log_cb => (
25             is => 'ro',
26             isa => CodeRef,
27             default => sub { sub {1} },
28             );
29              
30             has name => (
31             is => 'ro',
32             lazy => 1,
33             builder => 1,
34             );
35              
36             ( my $name = ref shift ) =~ s/^Dancer2::Template:://;
37             $name;
38             }
39              
40             has charset => (
41 2     2   1962 is => 'ro',
42 2         12 isa => Str,
43             default => sub {'UTF-8'},
44             );
45              
46             has default_tmpl_ext => (
47             is => 'ro',
48             isa => Str,
49             default => sub { shift->config->{extension} || 'tt' },
50             );
51              
52             has engine => (
53             is => 'ro',
54             isa => Object,
55             lazy => 1,
56             builder => 1,
57             );
58              
59             has settings => (
60             is => 'ro',
61             isa => HashRef,
62             lazy => 1,
63             default => sub { +{} },
64             writer => 'set_settings',
65             );
66              
67             # The attributes views, layout and layout_dir have triggers in
68             # Dancer2::Core::App that enable their values to be modified by
69             # the `set` keyword. As such, these are defined as read-write attrs.
70              
71             has views => (
72             is => 'rw',
73             isa => Maybe [Str],
74             );
75              
76             has layout => (
77             is => 'rw',
78             isa => Maybe [Str],
79             );
80              
81             has layout_dir => (
82             is => 'rw',
83             isa => Maybe [Str],
84             );
85              
86             my ( $self, $view ) = @_;
87             my $def_tmpl_ext = $self->default_tmpl_ext();
88             $view .= ".$def_tmpl_ext" if $view !~ /\.\Q$def_tmpl_ext\E$/;
89             return $view;
90             }
91              
92 158     158   536 my ( $self, $view ) = @_;
93 158         466  
94 158 100       1309 $view = $self->_template_name($view);
95 158         498 return path( $self->views, $view );
96             }
97              
98             my ( $self, $layout ) = @_;
99 134     134 1 945  
100             return path(
101 134         373 $self->views,
102 134         2100 $self->layout_dir,
103             $self->_template_name($layout),
104             );
105             }
106 2     2 1 5  
107             my ( $self, $pathname ) = @_;
108 2         28 return -f $pathname;
109             }
110              
111             my ( $self, $layout, $tokens, $content ) = @_;
112              
113             $layout = $self->layout_pathname($layout);
114              
115             # FIXME: not sure if I can "just call render"
116 113     113 1 271 $self->render( $layout, { %$tokens, content => $content } );
117 113         2697 }
118              
119             my ( $self, $view, $tokens ) = @_;
120             $view = $self->view_pathname($view) if !is_ref($view);
121 6     6 1 21 $tokens = $self->_prepare_tokens_options( $tokens );
122              
123 6         19 $self->execute_hook( 'engine.template.before_render', $tokens );
124              
125             my $content = $self->render( $view, $tokens );
126 6         50 $self->execute_hook( 'engine.template.after_render', \$content );
127              
128             # make sure to avoid ( undef ) in list context return
129             defined $content and return $content;
130 34     34 1 101 return;
131 34 100       199 }
132 34         169  
133             my ( $self, $content, $tokens, $options ) = @_;
134 34         177  
135             $tokens = $self->_prepare_tokens_options( $tokens );
136 30         280  
137 29         184 # If 'layout' was given in the options hashref, use it if it's a true value,
138             # or don't use a layout if it was false (0, or undef); if layout wasn't
139             # given in the options hashref, go with whatever the current layout setting
140 29 50       289 # is.
141 0         0 my $layout =
142             exists $options->{layout}
143             ? ( $options->{layout} ? $options->{layout} : undef )
144             : ( $self->layout || $self->config->{layout} );
145 29     29 1 97  
146             # that should only be $self->config, but the layout ain't there ???
147 29         84  
148             defined $content or return;
149             defined $layout or return $content;
150              
151             $self->execute_hook(
152             'engine.template.before_layout_render',
153             $tokens, \$content
154             );
155              
156 29 50 66     477 my $full_content = $self->render_layout( $layout, $tokens, $content );
    100          
157              
158             $self->execute_hook( 'engine.template.after_layout_render',
159             \$full_content );
160 29 50       341  
161 29 100       131 # make sure to avoid ( undef ) in list context return
162             defined $full_content and return $full_content;
163 6         28 return;
164             }
165              
166             my ( $self, $tokens ) = @_;
167              
168 6         47 # these are the default tokens provided for template processing
169             $tokens ||= {};
170 6         41 $tokens->{perl_version} = $^V;
171             $tokens->{dancer_version} = Dancer2->VERSION;
172             $tokens->{settings} = $self->settings;
173              
174 6 50       48 # no request when template is called as a global keyword
175 0         0 if ( $self->has_request ) {
176             $tokens->{request} = $self->request;
177             $tokens->{params} = $self->request->params;
178             $tokens->{vars} = $self->request->vars;
179 63     63   150  
180             # a session can not exist if there is no request
181             $tokens->{session} = $self->session->data
182 63   50     166 if $self->has_session;
183 63         176 }
184 63         402  
185 63         1280 return $tokens;
186             }
187              
188 63 100       712 my ( $self, $view, $tokens, $options ) = @_;
189 61         236 my ( $content, $full_content );
190 61         280  
191 61         290 # it's important that $tokens is not undef, so that things added to it via
192             # a before_template in apply_renderer survive to the apply_layout. GH#354
193             $tokens ||= {};
194 61 100       396 $options ||= {};
195              
196             ## FIXME - Look into PR 654 so we fix the problem here as well!
197              
198 63         192 $content =
199             $view
200             ? $self->apply_renderer( $view, $tokens )
201             : delete $options->{content};
202 34     34 1 132  
203 34         73 defined $content
204             and $full_content = $self->apply_layout( $content, $tokens, $options );
205              
206             defined $full_content
207 34   100     169 and return $full_content;
208 34   100     172  
209             croak "Template did not produce any content";
210             }
211              
212             1;
213              
214              
215 34 50       204 =pod
216              
217 29 50       153 =encoding UTF-8
218              
219             =head1 NAME
220 29 50       231  
221             Dancer2::Core::Role::Template - Role for template engines
222              
223 0           =head1 VERSION
224              
225             version 0.400000
226              
227             =head1 DESCRIPTION
228              
229             Any class that consumes this role will be able to be used as a template engine
230             under Dancer2.
231              
232             In order to implement this role, the consumer B<must> implement the method C<render>. This method will receive three arguments:
233              
234             =over 4
235              
236             =item $self
237              
238             =item $template
239              
240             =item $tokens
241              
242             =back
243              
244             Any template receives the following tokens, by default:
245              
246             =over 4
247              
248             =item * C<perl_version>
249              
250             Current version of perl, effectively C<$^V>.
251              
252             =item * C<dancer_version>
253              
254             Current version of Dancer2, effectively C<< Dancer2->VERSION >>.
255              
256             =item * C<settings>
257              
258             A hash of the application configuration.
259              
260             =item * C<request>
261              
262             The current request object.
263              
264             =item * C<params>
265              
266             A hash reference of all the parameters.
267              
268             Currently the equivalent of C<< $request->params >>.
269              
270             =item * C<vars>
271              
272             The list of request variables, which is what you would get if you
273             called the C<vars> keyword.
274              
275             =item * C<session>
276              
277             The current session data, if a session exists.
278              
279             =back
280              
281             =head1 ATTRIBUTES
282              
283             =head2 name
284              
285             The name of the template engine (e.g.: Simple).
286              
287             =head2 charset
288              
289             The charset. The default value is B<UTF-8>.
290              
291             =head2 default_tmpl_ext
292              
293             The default file extension. If not provided, B<tt> is used.
294              
295             =head2 views
296              
297             Path to the directory containing the views.
298              
299             =head2 layout
300              
301             Path to the directory containing the layouts.
302              
303             =head2 layout_dir
304              
305             Relative path to the layout directory.
306              
307             Default: B<layouts>.
308              
309             =head2 engine
310              
311             Contains the engine.
312              
313             =head1 METHODS
314              
315             =head2 view_pathname($view)
316              
317             Returns the full path to the requested view.
318              
319             =head2 layout_pathname($layout)
320              
321             Returns the full path to the requested layout.
322              
323             =head2 pathname_exists($pathname)
324              
325             Returns true if the requested pathname exists. Can be used for either views
326             or layouts:
327              
328             $self->pathname_exists( $self->view_pathname( 'some_view' ) );
329             $self->pathname_exists( $self->layout_pathname( 'some_layout' ) );
330              
331             =head2 render_layout($layout, \%tokens, \$content)
332              
333             Render the layout with the applied tokens
334              
335             =head2 apply_renderer($view, \%tokens)
336              
337             =head2 apply_layout($content, \%tokens, \%options)
338              
339             =head2 process($view, \%tokens, \%options)
340              
341             =head2 template($view, \%tokens, \%options)
342              
343             =head1 AUTHOR
344              
345             Dancer Core Developers
346              
347             =head1 COPYRIGHT AND LICENSE
348              
349             This software is copyright (c) 2022 by Alexis Sukrieh.
350              
351             This is free software; you can redistribute it and/or modify it under
352             the same terms as the Perl 5 programming language system itself.
353              
354             =cut