File Coverage

blib/lib/Text/TemplateLite.pm
Criterion Covered Total %
statement 121 147 82.3
branch 48 68 70.5
condition 20 30 66.6
subroutine 21 23 91.3
pod 16 16 100.0
total 226 284 79.5


line stmt bran cond sub pod time code
1             package Text::TemplateLite;
2              
3 2     2   62366 use 5.006;
  2         8  
  2         80  
4 2     2   11 use strict;
  2         10  
  2         78  
5 2     2   12 use warnings;
  2         28  
  2         58  
6 2     2   11 use Carp;
  2         2  
  2         204  
7 2     2   13 use Scalar::Util qw(blessed);
  2         4  
  2         160  
8 2     2   1297 use Text::TemplateLite::Renderer;
  2         4  
  2         4927  
9              
10             =head1 NAME
11              
12             Text::TemplateLite - Pure-Perl text templates with bare-bones syntax,
13             compact size, and limitable resource usage
14              
15             =head1 VERSION
16              
17             Version 0.01
18              
19             =cut
20              
21             our $VERSION = '0.01';
22              
23             =head1 SYNOPSIS
24              
25             use Text::TemplateLite;
26              
27             my $tpl = Text::TemplateLite->new;
28              
29             $tpl->set('Hello, <<$who>>');
30             print $tpl->render({ who => 'world' })->result;
31             # Generates "Hello, world"
32              
33             my $rdr = $tpl->new_renderer;
34             print $rdr->render({ who => 'universe' })->result;
35             # Generates "Hello, universe" with a configurable and
36             # reusable renderer (see Text::TemplateLite::Renderer)
37              
38             =head1 DESCRIPTION
39              
40             =head2 Overview
41              
42             Text::TemplateLite is intended primarily for "string-sized" templating
43             (e.g. for message localization rather than entire "pages") using compact
44             (terse?) templates with a (relatively) simple syntax.
45              
46             It is anticipated that templates may (at least sometimes) be entered or
47             managed by users whose skill set does not include "Perl programmer"
48             (perhaps a web site administrator, translator, or non-Perl programmer).
49              
50             Basic length and execution limits provide a measure of protection against
51             accidental or malicious time- and/or space-based resource attacks. These
52             are managed by the rendering companion class,
53             L.
54              
55             By design, only basic functionality is included in this module. Use parts
56             or all of the L function library and/or
57             create your own custom library to extend its capabilities.
58              
59             =head2 Syntax
60              
61             A template consists of literal text and template code. Any text between
62             "<<" and ">>" that does not contain "<<" or ">>" is treated as template
63             code. Everything else is literal text.
64              
65             Template code can contain sequences in any combination of the following:
66              
67             =over
68              
69             =item Comments
70              
71             Anything from "/*" to the closest "*/" is ignored and does not count
72             as a step (see L<"Steps">).
73              
74             =item String Literals
75              
76             To include literal text within code text, surround the text with single
77             quotes (') or double quotes ("). You can "escape" either kind of quote
78             or < or > in either kind of string by preceding it with a backslash
79             (\', \", \<, or \>). Use '<\<' or '>\>' to generate "<<" or ">>" within
80             code text.
81              
82             No variable substitution is performed within either kind of string literal.
83              
84             =item Numeric Literals
85              
86             Numeric literals consist of an optional minus sign and one or more
87             digits, optionally followed by a decimal point and additional digits.
88              
89             =item Variable Substitutions
90              
91             A dollar sign ($) followed by a name consisting of one or more letters,
92             digits, underscores (_), and/or non-initial periods (.) will be replaced
93             by the corresponding value from the variables supplied either at rendering
94             time or set during template execution.
95              
96             Variables can also store nested templates. Substituting a variable
97             containing a nested template executes the nested template. These templates
98             can be passed parameters using the same syntax as function calls. The
99             parameters will appear in the nested template as template variables "$1",
100             "$2", etc. Parameter "$0" will contain the number of parameters.
101              
102             Parameters after a non-template variable are ignored, unevaluated.
103              
104             $foo /* variable or nested template without parameters */
105             "$foo is " $foo /* only the second $foo is substituted */
106             $foo('hey', 'there') /* nested template(?) with parameters */
107              
108             See L for information
109             on creating nested templates.
110              
111             In future releases, periods in variable names may have structural meaning
112             (e.g. to support lists or maps). Do not write templates that expect "$a"
113             to be unrelated to "$a.b" or "$a.5", for example. For now, however, periods
114             are just part of the name.
115              
116             =item Function And External Template Calls
117              
118             Any other combination of alpha-numeric characters, or combination of symbols
119             other than parentheses or comma, are treated as the name of a function or
120             external template call. Either may optionally be passed a list of zero or
121             more parameters, surrounded by parentheses and separated by commas.
122              
123             Parameters to external templates should be provided in "name, value" pairs.
124              
125             cr nl /* call "cr" and "nl" without parameters */
126             foo('hey', 'there') /* pass foo two strings (or hey=there) */
127              
128             See L for some related
129             functions.
130              
131             Calls to unregistered names will instead call a definition with a zero-length
132             name, if registered, or L<"undef_call($name, $args, $renderer)"> otherwise.
133              
134             =back
135              
136             =head2 Steps
137              
138             Each element (literal, substitution, call, etc.) evaluated during template
139             execution is counted as a "step". For example:
140              
141             $=('a', 2) /* 3 steps: $=, 'a', and 2 */
142             ??(=($a, 1), /* +4 steps: ??, =, $a, and 1 */
143             '$a is 1', /* 1 step not eval'd/counted (= was false) */
144             =($a, 2), /* +3 steps: =, $a, 2 */
145             '$a is 2', /* +1 step: '$a is 2' */
146             'other') /* 1 step not eval'd/counted (not reached) */
147             /* renders '$a is 2' in 11 steps */
148              
149             ?*(<($a, 4), 'loop' $=('a', +($a, 1)))
150             /* 1 step: ?*
151             +3 steps: <, $a, 4 (assuming $a is 2 from above)
152             +6 steps: 'loop', $=, 'a', +, $a, 1 ($a becomes 3)
153             +3 steps: <, $a, 4
154             +6 steps: 'loop', $=, 'a', +, $a, 1 ($a becomes 4)
155             +3 steps: <, $a, 4 (now false, so loop stops)
156             renders 'looploop' in 22 steps */
157              
158             =head1 USER METHODS
159              
160             This section describes methods for normal usage.
161              
162             =head2 new( )
163              
164             This returns a new Text::TemplateLite template engine.
165              
166             =cut
167              
168             sub new {
169 2     2 1 22 my ($class) = @_;
170              
171 2         10 return bless {
172             }, $class;
173             }
174              
175             =head2 register($name, $definition)
176              
177             Register a function (coderef definition) or an external template
178             (Text::TemplateLite definition).
179              
180             $ttl->register('my_function', sub {
181             my ($name, $args, $renderer) = @_;
182             "You called function $name." });
183              
184             my $other_ttl = Text::TemplateLite->new();
185             $other_ttl->set('You called an external template.');
186             $ttl->register('external_tpl', $other_ttl);
187              
188             If you register a definition with a zero-length name, it will be called
189             in place of any call to an undefined function or external template instead
190             of using the default undefined-call handler,
191             L<"undef_call($name, $args, $renderer)">.
192              
193             Library functions (registered as coderefs) are passed three parameters:
194              
195             =over
196              
197             =item $name
198              
199             This is the name of the function as it was invoked from the template.
200              
201             =item $args
202              
203             This is an arrayref of code sequences for any parameters passed from the
204             template. See L<"execute_sequence($code, $renderer)"> and
205             L<"execute_each($list, $renderer)">.
206              
207             =item $renderer
208              
209             This is the instance of L that is managing
210             rendering of the template.
211              
212             =back
213              
214             =cut
215              
216             sub register {
217 3     3 1 545 my ($self, $name, $def) = @_;
218              
219 3         11 $self->{defs}{$name} = $def;
220 3         7 return $self;
221             }
222              
223             =head2 unregister($name)
224              
225             Unregister a function or external template definition.
226              
227             =cut
228              
229             sub unregister {
230 2     2 1 10 my ($self, $name) = @_;
231              
232 2         10 delete($self->{defs}{$name});
233 2         6 return $self;
234             }
235              
236             =head2 set($string)
237              
238             Set or change the template string (see L<"Syntax">) and return the
239             template object.
240              
241             =cut
242              
243             sub set {
244 20     20 1 44 my ($self, $template) = @_;
245              
246 20         53 delete($self->{code});
247              
248 20         150 my @parts = split(/<<(?!<)((?:[^<>]|<[^<]|>[^>])*)>>/s, $template);
249 20         28 my @code;
250              
251             # Template "text<>text<>..." => (text, code, text, code, ...)
252 20         55 for (my $literal = 1; @parts; $literal = !$literal) {
253 37 100       118 if (length(my $part = shift(@parts))) {
254 22 100       41 if ($literal) {
255             # Even elements are literal text.
256 8         36 push(@code, [ "''" => $part ]);
257             } else {
258             # Odd elements are template code text.
259 14         62 my @tokens = $self->get_tokens($part);
260 14         50 push(@code, $self->parse_list(\@tokens, []));
261             }
262             }
263             }
264              
265 20         40 $self->{code} = \@code;
266              
267 20         53 return $self;
268             }
269              
270             =head2 new_renderer( )
271              
272             Returns a new renderer companion object assigned to this template
273             engine. See L.
274              
275             =cut
276              
277             sub new_renderer {
278 5     5 1 2648 return Text::TemplateLite::Renderer->new->template(shift);
279             }
280              
281             =head2 render(\%variables)
282              
283             Create a new renderer via L<"new_renderer( )">, render the template,
284             and return the renderer (not the result).
285              
286             =cut
287              
288             sub render {
289 0     0 1 0 my $self = shift;
290              
291 0         0 return $self->new_renderer->render(@_);
292             }
293              
294             =head1 AUTHOR METHODS
295              
296             This section describes methods generally only used by library function
297             authors.
298              
299             =head2 execute_sequence($code, $renderer)
300              
301             Execute the code step(s), if any, in the sequence $code using renderer
302             $renderer.
303              
304             A code sequence looks like:
305              
306             [ \@step1code, \@step2code, ... ]
307              
308             This method is useful for "progressive" evaluation of individual parameters to
309             functions. It is also used to execute the code resulting from each section
310             of template code in a template.
311              
312             Execution may stop or step results may be truncated in response to
313             exceeded execution limits or a stop set in the rendering information.
314              
315             A sequence consisting of a single function call can return multiple values
316             if execute_sequence is called in array context. Otherwise, the concatenation
317             of step values is returned.
318              
319             =cut
320              
321             sub execute_sequence {
322 31     31 1 41 my ($self, $code, $renderer) = @_;
323              
324             # Return nothing on empty sequence or rendering stop.
325 31 50 100     206 return wantarray? (): ''
    100 66        
326             if !$code || !@$code || $renderer->info->{stop};
327              
328 27         77 my $max_len = $renderer->limit('step_length');
329 27         38 my @parts;
330              
331 27 100 66     71 if (wantarray && @$code == 1) {
332             # A one-step sequence may return multiple values.
333 2         6 @parts = $self->execute_step($code->[0], $renderer);
334              
335 2 50       11 if (defined($max_len)) {
336             # Enforce the step-length limit value-by-value.
337 0         0 foreach (@parts) {
338 0 0       0 if (length > $max_len) {
339 0         0 $_ = substr($_, 0, $max_len);
340 0         0 $renderer->exceeded_limits('step_length');
341             }
342             }
343             }
344 2         15 return @parts;
345             }
346              
347             # Combine all the parts of a multi-step sequence into a single value.
348             # The result must not exceed the step-length limit.
349 25         53 foreach (@$code) {
350 43         100 my $part = join('', $self->execute_step($_, $renderer));
351              
352 43 100       119 if (defined($max_len)) {
353             # Enforce the length limit for the entire sequence.
354 1         3 my $part_len = length($part);
355 1 50       5 if ($part_len > $max_len) {
356 1         3 push(@parts, substr($part, 0, $max_len));
357 1         5 $renderer->exceeded_limits('step_length');
358 1         2 last;
359             }
360 0         0 $max_len -= $part_len;
361             }
362              
363 42         105 push(@parts, $part);
364             }
365              
366 25         115 return join('', @parts);
367             }
368              
369             =head2 execute_each($list, $renderer)
370              
371             Execute an arrayref of code sequences and return a corresponding array
372             of results. This is typically used by library functions to "bulk evaluate"
373             their list of call parameters.
374              
375             $ttl->register('echo', sub {
376             my ($name, $args, $renderer) = @_;
377              
378             "$name(" . join(', ', $renderer->execute_each($args))
379             . ")";
380             });
381             $ttl->set(q{<>});
382             $ttl->render; # renders "echo(hello, world)"
383              
384             $ttl->register('uses2', sub {
385             my ($name, $args, $renderer) = @_;
386              
387             join('', $renderer->template->execute_each(@{$args}[0, 1]));
388             });
389             $ttl->set(q{<>});
390             $ttl->render; # renders "justthese" using 3 steps (not 5)
391              
392             =cut
393              
394             sub execute_each {
395 4     4 1 52 my ($self, $list, $renderer) = @_;
396              
397 4         17 return map($self->execute_sequence($_, $renderer), @$list);
398             }
399              
400             =head2 execute_step($code, $renderer)
401              
402             Execute one code step $code with renderer $renderer unless the total_steps
403             limit has been reached, in which case the total_steps limit is marked
404             exceeded.
405              
406             =cut
407              
408             sub execute_step {
409 45     45 1 60 my $self = shift;
410 45         62 my ($code, $renderer) = @_;
411              
412             # This is a hack in case someone wants to sub-class step execution
413 45 100       108 return $renderer->step? $self->_execute_step(@_): ();
414             }
415              
416             =head2 _execute_step($code, $renderer)
417              
418             This method does the "heavy lifting" after execute_step checks resource
419             usage.
420              
421             The step $code can be one of the following:
422              
423             [ "''" => $literal ]
424             [ '$' => $var_name ]
425             [ '()' => $fn_or_tpl [ \@a1codeseq, \@a2codeseq, ... ] ]
426              
427             A variable substitution is executed as a nested template if it's value
428             looks like this:
429              
430             [ '<>' => \@code_sequence ]
431              
432             =cut
433              
434             sub _execute_step {
435 43     43   70 my ($self, $code, $renderer) = @_;
436 43         61 my $type = $code->[0];
437 43         45 my $value;
438              
439             # Figure out what to do in this step...
440              
441             # [ "''" => $string ] : Return a literal.
442 43 100       108 if ($type eq "''") {
443 32         113 return $code->[1];
444             }
445              
446             # Note: The only currently supported array values are internal
447             # templates. They look like this: [ '<>' => \@code_sequence ]
448             # Other array values are ignored.
449              
450             # [ '$' => $name ] : Interpolate a variable (possibly an internal template).
451 11 100       26 if ($type eq '$') {
452 3         10 $value = $renderer->vars->{$code->[1]};
453              
454             # Check for an internal template.
455 3 0 0     9 return ((@$value && $value->[0] eq '<>')?
    50          
456             $self->execute_template($value->[1], [], $renderer): '')
457             if ref($value) eq 'ARRAY';
458              
459             # Ordinary variable substitution.
460 3 50       14 return defined($value)? $value: '';
461             }
462              
463             # [ '()' => $name, [ @arg_code_sequences ] ] :
464             # Call a function or a template (possibly with parameters).
465 8 50       22 if ($type eq '()') {
466 8         15 my $name = $code->[1];
467              
468 8 50       23 if ($name =~ /^\$([a-zA-Z0-9_\.]+)$/) {
469 0         0 $value = $renderer->vars->{$1};
470              
471 0 0       0 if (ref($value) eq 'ARRAY') {
472 0 0 0     0 return ((@$value && $value->[0] eq '<>')?
473             $self->execute_template($value->[1], $code->[2], $renderer):
474             ());
475             }
476              
477             # Ignore any call parameters and revert to plain variable
478             # substitution.
479 0 0       0 return defined($value)? $value: '';
480             }
481              
482 8         19 $value = $self->{defs}{$name};
483              
484             # Call an external template's renderer if available.
485 8 100 66     59 return $renderer->render_external($value,
486             { $self->execute_each($code->[2], $renderer) })->result
487             if blessed($value) && $value->can('render');
488              
489             # Call a registered function (or an undefined-call handler).
490 4 100       14 unless (ref($value) eq 'CODE') {
491 3         5 $value = $self->{defs}{''};
492 3 100       13 $value = \&undef_call unless ref($value) eq 'CODE';
493             }
494 4         11 return &$value($name, $code->[2], $renderer);
495             }
496              
497 0         0 croak "Unrecognized " . blessed($self) . " step-type: $type";
498             }
499              
500             =head2 execute($renderer)
501              
502             Execute the main template code with renderer $renderer and return the result.
503              
504             You shouldn't need to use this method unless you're building or sub-classing
505             a renderer.
506              
507             =cut
508              
509             sub execute {
510 29     29 1 36 my ($self, $renderer) = @_;
511              
512 29         87 return scalar($self->execute_sequence($self->{code}, $renderer));
513             }
514              
515             =head2 execute_template($code, $args, $renderer)
516              
517             This executes the code from a nested template after saving any
518             previous numeric variables and then setting $0 and parameters $1 through
519             $I.
520              
521             Any previous numeric variables are restored before returning.
522              
523             You shouldn't need this method except possibly if you're extending
524             nested template functionality in some way.
525              
526             =cut
527              
528             sub execute_template {
529 0     0 1 0 my ($self, $code, $args, $renderer) = @_;
530 0         0 my (%save_vars, $vars, $result);
531              
532             # Save and remove any previously existing numbered parameters.
533 0         0 $vars = $renderer->vars;
534 0         0 $save_vars{$_} = delete($vars->{$_}) foreach (grep(/^\d+$/, keys(%$vars)));
535              
536             # Save arguments as numbered parameters $1..$n.
537             # Set $0 to the number of arguments.
538 0         0 $vars->{0} = @$args;
539 0         0 for (my $i = 0; $i < @$args; ++$i) {
540 0         0 $vars->{$i + 1} = $self->execute_sequence($args->[$i], $renderer);
541             }
542              
543 0         0 $result = $self->execute_sequence($code, $renderer);
544              
545             # Remove current numbered parameters and restore anything we removed.
546 0         0 delete($vars->{$_}) foreach grep(/^\d+$/, keys(%$vars));
547 0         0 @$vars{keys(%save_vars)} = values(%save_vars);
548              
549 0         0 return $result;
550             }
551              
552             =head2 undef_call($name, $args, $renderer)
553              
554             This function is the default undefined-call handler called by the
555             L<"_execute_step($code, $renderer)"> method if no zero-length name is
556             currently registered.
557              
558             It increments the C count in the rendering information and
559             returns no value.
560              
561             =cut
562              
563             sub undef_call {
564 2     2 1 4 my ($name, $args, $renderer) = @_;
565              
566 2         9 ++$renderer->info->{undef_calls};
567 2         10 return ();
568             }
569              
570             =head1 PARSING METHODS
571              
572             These methods are used for parsing. If you extend these in a sub-class it's
573             likely to get ugly pretty quickly.
574              
575             =head2 get_tokens($text)
576              
577             Split template code text into tokens and return them as a list.
578              
579             =cut
580              
581             sub get_tokens {
582 15     15 1 41 my ($self, $text) = @_;
583              
584 15         705 return grep(!/^\s*$/, split(
585             /(
586             \/\*.*?\*\/ # \/* comment *\/
587             |
588             '(?:\\'|[^'])*' # 'string'
589             |
590             "(?:\\"|[^"])*" # "string"
591             |
592             \$[a-zA-Z0-9_][a-zA-Z0-9_\.]* # $vari.able
593             |
594             [a-zA-Z_][a-zA-Z0-9_]* # alpha-numeric function
595             |
596             -?\d+(?:\.\d*)? # integer or floating numeric literal
597             |
598             [(),] # (parameter, lists)
599             |
600             \s+
601             )/x,
602             $text));
603             }
604              
605             =head2 parse_list(\@tokens, \@stops)
606              
607             Parse a block of code from the token list up to one of the stop
608             symbols. This might be an entire code segment or parts of a call's
609             parameter list. The code tree is returned.
610              
611             =cut
612              
613             sub parse_list {
614 16     16 1 24 my ($self, $tokens, $stops) = @_;
615 16         20 my (@code, $token);
616              
617 16         43 while (@$tokens) {
618 27         36 $token = shift(@$tokens);
619              
620             # Remove comments
621 27 100       75 next if $token =~ /^\/\*.*\*\/$/s;
622              
623             # String literals
624 25 100 100     148 if ($token =~ /^'(.*)'$/s || $token =~ /^"(.*)"$/s) {
625 17         43 push(@code, [ "''" => $self->unescape($1) ]);
626 17         57 next;
627             }
628              
629             # Numeric literals
630 8 50       31 if ($token =~ /^-?\d+(?:\.\d*)?$/) {
631 0         0 push(@code, [ "''" => $token ]);
632 0         0 next;
633             }
634              
635             # Variables or internal template calls
636 8 100       25 if ($token =~ /^\$([a-zA-Z0-9_]+)$/) {
637 3 50 66     18 if (@$tokens && $tokens->[0] eq '(') {
638 0         0 push(@code, $self->parse_call($token, $tokens));
639             } else {
640 3         10 push(@code, [ '$' => $1 ]);
641             }
642 3         9 next;
643             }
644              
645             # Check stop list
646 5         14 foreach (@$stops) {
647 3 100       9 if ($token eq $_) {
648 2         4 unshift(@$tokens, $token);
649 2         9 return @code;
650             }
651             }
652              
653             # Function or external template call, with or without parameters
654 3         9 push(@code, $self->parse_call($token, $tokens));
655             }
656              
657 14         84 return @code;
658             }
659              
660             =head2 parse_call($name, $tokens)
661              
662             Parse a parameter list if one follows in the token stream and return the
663             code tree for a call to the function or template in $name.
664              
665             =cut
666              
667             sub parse_call {
668 3     3 1 6 my ($self, $name, $tokens) = @_;
669 3         5 my (@args, $token);
670              
671 3 100 100     19 if (@$tokens && $tokens->[0] eq '(') {
672 1         2 shift(@$tokens);
673 1         7 while (@$tokens) {
674 4         7 $token = $tokens->[0];
675 4 100 100     21 shift(@$tokens) if $token eq ',' || $token eq ')';
676 4 100       11 last if $token eq ')';
677              
678 3 100       11 if ($token ne ',') {
679             # The argument continues to the next ',' or ')'.
680 2         10 my @code = $self->parse_list($tokens, [',', ')']);
681 2 50       11 push(@args, \@code) if @code;
682             }
683             }
684             }
685              
686             # [ '()' => $name, [ \@arg0_code_seq, \@arg1_code_seq, ... ] ]
687 3         16 return [ '()' => $name, \@args ];
688             }
689              
690             =head2 unescape($string)
691              
692             Un-escape backslashed characters for string literals.
693              
694             =cut
695              
696             sub unescape {
697 17     17 1 34 my ($self, $string) = @_;
698              
699 17         29 $string =~ s/\\(.)/$1/g;
700 17         50 return $string;
701             }
702              
703             =head1 AUTHOR
704              
705             Brian Katzung, C<< >>
706              
707             =head1 BUGS
708              
709             Please report any bugs or feature requests to
710             C, or through the web interface at
711             L. I
712             will be notified, and then you'll automatically be notified of progress
713             on your bug as I make changes.
714              
715             =head1 SUPPORT
716              
717             You can find documentation for this module with the perldoc command.
718              
719             perldoc Text::TemplateLite
720              
721             You can also look for information at:
722              
723             =over 4
724              
725             =item * RT: CPAN's request tracker (report bugs here)
726              
727             L
728              
729             =item * AnnoCPAN: Annotated CPAN documentation
730              
731             L
732              
733             =item * CPAN Ratings
734              
735             L
736              
737             =item * Search CPAN
738              
739             L
740              
741             =back
742              
743             =head1 SEE ALSO
744              
745             L (the companion class to
746             Text::TemplateLite for rendering management) and
747             L (for standard library functions,
748             with examples)
749              
750             L ("powerful, high-performance templating for web and beyond")
751              
752             L (an alternative template system based on embedding
753             Perl code in templates)
754              
755             L (an alternative template system [based on "including
756             the kitchen sink"])
757              
758             L for a
759             comparison of template modules
760              
761             =head2 EVEN MORE TEMPLATE MODULES
762              
763             L,
764             L,
765             L,
766             L,
767             L,
768             L,
769             L,
770             L,
771             L,
772             L,
773             L,
774             L,
775             L,
776             L,
777             L,
778             L,
779             L,
780             L,
781             L,
782             L,
783             L,
784             L,
785             L,
786             L,
787             L,
788             L,
789             L,
790             L,
791             L
792             L,
793             L,
794             L
795              
796             ... and probably some I missed.
797              
798             =head1 LICENSE AND COPYRIGHT
799              
800             Copyright 2012 Brian Katzung.
801              
802             This program is free software; you can redistribute it and/or modify it
803             under the terms of either: the GNU General Public License as published
804             by the Free Software Foundation; or the Artistic License.
805              
806             See http://dev.perl.org/licenses/ for more information.
807              
808             =cut
809              
810             1; # End of Text::TemplateLite
811