File Coverage

blib/lib/Template/Liquid.pm
Criterion Covered Total %
statement 86 86 100.0
branch 4 4 100.0
condition 1 3 33.3
subroutine 28 28 100.0
pod 3 7 42.8
total 122 128 95.3


line stmt bran cond sub pod time code
1             package Template::Liquid;
2             our $VERSION = '1.0.23';
3 25     25   2744179 use strict;
  25         317  
  25         759  
4 25     25   169 use warnings;
  25         51  
  25         1057  
5             our (%tags, %filters);
6             #
7 25     25   12535 use Template::Liquid::Document;
  25         83  
  25         771  
8 25     25   12671 use Template::Liquid::Context;
  25         79  
  25         860  
9 25     25   12396 use Template::Liquid::Tag;
  25         99  
  25         709  
10 25     25   11418 use Template::Liquid::Block;
  25         65  
  25         783  
11 25     25   13569 use Template::Liquid::Condition;
  25         69  
  25         1948  
12 326     326 1 12046 sub register_tag { $tags{$_} = scalar caller for @_ }
13 608     608 0 4981 sub tags {%tags}
14 25     25   11768 use Template::Liquid::Tag::Assign;
  25         78  
  25         120  
15 25     25   11823 use Template::Liquid::Tag::Break;
  25         97  
  25         104  
16 25     25   11971 use Template::Liquid::Tag::Capture;
  25         71  
  25         180  
17 25     25   11909 use Template::Liquid::Tag::Case;
  25         75  
  25         195  
18 25     25   12073 use Template::Liquid::Tag::Comment;
  25         75  
  25         129  
19 25     25   11653 use Template::Liquid::Tag::Continue;
  25         71  
  25         106  
20 25     25   11584 use Template::Liquid::Tag::Cycle;
  25         66  
  25         115  
21 25     25   11477 use Template::Liquid::Tag::Decrement;
  25         97  
  25         165  
22 25     25   12186 use Template::Liquid::Tag::For;
  25         83  
  25         135  
23 25     25   170 use Template::Liquid::Tag::If;
  25         76  
  25         133  
24 25     25   136 use Template::Liquid::Tag::Increment;
  25         55  
  25         191  
25 25     25   11301 use Template::Liquid::Tag::Raw;
  25         80  
  25         103  
26 25     25   11293 use Template::Liquid::Tag::Unless;
  25         73  
  25         112  
27 25     25 1 8536 sub register_filter { $filters{$_} = scalar caller for @_ }
28 186     186 0 3979 sub filters {%filters}
29              
30             # merge
31 25     25   14684 use Template::Liquid::Filters;
  25         81  
  25         213  
