File Coverage

blib/lib/Mustache/Simple.pm
Criterion Covered Total %
statement 225 234 96.1
branch 74 92 80.4
condition 8 10 80.0
subroutine 28 29 96.5
pod 3 14 21.4
total 338 379 89.1


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