File Coverage

blib/lib/Mustache/Simple.pm
Criterion Covered Total %
statement 227 238 95.3
branch 76 96 79.1
condition 8 10 80.0
subroutine 28 29 96.5
pod 3 14 21.4
total 342 387 88.3


line stmt bran cond sub pod time code
1             package Mustache::Simple;
2              
3 3     3   150135 use strict;
  3         7  
  3         76  
4 3     3   14 use warnings;
  3         6  
  3         67  
5 3     3   34 use 5.10.1;
  3         11  
6 3     3   1030 use utf8;
  3         35  
  3         13  
7 3     3   563 use experimental qw(switch);
  3         4696  
  3         16  
8 3     3   412 use version;
  3         8  
  3         15  
9              
10             # Don't forget to change the version in the pod
11             our $VERSION = version->declare('v1.3.6');
12              
13 3     3   263 use File::Spec;
  3         9  
  3         82  
14 3     3   835 use Mustache::Simple::ContextStack v1.3.6;
  3         39  
  3         84  
15 3     3   20 use Scalar::Util qw( reftype );
  3         7  
  3         110  
16              
17 3     3   14 use Carp;
  3         5  
  3         955  
18              
19             #use Data::Dumper;
20             #$Data::Dumper::Useqq = 1;
21             #$Data::Dumper::Deparse = 1;
22              
23             =encoding utf8
24              
25             =head1 NAME
26              
27             Mustache::Simple - A simple Mustache Renderer
28              
29             See L.
30              
31             =head1 VERSION
32              
33             This document describes Mustache::Simple version 1.3.6
34              
35             =head1 SYNOPSIS
36              
37             A typical Mustache template:
38              
39             my $template = <
40             Hello {{name}}
41             You have just won ${{value}}!
42             {{#in_ca}}
43             Well, ${{taxed_value}}, after taxes.
44             {{/in_ca}}
45             EOT
46              
47             Given the following hashref:
48              
49             my $context = {
50             name => "Chris",
51             value => 10000,
52             taxed_value => 10000 - (10000 * 0.4),
53             in_ca => 1
54             };
55              
56             Will produce the following:
57              
58             Hello Chris
59             You have just won $10000!
60             Well, $6000, after taxes.
61              
62             using the following code:
63              
64             my $tache = new Mustache::Simple(
65             throw => 1
66             );
67             my $output = $tache->render($template, $context);
68              
69             =cut
70              
71             =head1 DESCRIPTION
72              
73             Mustache can be used for HTML, config files, source code - anything. It works
74             by expanding tags in a template using values provided in a hash or object.
75              
76             There are no if statements, else clauses, or
77             for loops. Instead there are only tags. Some tags are replaced with a value,
78             some nothing, and others a series of values.
79              
80             This is a simple perl implementation of the Mustache rendering. It has
81             a single class method, new() to obtain an object and a single instance
82             method render() to convert the template and the hashref into the final
83             output.
84              
85             As of version 1.2.0, it has support for nested contexts, for the dot notation
86             and for the implicit iterator.
87              
88             As of version 1.3.0, it will accept a blessed object. For any C<{{item}}>
89             where the object has a method called item (as returned by C<< $object->can >>),
90             the value will be the return from the method call (with no parameters).
91             If C<< $object->can(item) >> returns C, the object will be treated
92             as a hash and the value looked up directly. See L below.
93              
94             As of version 1.3.6, if a method call on a blessed object returns an array,
95             a C<{{#item}}> section will iterate over the array. This also works
96             recursively, so a method can return an array of objects.
97              
98             =head2 Rationale
99              
100             I wanted a simple rendering tool for Mustache that did not require any
101             subclassing.
102              
103             =cut
104              
105              
106             #############################################################
107             ##
108             ## Helper Functions
109             ##
110             ##
111              
112             sub dottags($;$)
113             {
114 27     27 0 47 my $tag = shift;
115 27   100     66 my $type = shift // '';
116 27         111 my @dots = $tag =~ /(.*?)\.(.*)/;
117 27         144 my @tags = (
118             { pre => '', type => '#', txt => $dots[0] },
119             { pre => '', type => $type, txt => $dots[1] },
120             { pre => '', type => '/', txt => $dots[0] },
121             );
122 27         73 return @tags;
123             }
124              
125             # Generate a regular expression for iteration
126             # Passed the open and close tags
127             # Returns the regular expression
128             sub tag_match(@)
129             {
130 135     135 0 218 my ($open, $close) = @_;
131             # Much of this regular expression stolen from Template::Mustache
132 135         2055 qr/
133             (?
 .*?)                # Text up to opening tag 
134             (? ^ \s*)? # Indent white space
135             (?: \Q$open\E \s*) # Start of tag
136             (?:
137             (? =) \s* (?.+?) \s* = | # Change delimiters
138             (? {) \s* (?.+?) \s* } | # Unescaped
139             (? &) \s* (?.+?) | # Unescaped
140             (? [#^>\/!]?) \s* (?.+?) # Normal tags
141             )
142             (?: \s* \Q$close\E) # End of tag
143             /xsm;
144             }
145              
146             # Escape HTML entities
147             # Passed a string
148             # Returns an escaped string
149             sub escape($)
150             {
151 114     114 0 155 local $_ = shift;
152 114         181 s/&/&/g;
153 114         145 s/"/"/g;
154 114         128 s/
155 114         128 s/>/>/g;
156 114         342 return $_;
157             }
158              
159             # Reassemble the source code for an array of tags
160             # Passed an array of tags
161             # Returns the original source (roughly)
162             sub reassemble(@)
163             {
164 5     5 0 8 my @tags = @_;
165 5         9 my $last = pop @tags;
166 5         6 my $ans = '';
167 5         7 local $_;
168 3     3   17 no warnings 'uninitialized';
  3         6  
  3         725  
169 5         13 $ans .= "$_->{pre}$_->{tab}\{\{$_->{type}$_->{txt}\}\}" foreach (@tags);
170 5         21 return $ans . $last->{pre};
171             }
172              
173             #############################################################
174             ##
175             ## Class Functions
176             ##
177             ##
178              
179             =head1 METHODS
180              
181             =head2 Creating a new Mustache::Simple object
182              
183             =over
184              
185             =item new
186              
187             my $tache = new Mustache::Simple(%options)
188              
189             =back
190              
191             =head3 Parameters:
192              
193             =over
194              
195             =item path
196              
197             The path from which to load templates and partials. This may be
198             a string or a reference to an array of strings. If it is a reference,
199             each string will be searched in order.
200              
201             Default: '.'
202              
203             =item extension
204              
205             The extension to add to filenames when reading them off disk. The
206             '.' should not be included as this will be added automatically.
207              
208             Default: 'mustache'
209              
210             =item throw
211              
212             If set to a true value, Mustache::Simple will croak when there
213             is no key in the context hash for a given tag.
214              
215             Default: undef
216              
217             =item partial
218              
219             This may be set to a subroutine to be called to generate the
220             filename or the template for a partial. If it is not set, partials
221             will be loaded using the same parameters as render().
222              
223             Default: undef
224              
225             =back
226              
227             =cut
228              
229             sub new
230             {
231 98     98 1 60651 my $class = shift;
232 98 50       369 my %options = @_ == 1 ? %{$_[0]} : @_; # Allow a hash to be passed, in case
  0         0  
233 98         355 my %defaults = (
234             path => '.',
235             extension => 'mustache',
236             delimiters => [qw({{ }})],
237             stack => new Mustache::Simple::ContextStack,
238             );
239 98         450 %options = (%defaults, %options);
240 98         188 my $self = \%options;
241 98         289 bless $self, $class;
242             }
243              
244             #############################################################
245             ##
246             ## Private Instance Functions
247             ##
248             ##
249              
250             # Breaks the template into separate tags, preserving the text
251             # Returns an array ref of the tags and the trailing text
252             sub match_template
253             {
254 122     122 0 152 my $self = shift;
255 122         137 my $template = shift;
256 122         141 my $match = tag_match(@{$self->{delimiters}}); # start with standard delimiters
  122         265  
257 122         232 my @tags;
258             my $afters;
259 122         1001 while ($template =~ /$match/g)
260             {
261 3     3   719 my %tag = %+; # pick up named parts from the regex
  3         956  
  3         5044  
  263         2625  
262 263 100       842 if ($tag{type} eq '=') # change delimiters
263             {
264 13         78 my @delimiters = split /\s/, $tag{txt};
265 13         31 $self->{delimiters} = \@delimiters;
266 13         24 $match = tag_match(@delimiters);
267             }
268 263         449 $afters = $'; # save off the rest in case it's done
269 263         1496 push @tags, \%tag; # put the tag into the array
270             }
271 122 100       285 return \@tags, $template if (@tags == 0); # no tags, it's all afters
272 107         261 for (1 .. $#tags)
273             { # lose a leading LF after sections
274 156 100       492 $tags[$_]->{pre} =~ s/^\r?\n// if $tags[$_ - 1]->{type} =~ m{^[#/^]$};
275             }
276 107 100       206 if (@tags > 1)
277             {
278 57 100 100     152 $tags[1]->{pre} =~ s/^\r?\n// if $tags[0]->{type} eq '=' and $tags[0]->{pre} =~ /^\s*$/;
279             }
280 107         182 foreach(0 .. $#tags)
281             {
282 263 100       469 $tags[$_]->{pre} =~ s/^\r?\n// if $tags[$_]->{type} =~ m{^[!]$};
283 263 100       501 $tags[$_]->{pre} =~ s/\r?\n$// if $tags[$_]->{type} =~ m{^[=]$};
284             }
285             # and from the trailing text
286 107 100       297 $afters =~ s/^\r?\n// if $tags[$#tags]->{type} =~ m{^[/!]$};
287 107         407 return \@tags, $afters;
288             }
289              
290             # Performs partial includes
291             # Passed the current context, it calls the user code if any
292             # Returns the partial rendered in the current context
293             sub include_partial
294             {
295 11     11 0 17 my $self = shift;
296 11         16 my $tag = shift;
297 11         13 my $result;
298 11 50       57 $tag = $self->partial->($tag) if (ref $self->partial eq 'CODE');
299 11         65 $self->render($tag);
300             }
301              
302             # This is the main worker function. It builds up the result from the tags.
303             # Passed the current context and the array of tags
304             # Returns the final text
305             # Note, this is called recursively, directly for sections and
306             # indirectly via render() for partials
307             sub resolve
308             {
309 222     222 0 312 my $self = shift;
310 222   100     462 my $context = shift // {};
311 222         462 $self->push($context);
312 222         370 my @tags = @_;
313 222         295 my $result = '';
314 222         436 for (my $i = 0; $i < @tags; $i++)
315             {
316 327         436 my $tag = $tags[$i]; # the current tag
317 327         480 $result .= $tag->{pre}; # add in the intervening text
318 327         412 given ($tag->{type})
319             {
320 327         524 when('!') { # it's a comment
321             # $result .= $tag->{tab} if $tag->{tab};
322             }
323 320         451 when('/') { break; } # it's a section end - skip
  73         148  
324 247         306 when('=') { break; } # delimiter change
  13         29  
325 234         603 when(/^([{&])?$/) { # it's a variable
326 137         169 my $txt;
327 137 100       343 if ($tag->{txt} eq '.')
    100          
328             {
329 10         22 $txt = $self->{stack}->top;
330             }
331             elsif ($tag->{txt} =~ /\./)
332             {
333 21         55 my @dots = dottags $tag->{txt}, $tag->{type};
334 21         85 $txt = $self->resolve(undef, @dots);
335             }
336             else {
337 106         192 $txt = $self->find($tag->{txt}); # get the entry from the context
338 106 100       202 if (defined $txt)
339             {
340 103 100       179 if (ref $txt eq 'CODE')
341             {
342 8         13 my $saved = $self->{delimiters};
343 8         15 $self->{delimiters} = [qw({{ }})];
344 8         17 $txt = $self->render($txt->());
345 8         17 $self->{delimiters} = $saved;
346             }
347             }
348             else {
349 3 50       23 croak qq(No context for "$tag->{txt}") if $self->throw;
350 3         7 $txt = '';
351             }
352             }
353 137 100       231 $txt = "$tag->{tab}$txt" if $tag->{tab}; # replace the indent
354 137 100       287 $result .= $tag->{type} ? $txt : escape $txt;
355             }
356 97         164 when('#') { # it's a section start
357 66         91 my $j;
358 66         79 my $nested = 0;
359 66         139 for ($j = $i + 1; $j < @tags; $j++) # find the end
360             {
361 276 100       516 if ($tag->{txt} eq $tags[$j]->{txt})
362             {
363 70 100       129 $nested++, next if $tags[$j]->{type} eq '#'; # nested sections with the
364 68 50       109 if ($tags[$j]->{type} eq '/') # same name
365             {
366 68 100       108 next if $nested--;
367 66         90 last;
368             }
369             }
370             }
371 66 50       120 croak 'No end tag found for {{#'.$tag->{txt}.'}}' if $j == @tags;
372 66         169 my @subtags = @tags[$i + 1 .. $j]; # get the tags for the section
373 66         84 my $txt;
374 66 100       139 if ($tag->{txt} =~ /\./)
375             {
376 3         10 my @dots = dottags($tag->{txt});
377 3         11 $txt = $self->resolve(undef, @dots);
378             }
379             else {
380             # wantarray!!!
381 63         117 my @ret = $self->find($tag->{txt}); # get the entry from the context
382 63 50       150 if (scalar @ret == 0) {
    50          
383 0         0 $txt = undef;
384             } elsif (scalar @ret == 1) {
385 63         117 $txt = $ret[0];
386             } else {
387 0         0 $txt = \@ret;
388             }
389             }
390 66         122 given (reftype $txt)
391             {
392 66         119 when ('ARRAY') { # an array of hashes (hopefully)
393 6         22 $result .= $self->resolve($_, @subtags) foreach @$txt;
394             }
395 60         82 when ('CODE') { # call user code which may call render()
396 5         11 $result .= $self->render($txt->(reassemble @subtags));
397             }
398 55         75 when ('HASH') { # use the hash as context
399 38 100       88 break unless scalar %$txt;
400 33         101 $result .= $self->resolve($txt, @subtags);
401             }
402 17         20 default { # resolve the tags in current context
403 17 100       54 $result .= $self->resolve(undef, @subtags) if $txt;
404             }
405             }
406 66         196 $i = $j;
407             }
408 31         45 when ('^') { # inverse section
409 20         25 my $j;
410 20         22 my $nested = 0;
411 20         46 for ($j = $i + 1; $j < @tags; $j++)
412             {
413 29 100       63 if ($tag->{txt} eq $tags[$j]->{txt})
414             {
415 24 100       49 $nested++, next if $tags[$j]->{type} eq '^'; # nested sections with the
416 22 50       36 if ($tags[$j]->{type} eq '/') # same name
417             {
418 22 100       53 next if $nested--;
419 20         41 last;
420             }
421             }
422             }
423 20 50       39 croak 'No end tag found for {{#'.$tag->{txt}.'}}' if $j == @tags;
424 20         52 my @subtags = @tags[$i + 1 .. $j];
425 20         29 my $txt;
426 20 100       48 if ($tag->{txt} =~ /\./)
427             {
428 3         8 my @dots = dottags($tag->{txt});
429 3         10 $txt = $self->resolve(undef, @dots);
430             }
431             else {
432 17         31 $txt = $self->find($tag->{txt}); # get the entry from the context
433             }
434 20         33 my $ans = '';
435 20         35 given (reftype $txt)
436             {
437 20         30 when ('ARRAY') {
438 2 100       9 $ans = $self->resolve(undef, @subtags) if @$txt == 0;
439             }
440 18         26 when ('HASH') {
441 1 50       6 $ans = $self->resolve(undef, @subtags) if keys %$txt == 0;
442             }
443 17         22 when ('CODE') {
444             # $ans = $self->resolve(undef, @subtags) unless &$txt;
445             # The above line is rem'd out to comply with the test:
446             # 'Lambdas used for inverted sections should be considered truthy.'
447             # although I'm not sure I agree with it.
448             }
449 16         20 default {
450 16 100       47 $ans = $self->resolve(undef, @subtags) unless $txt;
451             }
452             }
453 20 50       41 $ans = "$tag->{tab}$ans" if $tag->{tab}; # replace the indent
454 20         32 $result .= $ans;
455 20         47 $i = $j;
456             }
457 11         20 when ('>') { # partial - see include_partial()
458 11         18 my $saved = $self->{delimiters};
459 11         27 $self->{delimiters} = [qw({{ }})];
460 11         28 $result .= $self->include_partial($tag->{txt});
461 11         35 $self->{delimiters} = $saved;
462             }
463 0         0 default { # allow for future expansion
464 0         0 croak "Unknown tag type in \{\{$_$tag->{txt}}}";
465             }
466             }
467             }
468 222         484 $self->pop;
469 222         537 return $result;
470             }
471              
472             # Push something a context onto the stack
473             sub push
474             {
475 222     222 0 288 my $self = shift;
476 222         276 my $value = shift;
477 222         517 $self->{stack}->push($value);
478             }
479              
480             # Pop the context back off the stack
481             sub pop
482             {
483 222     222 0 265 my $self = shift;
484 222         407 my $value = $self->{stack}->pop;
485 222         278 return $value;
486             }
487              
488             # Find a value on the stack
489             sub find
490             {
491 186     186 0 232 my $self = shift;
492 186         237 my $value = shift;
493 186         408 return $self->{stack}->search($value);
494             }
495              
496             # Given a path and a filename
497             # returns the first match that exists
498             sub getfile($$);
499             sub getfile($$)
500             {
501 14     14 0 31 my ($path, $filename) = @_;
502 14         25 $filename =~ s/\r?\n$//; # not chomp $filename because of the possibility of \r\n
503 14 100       37 return if $filename =~ /\r?\n/;
504 13         19 my $fullfile;
505 13 50 33     37 if (ref $path && ref $path eq 'ARRAY')
506             {
507 0         0 foreach (@$path)
508             {
509 0         0 $fullfile = getfile $_, $filename;
510 0 0       0 last if $fullfile;
511             }
512             }
513             else {
514 13         119 $fullfile = File::Spec->catfile($path, $filename);
515 13 50       232 undef $fullfile unless -e $fullfile;
516             }
517 13         35 return $fullfile;
518             }
519              
520              
521             #############################################################
522             ##
523             ## Public Instance Functions
524             ##
525             ##
526              
527 3     3   22 use constant functions => qw(path extension throw partial);
  3         5  
  3         1356  
528              
529             =head2 Configuration Methods
530              
531             The configuration methods match the %options array thay may be passed
532             to new().
533              
534             Each option may be called with a non-false value to set the option
535             and will return the new value. If called without a value, it will return
536             the current value.
537              
538             =over
539              
540             =item path()
541              
542             $tache->path('/some/new/template/path');
543             or
544             $tache->path([ qw{/some/new/template/path .} ]);
545             my $path = $tache->path; # defaults to '.'
546              
547             =item extension()
548              
549             $tache->extension('html');
550             my $extension = $tache->extension; # defaults to 'mustache'
551              
552             =item throw()
553              
554             $tache->throw(1);
555             my $throwing = $tache->throw; # defaults to undef
556              
557             =item partial()
558              
559             $tache->partial(\&resolve_partials)
560             my $partial = $tache->partial # defaults to undef
561              
562             =back
563              
564             =cut
565              
566             sub AUTOLOAD
567             {
568 53     53   74 my $self = shift;
569 53         79 my $class = ref $self;
570 53         63 my $value = shift;
571 53         197 (my $name = our $AUTOLOAD) =~ s/.*:://;
572 53         113 my %ok = map { ($_, 1) } functions;
  212         388  
573 53 50       122 croak "Unknown function $class->$name()" unless $ok{$name};
574 53 50       80 $self->{$name} = $value if $value;
575 53         160 return $self->{$name};
576             }
577              
578             # Prevent it being caught by AUTOLOAD
579             sub DESTROY
580       0     {
581             }
582              
583             =head2 Instance methods
584              
585             =over
586              
587             =item read_file()
588              
589             my $template = read_file('templatefile');
590              
591             You will not usually need to call this directly as it's called by
592             L to load the file. If it is passed a string that looks like
593             a template (i.e. has {{ in it) it simply returns it. Similarly, if,
594             after prepending the path and adding the suffix, it cannot load the file,
595             it simply returns the original string.
596              
597             =back
598              
599             =cut
600              
601             sub read_file($)
602             {
603 122     122 1 155 my $self = shift;
604 122         153 my $file = shift;
605 122 100       208 return '' unless $file;
606 121 100       412 return $file if $file =~ /\{\{/;
607 14         59 my $extension = $self->extension;
608 14         122 (my $fullfile = $file) =~ s/(\.$extension)?$/.$extension/;
609 14         58 my $filepath = getfile $self->path, $fullfile;
610 14 50       45 return $file unless $filepath;
611 0         0 local $/;
612 0 0       0 open my $hand, "<:utf8", $filepath or croak "Can't open $filepath: $!";
613 0         0 <$hand>;
614             }
615              
616             =over
617              
618             =item render()
619              
620             my $context = {
621             "name" => "Chris",
622             "value" => 10000,
623             "taxed_value" => 10000 - (10000 * 0.4),
624             "in_ca" => true
625             }
626             my $html = $tache->render('templatefile', $context);
627              
628             This is the main entry-point for rendering templates. It can be passed
629             either a full template or path to a template file. See L
630             for details of how the file is loaded. It must also be passed a hashref
631             containing the main context.
632              
633             In callbacks (sections like C< {{#this}} > with a subroutine in the context),
634             you may call render on the passed string and the current context will be
635             remembered. For example:
636              
637             {
638             name => "Willy",
639             wrapped => sub {
640             my $text = shift;
641             chomp $text;
642             return "" . $tache->render($text) . "\n";
643             }
644             }
645              
646             Alternatively, you may pass in an entirely new context when calling
647             render() from a callback.
648              
649             =back
650              
651             =cut
652              
653             sub render
654             {
655 122     122 1 1764 my $self = shift;
656 122         241 my ($template, $context) = @_;
657 122 100       269 $context = {} unless $context;
658             # say "\$template = $template, ref \$context = ", ref $context;
659             # print Dumper $context;
660 122         236 $template = $self->read_file($template);
661 122         269 my ($tags, $tail) = $self->match_template($template);
662             # print reassemble(@$tags), $tail; exit;
663 122         307 my $result = $self->resolve($context, @$tags) . $tail;
664 122         421 return $result;
665             }
666              
667             =head1 COMPLIANCE WITH THE STANDARD
668              
669             The original standard for Mustache was defined at the
670             L
671             and this version of L was designed to comply
672             with just that. Since then, the standard for Mustache seems to be
673             defined by the L.
674              
675             The test suite on this version skips a number of tests
676             in the Spec, all of which relate to Decimals or White Space.
677             It passes all the other tests. The YAML from the Spec is built
678             into the test suite.
679              
680             =head1 MANAGING OBJECTS
681              
682             If a blessed object is passed in (at any level) as the context for
683             rendering a template, L will check each tag to
684             see if it can be called as a method on the object. To achieve this, it
685             calls C from L
686             on the object. If C<< $object->can(tag) >>
687             returns code, this code will be called (with no parameters). Otherwise,
688             if the object is based on an underlying HASH, it will be treated as that
689             HASH. This works well for objects with AUTOLOADed "getters".
690              
691             For example:
692              
693             package Test::Mustache;
694              
695             sub new
696             {
697             my $class = shift;
698             my %params = @_;
699             bless \%params, $class;
700             }
701              
702             sub name # Ensure the name starts with a capital
703             {
704             my $self = shift;
705             (my $name = $self->{name}) =~ s/.*/\L\u$&/;
706             return $name;
707             }
708              
709             sub AUTOLOAD # generic getter / setter
710             {
711             my $self = shift;
712             my $value = shift;
713             (my $method = our $AUTOLOAD) =~ s/.*:://;
714             $self->{$method} = $value if defined $value;
715             return $self->{$method};
716             }
717              
718             sub DESTROY { }
719              
720             Using the above object as C<$object>, C<{{name}}> would call
721             C<< $object->can('name') >> which would return a reference to
722             the C method and thus that method would be called as a
723             "getter". On a call to C<{{address}}>, C<< $object->can >> would
724             return undef and therefore C<< $object->{address} >> would be
725             used.
726              
727             This is usually what you want as it avoids the call to C<< $object->AUTOLOAD >>
728             for each simple lookup. If, however, you want something different to
729             happen, you either need to declare a "Forward Declaration"
730             (see L)
731             or you need to override the object's C
732             (see L).
733              
734             =head1 BUGS
735              
736             =over
737              
738             =item White Space
739              
740             Much of the more esoteric white-space handling specified in
741             L is not strictly adhered to
742             in this version. Most of this will be addressed in a future version.
743              
744             Because of this, the following tests from the Mustache Spec are skipped:
745              
746             =over
747              
748             =item * Indented Inline
749              
750             =item * Indented Inline Sections
751              
752             =item * Internal Whitespace
753              
754             =item * Standalone Indentation
755              
756             =item * Standalone Indented Lines
757              
758             =item * Standalone Line Endings
759              
760             =item * Standalone Without Newline
761              
762             =item * Standalone Without Previous Line
763              
764             =back
765              
766             =item Decimal Interpolation
767              
768             The spec implies that the template C<"{{power}} jiggawatts!"> when passed
769             C<{ power: "1.210" }> should return C<"1.21 jiggawatts!">. I believe this to
770             be wrong and simply a mistake in the YAML of the relevant tests or possibly
771             in L. I am far from being a YAML expert.
772              
773             Clearly C<{ power : 1.210 }> would have the desired effect.
774              
775             Because of this, all tests matching C have been skipped. We can just
776             assume that Perl will do the right thing.
777              
778             =back
779              
780             =head1 EXPORTS
781              
782             Nothing.
783              
784             =head1 SEE ALSO
785              
786             L - a much more complex module that is
787             designed to be subclassed for each template.
788              
789             =head1 AUTHOR INFORMATION
790              
791             Cliff Stanford C<< >>
792              
793             =head1 SOURCE REPOSITORY
794              
795             The source is maintained at a public Github repository at
796             L. Feel free to fork
797             it and to help me fix some of the above issues. Please leave any
798             bugs or issues on the L
799             page and I will be notified.
800              
801             =head1 LICENCE AND COPYRIGHT
802              
803             Copyright © 2014, Cliff Stanford C<< >>. All rights reserved.
804              
805             This module is free software; you can redistribute it and/or
806             modify it under the same terms as Perl itself.
807              
808             =cut
809              
810             1;
811