File Coverage

blib/lib/Plate.pm
Criterion Covered Total %
statement 301 301 100.0
branch 239 242 98.7
condition 145 164 88.4
subroutine 60 60 100.0
pod 10 10 100.0
total 755 777 97.1


line stmt bran cond sub pod time code
1 7     7   403793 use 5.020;
  7         85  
2 7     7   38 use warnings;
  7         13  
  7         331  
3             package Plate 1.5;
4              
5 7     7   36 use Carp 'croak';
  7         14  
  7         354  
6 7     7   42 use File::Spec;
  7         29  
  7         210  
7 7     7   40 use Scalar::Util;
  7         45  
  7         301  
8 7     7   42 use XSLoader;
  7         13  
  7         280  
9              
10 7     7   38 use constant WINDOWS => $^O eq 'MSWin32';
  7         12  
  7         639  
11              
12             BEGIN {
13 7     7   30805 XSLoader::load __PACKAGE__, $Plate::VERSION;
14             }
15              
16             =encoding UTF-8
17              
18             =head1 NAME
19              
20             Plate - Fast templating engine with support for embedded Perl
21              
22             =head1 SYNOPSIS
23              
24             use Plate;
25            
26             my $plate = Plate->new(
27             path => '/path/to/plate/files/',
28             cache_path => '/tmp/cache/',
29             auto_filter => 'trim',
30             );
31            
32             $plate->filter(html => \&HTML::Escape::escape_html);
33             $plate->filter(trim => sub { $_[0] =~ s/^\s+|\s+$//gr });
34            
35             # Render /path/to/plate/files/hello.plate cached as /tmp/cache/hello.pl
36             my $output = $plate->serve('hello');
37             print $output;
38              
39             =cut
40              
41             my $re_pre = qr'(.*?)(?:
42             ^%%\h*(\V*?)\h*(?:\R|\z)|
43             ^<%%(perl)>(?:\R|\z)(?:(.*?)^(?:\R|\z))?|
44             ^<%%(def|filter)\h+([\w/\.-]+)>(?:\R|\z)|
45             <%%(\s*(?:\#.+?)?)%%>|
46             <%%\s*(.+?)\s*(?:\|\h*(|\w+(?:\s*\|\h*\w+)*)\s*)?%%>|
47             <&&(\|)?\s*(.+?)\s*(?:\|\h*(|\w+(?:\s*\|\h*\w+)*)\s*)?&&>|
48             (?:\R|\z)|
49             |\z
50             )'mosx;
51             my $re_run = qr'(.*?)(?:
52             ^%\h*(\V*?)\h*(?:\R|\z)|
53             ^<%(perl)>(?:\R|\z)(?:(.*?)^(?:\R|\z))?|
54             ^<%(def|filter)\h+([\w/\.-]+)>(?:\R|\z)|
55             <%(\s*(?:\#.+?)?)%>|
56             <%\s*(.+?)\s*(?:\|\h*(|\w+(?:\s*\|\h*\w+)*)\s*)?%>|
57             <&(\|)?\s*(.+?)\s*(?:\|\h*(|\w+(?:\s*\|\h*\w+)*)\s*)?&>|
58             (?:\R|\z)|
59             |\z
60             )'mosx;
61              
62             sub _parse_text {
63 328     328   578 my $text = $_[0];
64 328 100       802 $_[2] = $text =~ s/\\\R//g unless $_[1];
65 328         1193 $text =~ s/(\\|')/\\$1/g;
66 328 100       1050 length $text ? "'$text'" : ();
67             }
68             sub _parse_cmnt {
69 77     77   136 my $cmnt = $_[0];
70 77 100       383 $cmnt =~ /^#(?:\s*line\s+(\d+)\s*(?:\s("?)([^"]+)\g2)?\s*|.*)$/
    100          
    100          
71             ? defined $1
72             ? defined $3
73             ? "\n#line $1 $3"
74             : "\n#line $1"
75             : ''
76             : $cmnt;
77             }
78             sub _parse_defn {
79 9     9   20 my $defn = $_[0];
80 9 100       44 $defn =~ /\W/ ? "'".($defn =~ s/(\\|')/\\$1/gr)."'" : $defn;
81             }
82             sub _parse_fltr {
83 175     175   278 my $expr = $_[0];
84 175 100       462 $expr .= "//''" unless $$Plate::_s{keep_undef};
85 175 100       430 if (length $_[1]) {
    100          
86 80         376 $expr = "Plate::_f($_=>$expr)" for split /\s*\|\s*/, $_[1];
87             } elsif (not $$Plate::_s{keep_undef}) {
88 88         163 $expr = "($expr)";
89             }
90 175         355 $expr;
91             }
92             sub _parse {
93 264     264   462 my @expr;
94             my $stmt;
95 264         501 my $pre = $_[1] == $re_pre;
96 264         361 my $fix_line_num;
97             my $expr2stmt = sub {
98 195 100   195   368 if (@expr) {
99 125 100       249 if (defined $stmt) {
100 85 100       160 $stmt .= ';push@Plate::_l,length$Plate::_b,__LINE__' if $pre;
101 85         118 $stmt .= ';$Plate::_b.=';
102             } else {
103 40         62 $stmt = 'local$Plate::_b=';
104             }
105 125 100       449 $stmt .= join('.', $_[0] ? splice @expr, 0, $fix_line_num : splice @expr).';';
106             } else {
107 70   100     198 $stmt //= q"local$Plate::_b='';";
108             }
109 195 100       439 undef $fix_line_num unless $_[0];
110 264         948 };
111 264         3494 while ($_[0] =~ /$_[1]/g) {
112              
113 534 100       1462 if (length $1) {
114 328         636 push @expr, _parse_text $1, $pre, my $add_lines;
115 328 100       701 (@expr ? $expr[-1] : defined $stmt ? $stmt : ($expr[0] = "''")) .= "\n" x $add_lines if $add_lines;
    100          
    100          
116 328 100       608 $fix_line_num = @expr if $fix_line_num;
117             }
118              
119 534 100 100     1626 if (!$pre and @Plate::_l and $Plate::_l[0] <= $+[1]) {
      100        
120 24         78 my($pos, $line) = splice @Plate::_l, 0, 2;
121 24   100     163 ($pos, $line) = splice @Plate::_l, 0, 2 while @Plate::_l and $Plate::_l[0] <= $+[1];
122 24         73 my $rem = $+[1] - $pos;
123 24 100       70 $line += substr($_[0], $pos, $rem) =~ tr/\n// if $rem;
124 24         59 $expr2stmt->();
125 24         59 $stmt .= "\n#line $line\n";
126             }
127              
128 534 100       1985 if (defined $2) {
    100          
    100          
    100          
    100          
    100          
129             # % ...
130 77         168 $expr2stmt->();
131 77         150 $stmt .= _parse_cmnt $2;
132 77         144 $stmt .= "\n";
133              
134             } elsif (defined $3) {
135             # <%perl>
136 8         14 $expr2stmt->();
137 8 100       21 unless (defined $4) {
138 2         5 my $line = 1 + $stmt =~ y/\n//;
139 2   100     11 $line = "$_[2] line $line.\nPlate ".($pre && 'pre').'compilation failed';
140 2   100     10 my $tag = ($pre && '%').'%'.$3;
141 2         197 croak "Opening <$tag...> tag without closing tag at $line";
142             }
143 6         15 $stmt .= "\n$4\n";
144              
145             } elsif (defined $5) {
146             # <%def ...> or <%filter ...>
147 9         23 $expr2stmt->();
148 9   100     68 local $_[3] = ($pre && '%')."%$5";
149 9         25 my $n = _parse_defn $6;
150 9 100       64 $stmt .= $5 eq 'def'
151             ? "local\$\$Plate::_s{mem}{$n}=\nsub{".&_parse.'};'
152             : "local\$\$Plate::_s{filters}{$n}=\nsub{my\$_c=\$_[0];local\@Plate::_c=sub{\$_c};".&_parse.'};';
153              
154             } elsif (defined $7) {
155             # <%# ... %>
156 4         17 my $add_lines = $7 =~ tr/\n//;
157 4 100       22 (@expr ? $expr[-1] : defined $stmt ? $stmt : ($expr[0] = "''")) .= "\n" x $add_lines if $add_lines;
    100          
    100          
158 4 100       11 $fix_line_num = @expr if $fix_line_num;
159              
160             } elsif (defined $8) {
161             # <% ... %>
162 106         507 my $nl1 = "\n" x substr($_[0], $+[1], $-[8] - $+[1]) =~ tr/\n//;
163 106         408 my $nl2 = "\n" x substr($_[0], $+[8], $+[0] - $+[8]) =~ tr/\n//;
164 106 100       281 $expr2stmt->(1) if $fix_line_num;
165             $fix_line_num = push @expr,
166 106   100     529 _parse_fltr "do{$nl1$8}$nl2", $9 // $$Plate::_s{auto_filter};
167 106 100       221 $expr2stmt->() if $pre;
168              
169             } elsif (defined $11) {
170             # <& ... &> or <&| ... &>
171 69         397 my $nl = "\n" x (substr($_[0], $+[1], $+[0] - $+[1]) =~ tr/\n// - $11 =~ tr/\n//);
172 69         151 my($tmpl, $args) = do { $11 =~ /^([\w\/\.-]+)\s*(?:,\s*(.*))?$/s };
  69         342  
173 69 100 100     286 $expr2stmt->(!$pre) if $pre or $fix_line_num;
174 69 100       127 if (defined $tmpl) {
175 58 100       168 if ($tmpl eq '_') {
176             $fix_line_num = push @expr, _parse_fltr defined $10
177 26 100       107 ? do {
    100          
178 9 100       22 $args = defined $args ? "($args)" : '';
179 9 100       26 local $_[3] = $pre ? '&&' : '&';
180 9         47 '(@Plate::_c?do{local@Plate::_c=@Plate::_c;&{splice@Plate::_c,-1,1,sub{'.&_parse."}}$args}:undef)$nl"
181             }
182             : defined $args ? "do{Plate::content($args)}$nl" : "do{&Plate::content}$nl", $12;
183 26 100 100     87 $expr2stmt->() if $pre and $nl;
184 26         237 next;
185             }
186 32 100       101 $tmpl = defined $args ? "Plate::_r('$tmpl',($args)," : "Plate::_r('$tmpl',";
187             } else {
188 11         42 $tmpl = "Plate::_r($11,";
189             }
190 43 100       228 $fix_line_num = push @expr,
    100          
191             _parse_fltr "do{$tmpl".(defined $10 ? (local $_[3] = $pre ? '&&' : '&', 'sub{'.&_parse.'}') : 'undef').")}$nl", $12;
192 43 100 100     183 $expr2stmt->() if $pre and $nl;
193              
194             } else {
195             # or or \z
196 261   100     1154 my $tag = $13 // $14 // '';
      100        
197 261 100       528 if ($tag ne $_[3]) {
198 3   100     28 my $line = 1 + join('', $stmt // '', @expr) =~ y/\n//;
199 3   100     38 $line = "$_[2] line $line.\nPlate ".($pre && 'pre').'compilation failed';
200 3 100       334 croak $tag
201             ? "Closing tag without opening <$tag...> tag at $line"
202             : "Opening <$_[3]...> tag without closing tag at $line";
203             }
204              
205             my $pl = defined $stmt
206 258 100       701 ? do {
    100          
207 84 100 100     221 $stmt .= ';push@Plate::_l,length$Plate::_b,__LINE__' if $pre and @expr;
208 84         281 $stmt.join('.', ';$Plate::_b', @expr);
209             }
210             : @expr ? join('.', @expr) : "''";
211 258 100 100     818 $pl .= '=~s/\R\z//r' if !$pre and $$Plate::_s{chomp};
212 258 100       510 $pl .= "\n" if defined $13;
213 258         1601 return $pl;
214             }
215              
216 244 100 100     2917 if (!$pre and @Plate::_l and $Plate::_l[0] <= $+[0]) {
      100        
217 5         13 my($pos, $line) = splice @Plate::_l, 0, 2;
218 5   66     40 ($pos, $line) = splice @Plate::_l, 0, 2 while @Plate::_l and $Plate::_l[0] <= $+[0];
219 5         18 my $rem = $+[0] - $pos;
220 5 100       20 $line += substr($_[0], $pos, $rem) =~ tr/\n// if $rem;
221 5         12 $expr2stmt->();
222 5         47 $stmt .= "\n#line $line\n";
223             }
224             }
225             }
226              
227             sub _read {
228 20 100   20   1116 open my $fh, '<'.$_[0]{io_layers}, $_[1]
229             or croak "Can't read $_[1]: $!";
230 16         16691 local $/;
231 16         574 scalar <$fh>;
232             }
233             sub _write {
234 8     8   56 my $umask = umask $$Plate::_s{umask};
235 8 100       661 (open(my $fh, '>:utf8', $_[0]), umask $umask)[0]
236             or croak "Can't write $_[0]: $!";
237 7         509 print $fh $_[1];
238             }
239             sub _eval {
240 222     222   25188 eval "package $$Plate::_s{package};$_[0]";
  3     3   61  
  3     1   5  
  3         95  
  1         7  
  1         2  
  1         133  
241             }
242             sub _compile {
243 116     116   725 my($pl, $file) = @_;
244 116         169 my($line, $sub);
245 116 100       228 if (length $file) {
246 46         109 $line = "\n#line 1 $_[1]\n";
247             } else {
248 70         100 $file = '-';
249 70         97 $line = '';
250             }
251 116         185 local @Plate::_l;
252             # Precompile
253 116         223 $pl = _parse $pl, $re_pre, $file, '';
254 113         326 $pl = "sub{$line$pl}";
255 113 100       202 $sub = _eval $pl
256             or croak $@.'Plate precompilation failed';
257 112 100       757 defined($pl = eval { $sub->() })
  112         1510  
258             or croak $@.'Plate precompilation failed';
259             # Compile
260 111         461 $pl = _parse $pl, $re_run, $file, '';
261 109         403 $pl = "$$Plate::_s{once}sub{$$Plate::_s{init}$line$pl}";
262 109 100       206 $sub = _eval $pl
263             or croak $@.'Plate compilation failed';
264             # Cache
265 104 100       1006 _write $_[2], "use 5.020;use warnings;use utf8;package $$Plate::_s{package};$pl" if defined $_[2];
266 103 100       235 $$Plate::_s{mod}{$_[3]} = $_[4] if defined $_[4];
267 103         589 return $sub;
268             }
269             sub _make_cache_dir {
270 11     11   31 my($dir, @mkdir) = $_[1];
271 11   100     101 unshift @mkdir, $_[0]{cache_path}.$dir until $dir !~ s|/[^/]*$|| or -d $_[0]{cache_path}.$dir;
272 11 100       49 return unless @mkdir;
273 2         14 my $umask = umask $_[0]{umask};
274 2   66     193 mkdir $_ or umask $umask, croak "Can't create cache directory $_: $!" for @mkdir;
275 1         7 umask $umask;
276 1         4 return;
277             }
278             sub _plate_file {
279 51 100   51   826 defined $_[0]{path} ? $_[0]{path}.$_[1].$_[0]{suffix} : undef;
280             }
281             sub _cache_file {
282 38 100   38   147 defined $_[0]{cache_path} ? $_[0]{cache_path}.$_[1].$_[0]{cache_suffix} : undef;
283             }
284             sub _load {
285 37     37   82 my $plate = $_[0]->_plate_file($_[1]);
286 37         74 my $cache = $_[0]->_cache_file($_[1]);
287 37         52 my $_n;
288 37 100       68 if (defined $cache) {
    100          
289 26 100       51 if ($_[0]{static}) {
290 8 50 66     527 return do $cache // croak $@ ? $@.'Plate compilation failed' : "Couldn't load $cache: $!" if -f $cache;
    100          
291 4   66     121 $plate // croak "Plate template '$_[1]' does not exist";
292             } else {
293 18   100     614 $_n = $_[2] // (stat $plate)[9] // croak "Can't read $plate: $!";
      66        
294 15 100 66     236 if (-f $cache and ($_[0]{mod}{$_[1]} // (stat _)[9]) >= $_n) {
      100        
295 7 50 66     1211 my $sub = do $cache // croak $@ ? $@.'Plate compilation failed' : "Couldn't load $cache: $!";
296 6   66     1510 $_[0]{mod}{$_[1]} //= $_n;
297 6         34 return $sub;
298             }
299             }
300 11         41 $_[0]->_make_cache_dir($_[1]);
301             } elsif (defined $plate) {
302 10 100 66     86 $_n = (stat $plate)[9] unless $_[0]{static} or exists $_[0]{mod}{$_[1]};
303             } else {
304 1         91 croak "Plate template '$_[1]' does not exist";
305             }
306 20         65 _compile $_[0]->_read($plate), $plate, $cache, $_[1], $_n;
307             }
308             sub _cached_sub {
309 170 100 100 170   943 return $_[0]{mem}{$_[1]} //= $_[0]->_load($_[1]) if $_[0]{static} or not exists $_[0]{mod}{$_[1]};
      100        
310 6 100       17 my $mod = (stat $_[0]->_plate_file($_[1]))[9]
311             or croak "Plate template '$_[1]' does not exist";
312 4 100 66     37 return $_[0]{mem}{$_[1]} //= $_[0]->_load($_[1], $mod) if $_[0]{mod}{$_[1]} == $mod;
313 1         4 $_[0]{mem}{$_[1]} = $_[0]->_load($_[1], $mod);
314             }
315             sub _sub {
316             $$Plate::_s{cache_code}
317             ? $Plate::_s->_cached_sub($_[0])
318 199 100 66 199   578 : $$Plate::_s{mem}{$_[0]} // $Plate::_s->_load($_[0]);
319             }
320              
321       3     sub _empty {}
322             sub _r {
323 161     161   1042 my $tmpl = shift;
324 161 100       305 if ($tmpl eq '_') {
325 6 100       64 return undef unless @Plate::_c;
326 3 100       8 if (defined(my $c = pop)) {
327 2         4 local @Plate::_c = @Plate::_c;
328 2         4 return &{splice @Plate::_c, -1, 1, $c};
  2         6  
329             } else {
330 1         3 $tmpl = pop @Plate::_c;
331 1         3 local @Plate::_c = @Plate::_c;
332 1         2 return &{$tmpl};
  1         21  
333             }
334             }
335 155 100       339 if (@Plate::_c >= $$Plate::_s{max_call_depth}) {
336 2         15 my($f, $l) = (caller 0)[1, 2];
337 2         110 die "Call depth limit exceeded while calling \"$tmpl\" at $f line $l.\n";
338             }
339 153         559 local @Plate::_c = @Plate::_c;
340 153   100     525 push @Plate::_c, pop // \&_empty;
341 153         261 &{_sub $tmpl};
  153         333  
342             }
343             sub _f {
344 125     125   1005 my $f = shift;
345 125   100     139 goto &{$$Plate::_s{filters}{$f} // croak "No '$f' filter defined"};
  125         868  
346             }
347              
348             sub _path {
349 21     21   606 my $path = $_[0];
350 21         51 my $vol = WINDOWS ? $path =~ s'^[\\/]{2}(?=[^\\/])'' ? '//' : $path =~ s'^([a-zA-Z]:)'' ? ucfirst $1 : '' : '';
351 21 100 66     62 length $path or return (length $vol or not $_[1]) ? $vol : './';
    100          
352 19         220 my @dir = grep $_ ne '.', split WINDOWS ? qr'[\\/]+' : qr'/+', $path.'/', -1;
353 19 100 66     135 $vol = './' if $_[1] and not length $vol and (length $dir[0] or @dir == 1);
      100        
      100        
354 19         127 $vol.join('/', @dir);
355             }
356              
357             {
358             my %esc_html = ('"' => '"', '&' => '&', "'" => ''', '<' => '<', '>' => '>');
359 7     7   64 no warnings 'uninitialized';
  7         17  
  7         13934  
360 116     116   1081 sub _basic_html_filter { $_[0] =~ s/(["&'<>])/$esc_html{$1}/egr }
  45         349  
361             }
362              
363             =head1 DESCRIPTION
364              
365             Plate is a very fast, efficient and full-featured templating engine.
366              
367             Inspired by L and L, the goal of this templating engine is speed and functionality.
368             It has no non-core dependencies, is a compact size and supports embedded Perl.
369              
370             Features include preprocessing templates,
371             caching compiled templates,
372             variable escaping/filtering,
373             localised global variables.
374             Templates can also include other templates, with optional content
375             and even define or override templates & filters locally.
376              
377             All templates have strict, warnings, utf8 and Perl 5.20 features enabled.
378              
379             =head2 Example
380              
381             Here is an example template for a letter stored in the file: C
382              
383             % my($title, $surname) = @_;
384             Dear <% $title %> <% $surname %>,
385            
386             <& _ &>
387            
388             Kind Regards,
389            
390             E. X. Ample
391              
392             Another template could I this template, Eg: C
393              
394             <&| letter, 'Dr.', 'No' &>\
395             In response to the recently advertised position, please
396             consider my résumé in your search for a professional sidekick.
397            
398              
399             Serving the C template will result in the following output:
400              
401             Dear Dr. No,
402            
403             In response to the recent advertised position, please
404             consider my résumé in your search for a professional sidekick.
405            
406             Kind Regards,
407            
408             E. X. Ample
409              
410             Here is the code to render this output:
411              
412             use Plate;
413            
414             my $plate = new Plate;
415             my $output = $plate->serve('job');
416              
417             =head2 Markup
418              
419             =head3 Variables
420              
421             <% $var %>
422             <% $unescaped |%>
423             <% $filtered |trim |html %>
424              
425             Variables are interpolated into the output and optionally filtered (escaped).
426             Filters are listed in the order to be applied preceded by a C<|> character.
427             If no filter is given as in the first example, then the default filter is applied.
428             To explicitly avoid the default filter use the empty string as a filter.
429              
430             =head3 Statements
431              
432             % my $user = db_lookup(user => 'bob');
433             % for my $var (@list) {
434              
435             Lines that start with a C<%> character are treated as Perl statements.
436              
437             =head3 Comments
438              
439             %# Comment line
440             <% # inline comment %>
441             <%#
442             Multi-line
443             comment
444             %>
445              
446             =head3 Perl blocks
447              
448             <%perl>
449             ...
450            
451              
452             Perl code can also be wrapped in a perl block.
453              
454             =head3 Newlines
455              
456             Newline characters can be escaped with a backslash, Eg:
457              
458             % for my $var ('a' .. 'c') {
459             <% $var %>\
460             % }
461              
462             This will result in the output C, all on one line.
463              
464             =head3 Include other templates
465              
466             <& header, 'My Title' &>
467             ...
468             <& footer &>
469              
470             A template can include other templates with optional arguments.
471              
472             =head3 Include other templates with provided content
473              
474             <&| paragraph &>
475             This content is passed to the "paragraph" template.
476            
477            
478             Plain text, <&| bold &>bold text, plain text.
479              
480             An included template can have its own content passed in.
481              
482             =head3 Content
483              
484             <& _ &>
485              
486             A template can be served with content. This markup will insert the content provided, if any.
487              
488             =head3 Def blocks
489              
490             <%def copyright>
491             Copyright © <% $_[0] %>
492            
493            
494             <& copyright, 2018 &>
495              
496             Local templates can be defined in a template.
497             They will override existing templates until the end of the template or block.
498              
499             =head3 Filter blocks
500              
501             <%filter one_line>
502             <% $_[0] =~ tr/\n/ / |%>
503            
504            
505             <%filter bold>
506             <& _ &>
507            
508            
509             <% "Single\nLine\nOnly" |one_line |bold %>
510              
511             Local filters can also be defined in a template.
512             They will override existing filters until the end of the template or block.
513             The text to be filtered will be passed in as the only argument and also as content.
514              
515             =head1 SUBROUTINES/METHODS
516              
517             =head2 new
518              
519             my $plate = Plate->new(%options);
520              
521             Creates a new C engine with the options provided.
522              
523             Options (with their defaults) are:
524              
525             =over
526              
527             =item C<< auto_filter => 'html' >>
528              
529             The name of the default filter to use for template variables when no filter is specified, S >>>.
530             The built-in default filter is a very basic HTML filter.
531             Set this to C to disable the default filter.
532              
533             To prevent the default filter being used for just a single variable,
534             just set the filter to an empty string. Eg: S >>>
535              
536             =item C<< cache_code => 1 >>
537              
538             If set to a true value, the engine will cache compiled template code in memory.
539             This vastly improves performance at the expense of some memory.
540              
541             =item C<< cache_path => undef >>
542              
543             Set this to a directory to store compiled templates on the filesystem.
544             If the directory does not exist, it will attempt to create it using the C setting.
545              
546             =item C<< cache_suffix => '.pl' >>
547              
548             Compiled templates stored on the filesystem will have this suffix appended.
549              
550             =item C<< chomp => 1 >>
551              
552             If set to a true value (the default),
553             the final newline in every template will be removed.
554              
555             =item C<< encoding => 'UTF-8' >>
556              
557             Set this to the encoding of your template files.
558              
559             =item C<< filters => { html => \&_basic_html_filter } >>
560              
561             A hash of filters to set for use in templates.
562             The key is the name of the filter, and the value is the CODE ref, subroutine name or C.
563             The subroutine will be given one argument (the content to filter) as a string,
564             and must return the filtered string.
565             To remove a filter pass C as it's value.
566              
567             To remove all filters pass C instead of a HASH ref.
568              
569             =item C<< keep_undef => undef >>
570              
571             If set to a false value (the default),
572             then variables and calls that return C are converted to an empty string.
573              
574             =item C<< max_call_depth => 99 >>
575              
576             This sets the maximum call depth to prevent infinite recursion.
577              
578             =item C<< package => 'Plate::Template' >>
579              
580             The package name that templates are compiled and run in.
581              
582             =item C<< path => '' >>
583              
584             The path to the templates on the filesystem.
585             An empty string (the default) refers to the current directory.
586             If set to C then the filesystem will not be searched,
587             only cached templates will be served.
588              
589             =item C<< static => undef >>
590              
591             If set to a false value (the default),
592             the engine will reload and recompile templates whenever files are modified.
593              
594             If set to a true value,
595             file modification will not be checked nor will templates be reloaded.
596             While this improves performance in production, it is not recommended in development.
597              
598             =item C<< suffix => '.plate' >>
599              
600             The suffix appended to template names when searching on the filesystem.
601              
602             =item C<< umask => 077 >>
603              
604             The C used when creating cache files and directories.
605              
606             =item C<< vars => {} >>
607              
608             A hash of vars to set for use in templates.
609             This will define new local variables to be imported into the templating package when compiling and running templates.
610             Values to be imported must be unblessed references.
611             If the value is a blessed object or not a reference it will be imported as a constant into the templating package.
612             To remove a var pass C as it's value.
613              
614             To remove all vars pass C instead of a HASH ref.
615              
616             All templates will have access to these variables, subroutines and constants even under C.
617              
618             =back
619              
620             =cut
621              
622             sub new {
623 20     20 1 9227 my $class = shift;
624 20         270 my $self = bless {
625             auto_filter => 'html',
626             cache_code => 1,
627             cache_path => undef,
628             cache_suffix => '.pl',
629             chomp => 1,
630             filters => {
631             html => \&_basic_html_filter,
632             },
633             init => '',
634             io_layers => ':encoding(UTF-8)',
635             keep_undef => undef,
636             max_call_depth => 99,
637             mem => {},
638             once => '',
639             package => 'Plate::Template',
640             path => '',
641             static => undef,
642             suffix => '.plate',
643             umask => 077,
644             vars => {},
645             }, $class;
646 20 100       109 $self->set(@_) if @_;
647 13         151 $self;
648             }
649              
650             =head2 serve
651              
652             my $output = $plate->serve($template_name, @arguments);
653              
654             Renders a template.
655             The C<@arguments> will be passed to the template as C<@_>.
656              
657             =head2 serve_with
658              
659             my $output = $plate->serve_with($content, $template_name, @arguments);
660              
661             Renders a template with the provided content.
662              
663             The content can be passed in one of three ways.
664             If C<$content> is a string then it is the name of a template to serve.
665             If C<$content> is a SCALAR ref then it is the contents of a template to be compiled and served.
666             C<$content> may also be a CODE ref which should return the content directly.
667              
668             =cut
669              
670 96     96 1 15048 sub serve { shift->serve_with(undef, @_) }
671             sub serve_with {
672 102     102 1 194 local $Plate::_s = shift;
673 102   100     454 my($_c, $tmpl) = (shift // \&_empty, shift);
674 102         636 _local_vars $$Plate::_s{package}, $$Plate::_s{vars};
675 102 100       422 local @Plate::_c = ref $_c eq 'CODE' ? $_c : ref $_c eq 'SCALAR' ? _compile $$_c : _sub $_c;
    100          
676              
677 102 100       305 my $sub = ref $tmpl eq 'SCALAR'
678             ? _compile $$tmpl
679             : _sub $tmpl;
680 87         1580 &$sub;
681             }
682              
683             =head2 content
684              
685             % my $content = &Plate::content;
686              
687             Used from within a template to return the content passed to that template.
688              
689             =head2 has_content
690              
691             % if (Plate::has_content) { ...
692              
693             Used from within a template to determine if that template was called with content.
694              
695             =cut
696              
697             sub content {
698 52 100   52 1 403 @Plate::_c ? do { local @Plate::_c = @Plate::_c; &{pop @Plate::_c} } : undef;
  51         102  
  51         68  
  51         169  
699             }
700             sub has_content {
701 4 100   4 1 57 @Plate::_c and $Plate::_c[-1] != \&_empty;
702             }
703              
704             =head2 define
705              
706             $plate->define($template_name => $content);
707              
708             This will cache a template in memory.
709             The C<$content> is the contents of a template (as a string) to be compiled or a CODE ref.
710              
711             This is useful if you need to use templates that are not stored on the file system,
712             for example from a database or a custom subroutine.
713              
714             =head2 undefine
715              
716             $plate->undefine;
717             $plate->undefine($template_name);
718              
719             This will delete a previously cached template,
720             or all templates if the name is C.
721              
722             =cut
723              
724             sub define {
725 31 100   31 1 24359 delete $_[0]{mod}{$_[1]} if $_[0]{mod};
726 31 100       93 $_[0]{mem}{$_[1]} = ref $_[2] eq 'CODE' ? $_[2] : do {
727 30         76 local($Plate::_s, @Plate::_c) = $_[0];
728 30         181 _local_vars $$Plate::_s{package}, $$Plate::_s{vars};
729 30         85 _compile $_[2], $_[1];
730             };
731             }
732             sub undefine {
733 3 100   3 1 1884 if (defined $_[1]) {
734 2         6 delete $_[0]{mod}{$_[1]};
735 2         19 delete $_[0]{mem}{$_[1]};
736             } else {
737 1         5 delete $_[0]{mod};
738 1         3 undef %{$_[0]{mem}};
  1         6  
739             }
740             }
741              
742             =head2 does_exist
743              
744             my $exists = $plate->does_exist($template_name);
745              
746             Returns true if a template by that name is cached or exists on the filesystem.
747             No attempt will be made to compile the template.
748              
749             =head2 can_serve
750              
751             my $ok = $plate->can_serve($template);
752              
753             Returns true if the template can be served (compiles successfully),
754             otherwise it sets C<$@> to the reason for failure.
755             If C<$template> is a string then it is the name of a template to compile.
756             If C<$template> is a SCALAR ref then it is the contents of a template to be compiled.
757              
758             =cut
759              
760             sub does_exist {
761 9 100 100 9 1 2016 $_[0]{cache_code} and not $_[0]{static} and exists $_[0]{mod}{$_[1]}
      100        
762             and return -f $_[0]->_plate_file($_[1]);
763              
764 7 100 66     33 exists $_[0]{mem}{$_[1]} or -f($_[0]->_plate_file($_[1]) // $_[0]->_cache_file($_[1]));
765             }
766             sub can_serve {
767 8     8 1 30 local($Plate::_s, @Plate::_c) = $_[0];
768 8         84 _local_vars $$Plate::_s{package}, $$Plate::_s{vars};
769 8 100       18 !!eval { ref $_[1] eq 'SCALAR' ? _compile ${$_[1]} : _sub $_[1] };
  8         42  
  1         4  
770             }
771              
772             =head2 set
773              
774             $plate->set(%options);
775              
776             Set the options for this C engine.
777             Options are the same as those for L.
778              
779             =cut
780              
781             my %sigil = (
782             ARRAY => '@',
783             CODE => '&',
784             GLOB => '*',
785             HASH => '%',
786             );
787              
788 2     2   12 eval "sub _set_$_ { \$_[0]{$_} = \$_[1] }" for qw(auto_filter cache_code chomp keep_undef max_call_depth static umask);
  7     7   57  
  2     2   12  
  3     3   28  
  1     1   6  
  2     2   12  
  3     3   16  
789 1   50 1   8 eval "sub _set_$_ { \$_[0]{$_} = \$_[1] // '' }" for qw(cache_suffix init io_layers once suffix);
  2   100 2   13  
  5   50 5   39  
  2   100 2   15  
  1   50 1   10  
790             sub _set_cache_path {
791             # A relative cache_path must start with "./" to prevent searching @INC when sourcing the file
792 11 100   11   50 $_[0]{cache_path} = defined $_[1] ? _path $_[1], 1 : $_[1];
793             }
794             sub _set_encoding {
795 4 100   4   115 $_[0]->_set_io_layers(length $_[1] ? $_[1] eq 'utf8' ? ':utf8' : ":encoding($_[1])" : '');
    100          
796             }
797             sub _set_filters {
798 9   100 9   30 $_[1] // return undef %{$_[0]{filters}};
  1         11  
799 8 100       143 ref $_[1] eq 'HASH'
800             or croak "Invalid filters (not a hash reference)";
801              
802 7         21 while (my($name, $code) = each %{$_[1]}) {
  13         69  
803 8 100       125 $name =~ /^\w+$/
804             or croak "Invalid filter name '$name'";
805 7 100       20 if (defined $code) {
806             ref $code eq 'CODE'
807             or $code = ($code =~ /(.*)::(.*)/
808             ? $1->can($2)
809 5 100 100     135 : do {
    100          
810 1         3 my($i,$p) = 0;
811 1         7 $i++ while __PACKAGE__ eq ($p = caller $i);
812 1         15 $p->can($code)
813             })
814             or croak "Invalid subroutine '$_[1]{$name}' for filter '$name'";
815 4         13 $_[0]{filters}{$name} = $code;
816             } else {
817 2         6 delete $_[0]{filters}{$name};
818             }
819             }
820             }
821             sub _set_path {
822 15 100   15   67 $_[0]{path} = length $_[1] ? _path $_[1] : $_[1];
823             }
824             sub _set_package {
825 3 100 100 3   240 defined $_[1] and $_[1] =~ /^[A-Z_a-z][0-9A-Z_a-z]*(?:::[0-9A-Z_a-z]+)*$/
      100        
826             or croak "Invalid package name '".($_[1] // '')."'";
827 1         7 $_[0]{package} = $_[1];
828             }
829             sub _set_vars {
830 5   100 5   22 $_[1] // return undef %{$_[0]{vars}};
  1         11  
831 4 100       169 ref $_[1] eq 'HASH'
832             or croak "Invalid vars (not a hash reference)";
833              
834 3         5 while (my($name, $ref) = each %{$_[1]}) {
  11         44  
835 8 100       15 if (defined $ref) {
836 7   100     35 my $sigil = $sigil{Scalar::Util::reftype $ref // 'CODE'} // '$';
      100        
837 7 100       75 $name =~ s/^\Q$sigil\E?/$sigil ne '&' && $sigil/e;
  7         29  
838 7         25 $_[0]{vars}{$name} = $ref;
839             } else {
840 1         4 delete $_[0]{vars}{$name};
841             }
842             }
843             }
844              
845             sub set {
846 54     54 1 12446 my($self, %opt) = @_;
847              
848 54         257 while (my($k, $v) = each %opt) {
849 76 100       661 my $c = $self->can("_set_$k")
850             or croak "Invalid setting '$k'";
851 75         790 $c->($self, $v);
852             }
853              
854 47 100       140 if (defined $$self{path}) {
855 43         92 undef $!;
856 43 100       114 my $dir = length $$self{path} ? $$self{path} : '.';
857 43 100 50     1046 -d $dir and -r _ or croak "Can't set path to $dir: ".($! || 'Not accessable');
      66        
858 42 100 100     207 undef $$self{static} if $$self{static} and $$self{static} eq 'auto';
859             } else {
860 4   100     16 $$self{static} ||= 'auto';
861             }
862              
863 46 100       191 if (defined $$self{cache_path}) {
    100          
864 16         32 my $dir = $$self{cache_path};
865 16 100       675 if (-d $dir) {
866 11 50       90 -w _ or croak "Cache directory $dir is not writeable";
867             } else {
868 5         39 my $umask = umask $$self{umask};
869 5 100       491 (mkdir($dir), umask $umask)[0]
870             or croak "Can't create cache directory $dir: $!";
871             }
872             } elsif (not $$self{cache_code}) {
873 9   100     57 $$self{static} ||= 'auto';
874             }
875             }
876              
877             =head1 AUTHOR
878              
879             Vernon Lyon C<< >>
880              
881             =head1 BUGS
882              
883             Please report any bugs or feature requests on L.
884              
885             =head1 SOURCE
886              
887             The source code is hosted on L.
888             Feel free to fork the repository and submit pull requests!
889              
890             =head1 SUPPORT
891              
892             You can find documentation for this module with the perldoc command.
893              
894             perldoc Plate
895              
896             You can also read the documentation online on L.
897              
898             =head1 COPYRIGHT AND LICENSE
899              
900             Copyright (C) 2018, Vernon Lyon.
901              
902             This library is free software; you can redistribute it and/or modify
903             it under the same terms as Perl itself.
904              
905             =cut
906              
907             1;