File Coverage

blib/lib/Text/MicroTemplate/Extended.pm
Criterion Covered Total %
statement 135 140 96.4
branch 36 44 81.8
condition 19 20 95.0
subroutine 24 26 92.3
pod 8 8 100.0
total 222 238 93.2


line stmt bran cond sub pod time code
1             package Text::MicroTemplate::Extended;
2 7     7   21915 use strict;
  7         17  
  7         269  
3 7     7   39 use warnings;
  7         27  
  7         221  
4 7     7   38 use base 'Text::MicroTemplate::File';
  7         11  
  7         5970  
5              
6             our $VERSION = '0.17';
7              
8             sub new {
9 6     6 1 135 my $self = shift->SUPER::new(@_);
10              
11 6   100     438 $self->{template_args} ||= {};
12 6 100 50     64 $self->{extension} ||= '.mt' unless defined $self->{extension};
13 6   100     35 my $m = $self->{macro} ||= {};
14              
15             # install default macros to support template inheritance
16             $m->{extends} = sub {
17 21     21   81 $self->render_context->{extends} = $_[0];
18 6         123 };
19              
20 6         15 my $super = '';
21 6     3   30 $m->{super} = sub { $super };
  3         79  
22              
23             $m->{block} = sub {
24 54     54   100 my ($name, $code) = @_;
25              
26 7     7   39629 no strict 'refs';
  7         19  
  7         3197  
27 54         69 my $block;
28 54 100       151 if (defined $code) {
29 52 100       141 if ($self->render_context->{blocks}{$name}) {
30 21         47 unshift @{ $self->render_context->{super}{$name}}, {
  21         227  
31             context_ref => ${"$self->{package_name}::_MTREF"},
32 6     6   28 code => ref($code) eq 'CODE' ? $code : sub { return $code },
33 21 100       32 };
34             }
35              
36 31         290 $block = $self->render_context->{blocks}{$name} ||= {
37             context_ref => ${"$self->{package_name}::_MTREF"},
38 7     7   25 code => ref($code) eq 'CODE' ? $code : sub { return $code },
39 52 100 100     126 };
40             }
41             else {
42 2 50       5 $block = $self->render_context->{blocks}{$name}
43             or die qq[block "$name" does not define];
44             }
45              
46 54 100       131 if (!$self->render_context->{extends}) {
47 33         41 my $current_ref = ${"$self->{package_name}::_MTREF"};
  33         94  
48 33   100     124 my $rendered = $$current_ref || '';
49              
50 33 100       75 $super = Text::MicroTemplate::encoded_string($self->_render_block($_))
51 33         48 for (@{ $self->render_context->{super}{$name} || [] });
52              
53 33         275 $$current_ref = $rendered . $self->_render_block($block);
54 31         1010 $super = '';
55             }
56 6         51 };
57              
58             $m->{include} = sub {
59 2     2   11 $self->include_file(@_);
60 6         38 };
61              
62 6         16 for my $name (keys %{ $self->{macro} }) {
  6         29  
63 26 50       293 unless ($name =~ /^[a-zA-Z_][a-zA-Z0-9_]*$/) {
64 0         0 die qq{Invalid macro key name: "$name"};
65             }
66              
67 7     7   44 no strict 'refs';
  7         20  
  7         207  
68 7     7   37 no warnings 'redefine';
  7         11  
  7         1399  
69 26         51 my $code = $self->{macro}{$name};
70 26     0   104 *{ $self->package_name . "::$name" }
  0         0  
71 26 50       67 = ref $code eq 'CODE' ? $code : sub {$code};
72             }
73              
74 6         73 $self;
75             }
76              
77             sub template_args {
78 291     291 1 404 my $self = shift;
79 291 50       543 $self->{template_args} = $_[0] if @_;
80 291         3941 $self->{template_args};
81             }
82              
83             sub extension {
84 51     51 1 76 my $self = shift;
85 51 50       116 $self->{extension} = $_[0] if @_;
86 51         304 $self->{extension};
87             }
88              
89             {
90 7     7   39 no warnings 'once';
  7         15  
  7         2057  
91             *render = \&render_file;
92             *include = \&include_file;
93             }
94              
95             sub render_file {
96 49     49 1 256 my $self = shift;
97 49         64 my $template = shift;
98              
99 49   100     130 my $context = $self->render_context || {};
100 49         117 $self->render_context($context);
101              
102 49         124 my $renderer = $self->build_file( $template . $self->extension );
103 47         633 my $result;
104              
105             my $die_msg;
106             {
107 47         63 local $@;
  47         68  
108 47         80 eval {
109 47         1469 $result = $renderer->(@_);
110              
111 42         682 my $tmpl = $self->{template};
112 42   100     66 $_->{template_ref} ||= \$tmpl for values %{ $context->{blocks} };
  42         343  
113             };
114 47         178 $die_msg = $@;
115             }
116 47 100       110 unless ($die_msg) {
117 42 100       135 if (my $parent = delete $context->{extends}) {
118 21         71 $result = $self->render($parent);
119             }
120             }
121              
122 43         126 $self->render_context(undef);
123              
124 43 100 100     123 die $self->_error($die_msg, 0, $context->{caller} || '')
125             if $die_msg;
126              
127 38         384 $result;
128             }
129              
130             sub _render_block {
131 55     55   108 my ($self, $block) = @_;
132              
133 7     7   38 no strict 'refs';
  7         15  
  7         4913  
134              
135 55         84 my $block_ref = $block->{context_ref};
136 55         64 local ${"$self->{package_name}::_MTEREF"} = $block_ref;
  55         154  
137              
138 55         75 $$block_ref = '';
139 55         61 my ($result, $die_msg);
140 55         69 eval {
141 55   100     1300 $result = $block->{code}->() || $$block_ref || '';
142             };
143 55 100       468 if ($@) {
144 2         6 my $context = $self->render_context;
145 2         4 local $self->{template} = ${ $block->{template_ref} };
  2         7  
146 2         17 die $self->_error($@, 0, $context->{caller});
147             }
148              
149 53         673 $result;
150             }
151              
152             sub include_file {
153 2     2 1 4 my $self = shift;
154 2         5 my $template = shift;
155              
156 2         9 my $renderer = $self->build_file( $template . $self->extension );
157 1         643 $renderer->(@_);
158             }
159              
160             sub render_context {
161 419     419 1 792 my $self = shift;
162 419 100       1056 $self->{render_context} = $_[0] if @_;
163 419         2850 $self->{render_context};
164             }
165              
166             sub build {
167 41     41 1 39240 my $self = shift;
168              
169 41         123 my $context = $self->render_context;
170 41         175 $context->{code} = $self->code;
171             $context->{caller} = sub {
172 41     41   66 my $i = 0;
173 41         527 while (my @c = caller(++$i)) {
174 41 50       329 return "$c[1] at line $c[2]" if $c[0] ne __PACKAGE__;
175             }
176 0         0 '';
177 41         5651 }->();
178              
179 41         400 $context->{args} = '';
180 41 50       59 for my $key (keys %{ $self->template_args || {} }) {
  41         139  
181 109 50       409 unless ($key =~ /^[a-zA-Z_][a-zA-Z0-9_]*$/) {
182 0         0 die qq{Invalid template args key name: "$key"};
183             }
184              
185 109 100       213 if (ref($self->template_args->{$key}) eq 'CODE') {
186 25         271 $context->{args} .= qq{my \$$key = \$self->template_args->{$key}->();\n};
187             }
188             else {
189 84         432 $context->{args} .= qq{my \$$key = \$self->template_args->{$key};\n};
190             }
191             }
192              
193 41   100     222 $context->{blocks} ||= {};
194              
195 41         52 my $die_msg;
196             {
197 41         935 local $@;
  41         59  
198 41 100       115 if (my $builder = $self->eval_builder()) {
199 39         167 return $builder;
200             }
201 2         35 $die_msg = $self->_error($@, 0, $context->{caller});
202             }
203 2         94 die $die_msg;
204             }
205              
206             sub eval_builder {
207 41     41 1 65 my ($self) = @_;
208              
209             local $SIG{__WARN__} = sub {
210 0     0   0 print STDERR $self->_error(shift, 0, $self->render_context->{caller});
211 41         346 };
212              
213 41         12983 eval <<"...";
214             package $self->{package_name};
215             sub {
216             $self->{render_context}{args}
217             # line 1
218             Text::MicroTemplate::encoded_string(($self->{render_context}{code})->(\@_));
219             }
220             ...
221             }
222              
223             1;
224              
225             __END__
226              
227             =head1 NAME
228              
229             Text::MicroTemplate::Extended - Extended MicroTemplate
230              
231             =head1 SYNOPSIS
232              
233             use Text::MicroTemplate::Extended;
234            
235             my $mt = Text::MicroTemplate::Extended->new(
236             include_path => ['/path/to/document_root'],
237             template_args => { c => $c, stash => $c->stash, },
238             );
239            
240             $mt->render('content'); # render file: /path/to/document_root/content.mt
241              
242             =head1 DESCRIPTION
243              
244             L<Text::MicroTemplate::Extended> is an extended template engine based on L<Text::MicroTemplate::File>.
245              
246             =head1 EXTENDED FEATURES
247              
248             =head2 Template inheritance
249              
250             Most notable point of this extended module is Template inheritance.
251             This concept is used in Python's Django framework.
252              
253             Template inheritance allows you to build a base "skeleton" template that contains all the common elements of your site and defines blocks that child templates can override.
254              
255             It's easiest to understand template inheritance by starting with an example:
256              
257             <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
258             "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
259             <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
260             <head>
261             <link rel="stylesheet" href="style.css" />
262             <title><? block title => sub { ?>My amazing site<? } ?></title>
263             </head>
264            
265             <body>
266             <div id="sidebar">
267             <? block sidebar => sub { ?>
268             <ul>
269             <li><a href="/">Home</a></li>
270             <li><a href="/blog/">Blog</a></li>
271             </ul>
272             <? } ?>
273             </div>
274            
275             <div id="content">
276             <? block content => sub {} ?>
277             </div>
278             </body>
279             </html>
280              
281             This template, which we'll call base.mt, defines a simple HTML skeleton document that you might use for a simple two-column page. It's the job of "child" templates to fill the empty blocks with content.
282              
283             In this example, the C<<? block ?>> tag defines three blocks that child templates can fill in. All the block tag does is to tell the template engine that a child template may override those portions of the template.
284              
285             A child template might look like this:
286              
287             ? extends 'base'
288            
289             <? block title => sub { ?>My amazing blog<? } ?>
290            
291             ? block content => sub {
292             ? for my $entry (@$blog_entries) {
293             <h2><?= $entry->title ?></h2>
294             <p><?= $entry->body ?></p>
295             ? } # endfor
296             ? } # endblock
297              
298             The C<<? extends ?>> tag is the key here. It tells the template engine that this template "extends" another template. When the template system evaluates this template, first it locates the parent -- in this case, "base.mt".
299              
300             At that point, the template engine will notice the three C<<? block ?>> tags in base.mt and replace those blocks with the contents of the child template. Depending on the value of blog_entries, the output might look like:
301              
302             <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
303             "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
304             <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
305             <head>
306             <link rel="stylesheet" href="style.css" />
307             <title>My amazing blog</title>
308             </head>
309            
310             <body>
311             <div id="sidebar">
312             <ul>
313             <li><a href="/">Home</a></li>
314             <li><a href="/blog/">Blog</a></li>
315             </ul>
316             </div>
317            
318             <div id="content">
319             <h2>Entry one</h2>
320             <p>This is my first entry.</p>
321            
322             <h2>Entry two</h2>
323             <p>This is my second entry.</p>
324             </div>
325             </body>
326             </html>
327              
328             Note that since the child template didn't define the sidebar block, the value from the parent template is used instead. Content within a C<<? block ?>> tag in a parent template is always used as a fallback.
329              
330             You can use as many levels of inheritance as needed. One common way of using inheritance is the following three-level approach:
331              
332             =over 4
333              
334             =item 1.
335              
336             Create a base.mt template that holds the main look-and-feel of your site.
337              
338             =item 2.
339              
340             Create a base_SECTIONNAME.mt template for each "section" of your site. For example, base_news.mt, base_sports.mt. These templates all extend base.mt and include section-specific styles/design.
341              
342             =item 3.
343              
344             Create individual templates for each type of page, such as a news article or blog entry. These templates extend the appropriate section template.
345              
346             =back
347              
348             This approach maximizes code reuse and makes it easy to add items to shared content areas, such as section-wide navigation.
349              
350             Here are some tips for working with inheritance:
351              
352             =over 4
353              
354             =item *
355              
356             If you use C<<? extends ?>> in a template, it must be the first template tag in that template. Template inheritance won't work, otherwise.
357              
358             =item *
359              
360             More C<<? block ?>> tags in your base templates are better. Remember, child templates don't have to define all parent blocks, so you can fill in reasonable defaults in a number of blocks, then only define the ones you need later. It's better to have more hooks than fewer hooks.
361              
362             =item *
363              
364             If you find yourself duplicating content in a number of templates, it probably means you should move that content to a C<<? block ?>> in a parent template.
365              
366             =item *
367              
368             If you need to get the content of the block from the parent template, the C<< <?= super() ?> >> variable will do the trick. This is useful if you want to add to the contents of a parent block instead of completely overriding it. Data inserted using C<< <?= super() ?> >> will not be automatically escaped, since it was already escaped, if necessary, in the parent template.
369              
370             =item *
371              
372             For extra readability, you can optionally give a name to your C<<? } # endblock ?>> tag. For example:
373              
374             <? block content => sub { ?>
375             ...
376             <? } # endblock content ?>
377              
378             In larger templates, this technique helps you see which C<<? block ?>> tags are being closed.
379              
380             =back
381              
382             Finally, note that you can't define multiple C<<? block ?>> tags with the same name in the same template. This limitation exists because a block tag works in "both" directions. That is, a block tag doesn't just provide a hole to fill -- it also defines the content that fills the hole in the parent. If there were two similarly-named C<<? block ?>> tags in a template, that template's parent wouldn't know which one of the blocks' content to use.
383              
384             =head2 Named template arguments
385              
386             L<Text::MicroTemplate::Extended> has new template_args option.
387             Using this option, You can pass named template arguments to your tamplate like:
388              
389             my $mf = Text::MicroTemplate::Extended->new(
390             template_args => { foo => 'bar', },
391             ...
392             );
393              
394             Then in template:
395              
396             <?= $foo ?>
397              
398             This template display 'bar'.
399              
400             C<template_args> also supports CodeRef as its value life below:
401              
402             my $mf = Text::MicroTemplate::Extended->new(
403             template_args => { foo => sub { $self->get_foo() } },
404             ...
405             );
406              
407             In template, you can C<<?= $foo ?>> to show C<$foo> value. this value is set by calling C<< $self->get_foo >> in template process time.
408              
409             This feature is useful to set variable does not exists when template object is created.
410              
411             =head2 Macro
412              
413             Similar to named arguments, but this feature install your subroutine to template instead of variables.
414              
415             my $mh = Text::MicroTemplate::Extended->new(
416             macro => {
417             hello => sub { return 'Hello World!' },
418             },
419             ...
420             );
421              
422             And in template:
423              
424             <?= hello() ?> # => 'Hello World'
425              
426             =head2 extension option
427              
428             There is another new option 'extension'. You can specify template file extension.
429              
430             If this option is set, you don't have to set extension with render method:
431              
432             $mf->render_file('template'); # render template.mt
433              
434             Default value is '.mt'.
435              
436             =head2 replace render method
437              
438             For supporting template inheritance, it is no longer possible to implement original render method. Because extends function requires filename.
439              
440             So in this module, render method acts same as render_file.
441              
442             $mf->render('template');
443             $mf->render_file('template');
444              
445             =head1 METHODS
446              
447             =head2 new (%options)
448              
449             my $mf = Text::MicroTemplate::Extended->new(
450             extension => '.mt',
451             template_args => { c => $c, stash => $c->stash },
452             );
453              
454             Create new L<Text::MicroTemplate::Extended> object.
455              
456             Available options are:
457              
458             =over 4
459              
460             =item extension
461              
462             Template file extension. (Default: '.mt')
463              
464             =item template_args
465              
466             Hash Reference of template args.
467              
468             =item macro
469              
470             Hash Reference of macros
471              
472             =back
473              
474             See L<Text::MicroTemplate::File> for more options.
475              
476             =head2 render ($template_name, @args)
477              
478             =head2 render_file ($template_name, @args)
479              
480             Render $template_name and return result.
481              
482             =head2 include ($template_name, @args)
483              
484             =head2 include_file ($template_name, @args)
485              
486             Render $template_name and return result.
487              
488             Difference between include and render is that render treats extends and block macros and supports template inheritance but include not.
489             But render method does not work in template.
490              
491             <?= $self->render('template') ?> # does not work!
492              
493             Instead of above, use:
494              
495             <?= $self->include('template') ?>
496            
497             # or just
498            
499             <?= include('template') ?>
500              
501             =head1 INTERNAL METHODS
502              
503             =head2 build
504              
505             =head2 eval_builder
506              
507             =head2 template_args
508              
509             =head2 extension
510              
511             =head2 render_context
512              
513             =head1 AUTHOR
514              
515             Daisuke Murase <typester@cpan.org>
516              
517             =head1 COPYRIGHT AND LICENSE
518              
519             Copyright (c) 2009 by KAYAC Inc.
520              
521             This program is free software; you can redistribute
522             it and/or modify it under the same terms as Perl itself.
523              
524             The full text of the license can be found in the
525             LICENSE file included with this module.
526              
527             =cut
528              
529             Process flymake-proc finished