32             #
33             sub new {
34 371     371 0 1116 my ($class) = @_;
35 371         1894 my $s = bless {break => 0,
36             continue => 0,
37             tags => {},
38             filters => {},
39             line => 1,
40             column => 0
41             }, $class;
42 371         822 return $s;
43             }
44              
45             sub parse {
46 369     369 0 640451 my ($class, $source) = @_;
47 369 100       1238 my $s = ref $class ? $class : $class->new();
48 369         1375 my @tokens = Template::Liquid::Utility::tokenize($source);
49 369   33     2594 $s->{'document'} ||= Template::Liquid::Document->new({template => $s});
50 369         1579 $s->{'document'}->parse(\@tokens);
51 369         2116 return $s;
52             }
53              
54             sub render {
55 388     388 1 1576 my ($s, %assigns) = @_;
56 388         632 my $result;
57 388 100       979 if (!$s->{context}) {
58             $s->{context}
59 368         1301 = Template::Liquid::Context->new(template => $s,
60             assigns => \%assigns);
61 368         1100 $result = $s->{document}->render();
62             }
63             else {
64             # This is quite similar to $s->{context}->block(), but
65             # we want %assigns to override what is currently in the scope
66 20         52 my $old_scope = $s->{context}->{scopes}->[-1];
67 20         135 $s->{context}->push({%$old_scope, %assigns});
68 20         76 $result = $s->{document}->render();
69 20         67 $s->{context}->pop;
70             }
71 388         2485 return $result;
72             }
73             1;
74              
75             =pod
76              
77             =encoding UTF-8
78              
79             =begin stopwords
80              
81             sorta whitespace non-evaling
82              
83             =end stopwords
84              
85             =head1 NAME
86              
87             Template::Liquid - A Simple, Stateless Template System
88              
89             =head1 Synopsis
90              
91             use Template::Liquid;
92             my $template = Template::Liquid->parse(
93             '{% for x in (1..3) reversed %}{{ x }}, {% endfor %}{{ some.text }}');
94             print $template->render(some => {text => 'Contact!'}); # 3, 2, 1, Contact!
95              
96             =head1 Description
97              
98             The original Liquid template engine was crafted for very specific requirements:
99              
100             =over 4
101              
102             =item * It has to have simple markup and beautiful results.
103              
104             Template engines which don't produce good looking results are no fun to use.
105              
106             =item * It needs to be non-evaling and secure.
107              
108             Liquid templates are made so that users can edit them. You don't want to run
109             code on your server which your users wrote.
110              
111             =item * It has to be stateless.
112              
113             The compile and render steps have to be separate so the expensive parsing and
114             compiling can be done once; later on, you can just render it by passing in a
115             hash with local variables and objects.
116              
117             =item * It needs to be able to style email as well as HTML.
118              
119             =back
120              
121             =head1 Getting Started
122              
123             It's very simple to get started. Templates are built and used in two steps:
124             Parse and Render.
125              
126             If you're in a hurry, you could just...
127              
128             use Template::Liquid;
129             print Template::Liquid->parse('Hi, {{name}}!')->render(name => 'Sanko');
130              
131             But because Liquid is stateless, you can split that part. Keep reading.
132              
133             =head2 Parse
134              
135             use Template::Liquid;
136             my $sol = Template::Liquid->new(); # Create a Template::Liquid object
137             $sol->parse('Hi, {{name}}!'); # Parse and compile the template
138              
139             ...or...
140              
141             use Template::Liquid;
142             my $sol = Template::Liquid->parse('Hi, {{name}}!'); # Obj is auto-created
143              
144             The C<parse> step creates a fully compiled template which can be re-used as
145             often as you like. You can store it in memory or in a cache for faster
146             rendering later. Templates are simple, blessed references so you could do...
147              
148             use Template::Liquid;
149             use Data::Dump qw[pp];
150             my $greet = Template::Liquid->parse('Hi, {{name}}!');
151             my $dump = pp($greet);
152              
153             ...store C<$dump> somewhere (a file, database, etc.) and then eval the
154             structure later without doing the 'expensive' parsing step again.
155              
156             =head2 Render
157              
158             To complete our C<$sol> examples from the previous section, rendering a
159             template is as easy as...
160              
161             $sol->render(name => 'Sanko'); # Returns 'Hi, Sanko!'
162             $sol->render(name => 'Megatron'); # Returns 'Hi, Megatron!'
163              
164             All parameters you want Template::Liquid to work with must be passed to the
165             C<render> method. Template::Liquid is a closed ecosystem; it does not know
166             about your local, instance, global, or environment variables. If your template
167             requires any of those, you must pass them along:
168              
169             use Template::Liquid;
170             print Template::Liquid->parse(
171             '@INC: {%for item in inc%}{{item}}, {%endfor%}')
172             ->render(inc => \@INC);
173              
174             =head1 Standard Liquid Tags
175              
176             L<Expanding the list of supported tags|/"Extending Template::Liquid"> is easy
177             but here's the current standard set:
178              
179             =head2 C<comment>
180              
181             Comment tags are simple blocks that do nothing during the L<render|/"Render">
182             stage. Use these to temporarily disable blocks of code or to insert
183             documentation.
184              
185             This is a {% comment %} secret {% endcomment %}line of text.
186              
187             ...renders to...
188              
189             This is a line of text.
190              
191             For more, see L<Template::Liquid::Tag::Comment|Template::Liquid::Tag::Comment>.
192              
193             =head2 C<raw>
194              
195             Raw temporarily disables tag processing. This is useful for generating content
196             (Mustache, Handlebars) which uses conflicting syntax.
197              
198             {% raw %}
199             In Handlebars, {{ this }} will be HTML-escaped, but {{{ that }}} will not.
200             {% endraw %}
201              
202             ...renders to...
203              
204             In Handlebars, {{ this }} will be HTML-escaped, but {{{ that }}} will not.
205              
206             For more, see L<Template::Liquid::Tag::Raw|Template::Liquid::Tag::Raw>.
207              
208             =head2 C<if> / C<elseif> / C<else>
209              
210             {% if post.body contains search_string %}
211             <div class="post result" id="p-{{post.id}}">
212             <p class="title">{{ post.title }}</p>
213             ...
214             </div>
215             {% endunless %}
216              
217             For more, see L<Template::Liquid::Tag::If|Template::Liquid::Tag::If> and
218             L<Template::Liquid::Condition|Template::Liquid::Condition>. .
219              
220             =head2 C<unless> / C<elseif> / C<else>
221              
222             This is sorta the opposite of C<if>.
223              
224             {% unless some.value == 3 %}
225             Well, the value sure ain't three.
226             {% elseif some.value > 1 %}
227             It's greater than one.
228             {% else %}
229             Well, is greater than one but not equal to three.
230             Psst! It's {{some.value}}.
231             {% endunless %}
232              
233             For more, see L<Template::Liquid::Tag::Unless|Template::Liquid::Tag::Unless>
234             and L<Template::Liquid::Condition|Template::Liquid::Condition>.
235              
236             =head2 C<case>
237              
238             If you need more conditions, you can use the case statement:
239              
240             {% case condition %}
241             {% when 1 %}
242             hit 1
243             {% when 2 or 3 %}
244             hit 2 or 3
245             {% else %}
246             ... else ...
247             {% endcase %}
248              
249             For more, see L<Template::Liquid::Tag::Case|Template::Liquid::Tag::Case>.
250              
251             =head2 C<cycle>
252              
253             Often you have to alternate between different colors or similar tasks. Liquid
254             has built-in support for such operations, using the cycle tag.
255              
256             {% cycle 'one', 'two', 'three' %}
257             {% cycle 'one', 'two', 'three' %}
258             {% cycle 'one', 'two', 'three' %}
259             {% cycle 'one', 'two', 'three' %}
260              
261             ...will result in...
262              
263             one
264             two
265             three
266             one
267              
268             If no name is supplied for the cycle group, then it's assumed that multiple
269             calls with the same parameters are one group.
270              
271             If you want to have total control over cycle groups, you can optionally specify
272             the name of the group. This can even be a variable.
273              
274             {% cycle 'group 1': 'one', 'two', 'three' %}
275             {% cycle 'group 1': 'one', 'two', 'three' %}
276             {% cycle 'group 2': 'one', 'two', 'three' %}
277             {% cycle 'group 2': 'one', 'two', 'three' %}
278              
279             ...will result in...
280              
281             one
282             two
283             one
284             two
285              
286             For more, see L<Template::Liquid::Tag::Cycle|Template::Liquid::Tag::Cycle>.
287              
288             =head2 C<increment>
289              
290             Creates a new number variable, and increases its value by one every time it is
291             called. The initial value is C<0>.
292              
293             {% increment my_counter %}
294             {% increment my_counter %}
295             {% increment my_counter %}
296              
297             ...would become...
298              
299             0
300             1
301             2
302              
303             =head2 C<decrement>
304              
305             Creates a new number variable, and decreases its value by one every time it is
306             called. The initial value is C<-1>.
307              
308             {% decrement variable %}
309             {% decrement variable %}
310             {% decrement variable %}
311              
312             ...would become...
313              
314             -1
315             -2
316             -3
317              
318             For more, see
319             L<Template::Liquid::Tag::Decrement|Template::Liquid::Tag::Decrement>.
320              
321             =head2 C<for>
322              
323             Liquid allows for loops over collections:
324              
325             {% for item in array %}
326             {{ item }}
327             {% endfor %}
328              
329             Please see see L<Template::Liquid::Tag::For|Template::Liquid::Tag::For>.
330              
331             =head2 C<assign>
332              
333             You can store data in your own variables, to be used in output or other tags as
334             desired. The simplest way to create a variable is with the assign tag, which
335             has a pretty straightforward syntax:
336              
337             {% assign name = 'freestyle' %}
338              
339             {% for t in collections.tags %}{% if t == name %}
340             <p>Freestyle!</p>
341             {% endif %}{% endfor %}
342              
343             Another way of doing this would be to assign true / false values to the
344             variable:
345              
346             {% assign freestyle = false %}
347              
348             {% for t in collections.tags %}{% if t == 'freestyle' %}
349             {% assign freestyle = true %}
350             {% endif %}{% endfor %}
351              
352             {% if freestyle %}
353             <p>Freestyle!</p>
354             {% endif %}
355              
356             If you want to combine a number of strings into a single string and save it to
357             a variable, you can do that with the capture tag.
358              
359             For more, see L<Template::Liquid::Tag::Assign|Template::Liquid::Tag::Assign>.
360              
361             =head2 C<capture>
362              
363             This tag is a block which "captures" whatever is rendered inside it, then
364             assigns the captured value to the given variable instead of rendering it to the
365             screen.
366              
367             {% capture attribute_name %}{{ item.title | handleize }}-{{ i }}-color{% endcapture %}
368              
369             <label for="{{ attribute_name }}">Color:</label>
370             <select name="attributes[{{ attribute_name }}]" id="{{ attribute_name }}">
371             <option value="red">Red</option>
372             <option value="green">Green</option>
373             <option value="blue">Blue</option>
374             </select>
375              
376             For more, see L<Template::Liquid::Tag::Capture|Template::Liquid::Tag::Capture>.
377              
378             =head1 Standard Liquid Filters
379              
380             Please see L<Template::Liquid::Filters|Template::Liquid::Filters>.
381              
382             =head1 Whitespace Control
383              
384             In Liquid, you can include a hyphen in your tag syntax C<{{->, C<-}}>, C<{%->,
385             and C<-%}> to strip whitespace from the left or right side of a rendered tag.
386              
387             See https://shopify.github.io/liquid/basics/whitespace/
388              
389             =head1 Extending Template::Liquid
390              
391             Extending the Template::Liquid template engine for your needs is almost too
392             simple. Keep reading.
393              
394             =head2 Custom Tags
395              
396             See the section entitled L<Extending Template::Liquid with Custom
397             Tags|Template::Liquid::Tag/"Extending Template::Liquid with Custom Tags"> in
398             L<Template::Liquid::Tag> for more information.
399              
400             Also check out the examples of L<Template::LiquidX::Tag::Dump> and
401             L<Template::LiquidX::Tag::Include> now on CPAN.
402              
403             To assist with custom tag creation, Template::Liquid provides several basic tag
404             types for subclassing and exposes the following methods:
405              
406             =head3 C<< Template::Liquid::register_tag( ... ) >>
407              
408             This registers a package which must contain (directly or through inheritance)
409             both a C<parse> and C<render> method.
410              
411             # Register a new tag which Template::Liquid will look for in the calling package
412             Template::Liquid::register_tag( 'newtag' );
413              
414             # Or simply say...
415             Template::Liquid::register_tag( 'newtag' );
416             # ...and Template::Liquid will assume the new tag is in the calling package
417              
418             Pre-existing tags are replaced when new tags are registered with the same name.
419             You may want to do this to override some functionality.
420              
421             =head2 Custom Filters
422              
423             Filters are simple subs called when needed. They are not passed any state data
424             by design and must return the modified content.
425              
426             =for todo I need to write Template::Liquid::Filter which will be POD with all sorts of info in it. Yeah.
427              
428             =head3 C<< Template::Liquid::register_filter( ... ) >>
429              
430             This registers a package which Template::Liquid will assume contains one or
431             more filters.
432              
433             # Register a package as a filter
434             Template::Liquid::register_filter( 'Template::Solution::Filter::Amalgamut' );
435              
436             # Or simply say...
437             Template::Liquid::register_filter( );
438             # ...and Template::Liquid will assume the filters are in the calling package
439              
440             =head1 Why should I use Template::Liquid?
441              
442             =over 4
443              
444             =item * You want to allow your users to edit the appearance of your
445             application, but don't want them to run insecure code on your server.
446              
447             =item * You want to render templates directly from the database.
448              
449             =item * You like Smarty-style template engines.
450              
451             =item * You need a template engine which does HTML just as well as email.
452              
453             =item * You don't like the markup language of your current template engine.
454              
455             =item * You wasted three days reinventing this wheel when you could have been
456             doing something productive like volunteering or catching up on past seasons of
457             I<Doctor Who>.
458              
459             =back
460              
461             =head1 Why shouldn't I use Template::Liquid?
462              
463             =over 4
464              
465             =item * You've found or written a template engine which fills your needs
466             better than Liquid or Template::Liquid ever could.
467              
468             =item * You are uncomfortable with text that you didn't copy and paste
469             yourself. Everyone knows computers cannot be trusted.
470              
471             =back
472              
473             =head1 Template::LiquidX or Solution?
474              
475             I'd really rather use Solution::{Package} for extensions but Template::LiquidX
476             really is a better choice.
477              
478             As I understand it, the original project's name, Liquid, is a reference to the
479             classical states of matter (the engine itself being stateless). I wanted to use
480             L<solution|http://en.wikipedia.org/wiki/Solution> because it's liquid but with
481             bits of other stuff floating in it. (Pretend you majored in chemistry instead
482             of mathematics or computer science.) Liquid templates will I<always> work with
483             Template::Liquid but (due to Template::LiquidX's expanded syntax)
484             Template::LiquidX templates I<may not> be compatible with Liquid or
485             Template::Liquid.
486              
487             =head1 Author
488              
489             Sanko Robinson <sanko@cpan.org> - http://sankorobinson.com/
490              
491             CPAN ID: SANKO
492              
493             =encoding utf8
494              
495             The original Liquid template system was developed by
496             L<jadedPixel|http://jadedpixel.com/> and L<Tobias
497             Lütke|http://blog.leetsoft.com/>.
498              
499             =head1 License and Legal
500              
501             Copyright (C) 2009-2022 by Sanko Robinson <sanko@cpan.org>
502              
503             This program is free software; you can redistribute it and/or modify it under
504             the terms of L<The Artistic License
505             2.0|http://www.perlfoundation.org/artistic_license_2_0>. See the F<LICENSE>
506             file included with this distribution or L<notes on the Artistic License
507             2.0|http://www.perlfoundation.org/artistic_2_0_notes> for clarification.
508              
509             When separated from the distribution, all original POD documentation is covered
510             by the L<Creative Commons Attribution-Share Alike 3.0
511             License|http://creativecommons.org/licenses/by-sa/3.0/us/legalcode>. See the
512             L<clarification of the
513             CCA-SA3.0|http://creativecommons.org/licenses/by-sa/3.0/us/>.
514              
515             =cut