File Coverage

blib/lib/Plate.pm
Criterion Covered Total %
statement 294 294 100.0
branch 257 260 98.8
condition 135 152 88.8
subroutine 42 42 100.0
pod 10 10 100.0
total 738 758 97.3


line stmt bran cond sub pod time code
1 7     7   424495 use 5.020;
  7         78  
2 7     7   38 use warnings;
  7         11  
  7         307  
3             package Plate 1.4;
4              
5 7     7   41 use Carp 'croak';
  7         13  
  7         347  
6 7     7   55 use File::Spec;
  7         11  
  7         202  
7 7     7   46 use Scalar::Util;
  7         37  
  7         281  
8 7     7   42 use XSLoader;
  7         10  
  7         262  
9              
10 7     7   50 use constant WINDOWS => $^O eq 'MSWin32';
  7         13  
  7         758  
11              
12             BEGIN {
13 7     7   31889 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\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\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 318     318   558 my $text = $_[0];
64 318 100       823 $_[2] = $text =~ s/\\\R//g unless $_[1];
65 318         1099 $text =~ s/(\\|')/\\$1/g;
66 318 100       1071 length $text ? "'$text'" : ();
67             }
68             sub _parse_cmnt {
69 75     75   138 my $cmnt = $_[0];
70 75 100       261 $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 7     7   14 my $defn = $_[0];
80 7 100       56 $defn =~ /\W/ ? "'".($defn =~ s/(\\|')/\\$1/gr)."'" : $defn;
81             }
82             sub _parse_fltr {
83 168     168   272 my $expr = $_[0];
84 168 100       511 $expr .= "//''" unless $$Plate::_s{keep_undef};
85 168 100       428 if (length $_[1]) {
    100          
86 77         294 for (split /\s*\|\s*/, $_[1]) {
87 81 100       574 exists $$Plate::_s{filters}{$_} or croak "No '$_' filter defined";
88 78         213 $expr = "Plate::_f($_=>$expr)";
89             }
90             } elsif (not $$Plate::_s{keep_undef}) {
91 84         161 $expr = "($expr)";
92             }
93 165         351 $expr;
94             }
95             sub _parse {
96 258     258   420 my @expr;
97             my $stmt;
98 258         507 my $pre = $_[1] == $re_pre;
99 258         373 my $fix_line_num;
100             my $expr2stmt = sub {
101 188 100   188   321 if (@expr) {
102 121 100       202 if (defined $stmt) {
103 81 100       149 $stmt .= ';push@Plate::_l,length$Plate::_b,__LINE__' if $pre;
104 81         127 $stmt .= ';$Plate::_b.=';
105             } else {
106 40         61 $stmt = 'local$Plate::_b=';
107             }
108 121 100       403 $stmt .= join('.', $_[0] ? splice @expr, 0, $fix_line_num : splice @expr).';';
109             } else {
110 67   100     197 $stmt //= q"local$Plate::_b='';";
111             }
112 188 100       443 undef $fix_line_num unless $_[0];
113 258         987 };
114 258         3397 while ($_[0] =~ /$_[1]/g) {
115              
116 514 100       1569 if (length $1) {
117 318         610 push @expr, _parse_text $1, $pre, my $add_lines;
118 318 100       653 (@expr ? $expr[-1] : defined $stmt ? $stmt : ($expr[0] = "''")) .= "\n" x $add_lines if $add_lines;
    100          
    100          
119 318 100       646 $fix_line_num = @expr if $fix_line_num;
120             }
121              
122 514 100 100     1623 if (!$pre and @Plate::_l and $Plate::_l[0] <= $+[1]) {
      100        
123 24         75 my($pos, $line) = splice @Plate::_l, 0, 2;
124 24   100     137 ($pos, $line) = splice @Plate::_l, 0, 2 while @Plate::_l and $Plate::_l[0] <= $+[1];
125 24         65 my $rem = $+[1] - $pos;
126 24 100       77 $line += substr($_[0], $pos, $rem) =~ tr/\n// if $rem;
127 24         58 $expr2stmt->();
128 24         52 $stmt .= "\n#line $line\n";
129             }
130              
131 514 100       2072 if (defined $2) {
    100          
    100          
    100          
    100          
    100          
132             # % ...
133 75         146 $expr2stmt->();
134 75         136 $stmt .= _parse_cmnt $2;
135 75         156 $stmt .= "\n";
136              
137             } elsif (defined $3) {
138             # <%perl>
139 8         17 $expr2stmt->();
140 8 100       19 unless (defined $4) {
141 2         6 my $line = 1 + $stmt =~ y/\n//;
142 2   100     12 $line = "$_[2] line $line.\nPlate ".($pre && 'pre').'compilation failed';
143 2   100     9 my $tag = ($pre && '%').'%'.$3;
144 2         197 croak "Opening <$tag...> tag without closing tag at $line";
145             }
146 6         15 $stmt .= "\n$4\n";
147              
148             } elsif (defined $5) {
149             # <%def ...>
150 7         17 $expr2stmt->();
151 7   100     38 local $_[3] = ($pre && '%').'%def';
152 7         22 $stmt .= 'local$$Plate::_s{mem}{'._parse_defn($5)."}=\nsub{".&_parse.'};';
153              
154             } elsif (defined $6) {
155             # <%# ... %>
156 4         10 my $add_lines = $6 =~ 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       10 $fix_line_num = @expr if $fix_line_num;
159              
160             } elsif (defined $7) {
161             # <% ... %>
162 100         500 my $nl1 = "\n" x substr($_[0], $+[1], $-[7] - $+[1]) =~ tr/\n//;
163 100         390 my $nl2 = "\n" x substr($_[0], $+[7], $+[0] - $+[7]) =~ tr/\n//;
164 100 100       289 $expr2stmt->(1) if $fix_line_num;
165             $fix_line_num = push @expr,
166 100   100     968 _parse_fltr "do{$nl1$7}$nl2", $8 // $$Plate::_s{auto_filter};
167 98 100       231 $expr2stmt->() if $pre;
168              
169             } elsif (defined $10) {
170             # <& ... &> or <&| ... &>
171 68         379 my $nl = "\n" x (substr($_[0], $+[1], $+[0] - $+[1]) =~ tr/\n// - $10 =~ tr/\n//);
172 68         142 my($tmpl, $args) = do { $10 =~ /^([\w\/\.-]+)\s*(?:,\s*(.*))?$/s };
  68         394  
173 68 100 100     284 $expr2stmt->(!$pre) if $pre or $fix_line_num;
174 68 100       126 if (defined $tmpl) {
175 57 100       125 if ($tmpl eq '_') {
176             $fix_line_num = push @expr, _parse_fltr defined $9
177 25 100       112 ? do {
    100          
178 9 100       26 $args = defined $args ? "($args)" : '';
179 9 100       27 local $_[3] = $pre ? '&&' : '&';
180 9         40 '(@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", $11;
183 25 100 100     79 $expr2stmt->() if $pre and $nl;
184 25         212 next;
185             }
186 32 100       112 $tmpl = defined $args ? "Plate::_r('$tmpl',($args)," : "Plate::_r('$tmpl',";
187             } else {
188 11         33 $tmpl = "Plate::_r($10,";
189             }
190 43 100       257 $fix_line_num = push @expr,
    100          
191             _parse_fltr "do{$tmpl".(defined $9 ? (local $_[3] = $pre ? '&&' : '&', 'sub{'.&_parse.'}') : 'undef').")}$nl", $11;
192 42 100 100     135 $expr2stmt->() if $pre and $nl;
193              
194             } else {
195             # or or \z
196 252   100     1358 my $tag = $12 // $13 // '';
      100        
197 252 100       534 if ($tag ne $_[3]) {
198 3   100     22 my $line = 1 + join('', $stmt // '', @expr) =~ y/\n//;
199 3   100     23 $line = "$_[2] line $line.\nPlate ".($pre && 'pre').'compilation failed';
200 3 100       348 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 249 100       666 ? do {
    100          
207 81 100 100     219 $stmt .= ';push@Plate::_l,length$Plate::_b,__LINE__' if $pre and @expr;
208 81         297 $stmt.join('.', ';$Plate::_b', @expr);
209             }
210             : @expr ? join('.', @expr) : "''";
211 249 100 100     756 $pl .= '=~s/\R\z//r' if !$pre and $$Plate::_s{chomp};
212 249 100       488 $pl .= "\n" if defined $12;
213 249         1624 return $pl;
214             }
215              
216 231 100 100     2319 if (!$pre and @Plate::_l and $Plate::_l[0] <= $+[0]) {
      100        
217 5         14 my($pos, $line) = splice @Plate::_l, 0, 2;
218 5   66     35 ($pos, $line) = splice @Plate::_l, 0, 2 while @Plate::_l and $Plate::_l[0] <= $+[0];
219 5         13 my $rem = $+[0] - $pos;
220 5 100       27 $line += substr($_[0], $pos, $rem) =~ tr/\n// if $rem;
221 5         14 $expr2stmt->();
222 5         42 $stmt .= "\n#line $line\n";
223             }
224             }
225             }
226              
227             sub _read {
228 20 100   20   1074 open my $fh, '<'.$_[0]{io_layers}, $_[1]
229             or croak "Can't read $_[1]: $!";
230 16         23053 local $/;
231 16         593 scalar <$fh>;
232             }
233             sub _write {
234 8     8   60 my $umask = umask $$Plate::_s{umask};
235 8 100       637 (open(my $fh, '>:utf8', $_[0]), umask $umask)[0]
236             or croak "Can't write $_[0]: $!";
237 7         451 print $fh $_[1];
238             }
239             sub _eval {
240 215     215   25345 eval "package $$Plate::_s{package};$_[0]";
  3     3   44  
  3     1   7  
  3         107  
  1         7  
  1         2  
  1         126  
241             }
242             sub _compile {
243 114     114   727 my($pl, $file) = @_;
244 114         154 my($line, $sub);
245 114 100       223 if (length $file) {
246 46         113 $line = "\n#line 1 $_[1]\n";
247             } else {
248 68         100 $file = '-';
249 68         95 $line = '';
250             }
251 114         300 local @Plate::_l;
252             # Precompile
253 114         282 $pl = _parse $pl, $re_pre, $file, '';
254 111         333 $pl = "sub{$line$pl}";
255 111 100       240 $sub = _eval $pl
256             or croak $@.'Plate precompilation failed';
257 110 100       771 defined($pl = eval { $sub->() })
  110         1518  
258             or croak $@.'Plate precompilation failed';
259             # Compile
260 109         451 $pl = _parse $pl, $re_run, $file, '';
261 104         373 $pl = "$$Plate::_s{once}sub{$$Plate::_s{init}$line$pl}";
262 104 100       223 $sub = _eval $pl
263             or croak $@.'Plate compilation failed';
264             # Cache
265 99 100       995 _write $_[2], "use 5.020;use warnings;use utf8;package $$Plate::_s{package};$pl" if defined $_[2];
266 98 100       230 $$Plate::_s{mod}{$_[3]} = $_[4] if defined $_[4];
267 98         648 return $sub;
268             }
269             sub _make_cache_dir {
270 11     11   27 my($dir, @mkdir) = $_[1];
271 11   100     113 unshift @mkdir, $_[0]{cache_path}.$dir until $dir !~ s|/[^/]*$|| or -d $_[0]{cache_path}.$dir;
272 11 100       37 return unless @mkdir;
273 2         13 my $umask = umask $_[0]{umask};
274 2   66     207 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 49 100   49   577 defined $_[0]{path} ? $_[0]{path}.$_[1].$_[0]{suffix} : undef;
280             }
281             sub _cache_file {
282 38 100   38   124 defined $_[0]{cache_path} ? $_[0]{cache_path}.$_[1].$_[0]{cache_suffix} : undef;
283             }
284             sub _load {
285 37     37   96 my $plate = $_[0]->_plate_file($_[1]);
286 37         83 my $cache = $_[0]->_cache_file($_[1]);
287 37         57 my $_n;
288 37 100       71 if (defined $cache) {
    100          
289 26 100       48 if ($_[0]{static}) {
290 8 50 66     541 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     747 $_n = $_[2] // (stat $plate)[9] // croak "Can't read $plate: $!";
      66        
294 15 100 66     261 if (-f $cache and ($_[0]{mod}{$_[1]} // (stat _)[9]) >= $_n) {
      100        
295 7 50 66     1224 my $sub = do $cache // croak $@ ? $@.'Plate compilation failed' : "Couldn't load $cache: $!";
296 6   66     1539 $_[0]{mod}{$_[1]} //= $_n;
297 6         36 return $sub;
298             }
299             }
300 11         39 $_[0]->_make_cache_dir($_[1]);
301             } elsif (defined $plate) {
302 10 100 66     102 $_n = (stat $plate)[9] unless $_[0]{static} or exists $_[0]{mod}{$_[1]};
303             } else {
304 1         95 croak "Plate template '$_[1]' does not exist";
305             }
306 20         68 _compile $_[0]->_read($plate), $plate, $cache, $_[1], $_n;
307             }
308             sub _cached_sub {
309 151 100 100 151   903 return $_[0]{mem}{$_[1]} //= $_[0]->_load($_[1]) if $_[0]{static} or not exists $_[0]{mod}{$_[1]};
      100        
310 5 100       14 my $mod = (stat $_[0]->_plate_file($_[1]))[9]
311             or croak "Plate template '$_[1]' does not exist";
312 4 100 66     31 return $_[0]{mem}{$_[1]} //= $_[0]->_load($_[1], $mod) if $_[0]{mod}{$_[1]} == $mod;
313 1         5 $_[0]{mem}{$_[1]} = $_[0]->_load($_[1], $mod);
314             }
315             sub _sub {
316             $$Plate::_s{cache_code}
317             ? $Plate::_s->_cached_sub($_[0])
318 180 100 66 180   554 : $$Plate::_s{mem}{$_[0]} // $Plate::_s->_load($_[0]);
319             }
320              
321       3     sub _empty {}
322             sub _r {
323 144     144   964 my $tmpl = shift;
324 144 100       280 if ($tmpl eq '_') {
325 6 100       61 return undef unless @Plate::_c;
326 3 100       9 if (defined(my $c = pop)) {
327 2         6 local @Plate::_c = @Plate::_c;
328 2         3 return &{splice @Plate::_c, -1, 1, $c};
  2         7  
329             } else {
330 1         4 $tmpl = pop @Plate::_c;
331 1         3 local @Plate::_c = @Plate::_c;
332 1         1 return &{$tmpl};
  1         22  
333             }
334             }
335 138 100       282 if (@Plate::_c >= $$Plate::_s{max_call_depth}) {
336 1         10 my($f, $l) = (caller 0)[1, 2];
337 1         100 die "Call depth limit exceeded while calling \"$tmpl\" at $f line $l.\n";
338             }
339 137         570 local @Plate::_c = @Plate::_c;
340 137   100     460 push @Plate::_c, pop // \&_empty;
341 137         218 &{_sub $tmpl};
  137         296  
342             }
343             sub _f {
344 120     120   988 my $f = shift;
345 120   66     148 goto &{$$Plate::_s{filters}{$f} // croak "No '$f' filter defined"};
  120         527  
346             }
347              
348             sub _path {
349 21     21   504 my $path = $_[0];
350 21         28 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         280 my @dir = grep $_ ne '.', split WINDOWS ? qr'[\\/]+' : qr'/+', $path.'/', -1;
353 19 100 66     125 $vol = './' if $_[1] and not length $vol and (length $dir[0] or @dir == 1);
      100        
      100        
354 19         83 $vol.join('/', @dir);
355             }
356              
357             {
358             my %esc_html = ('"' => '"', '&' => '&', "'" => ''', '<' => '<', '>' => '>');
359 7     7   105 no warnings 'uninitialized';
  7         17  
  7         12558  
360 115     115   985 sub _basic_html_filter { $_[0] =~ s/(["&'<>])/$esc_html{$1}/egr }
  45         344  
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 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 Content
465              
466             <& _ &>
467              
468             A template can be served with content. This markup will insert the content provided, if any.
469              
470             =head3 Include other templates
471              
472             <& header, 'My Title' &>
473             ...
474             <& footer &>
475              
476             A template can include other templates with optional arguments.
477              
478             =head3 Include other templates with provided content
479              
480             <&| paragraph &>
481             This content is passed to the "paragraph" template.
482            
483            
484             Plain text, <&| bold &>bold text, plain text.
485              
486             An included template can have its own content passed in.
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 can even override existing templates.
498              
499             =head1 SUBROUTINES/METHODS
500              
501             =head2 new
502              
503             my $plate = Plate->new(%options);
504              
505             Creates a new C engine with the options provided.
506              
507             Options (with their defaults) are:
508              
509             =over
510              
511             =item C<< auto_filter => 'html' >>
512              
513             The name of the default filter to use for template variables when no filter is specified, S >>>.
514             The built-in default filter is a very basic HTML filter.
515             Set this to C to disable the default filter.
516              
517             To prevent the default filter being used for just a single variable,
518             just set the filter to an empty string. Eg: S >>>
519              
520             =item C<< cache_code => 1 >>
521              
522             If set to a true value, the engine will cache compiled template code in memory.
523             This vastly improves performance at the expense of some memory.
524              
525             =item C<< cache_path => undef >>
526              
527             Set this to a directory to store compiled templates on the filesystem.
528             If the directory does not exist, it will attempt to create it using the C setting.
529              
530             =item C<< cache_suffix => '.pl' >>
531              
532             Compiled templates stored on the filesystem will have this suffix appended.
533              
534             =item C<< chomp => 1 >>
535              
536             If set to a true value (the default),
537             the final newline in every template will be removed.
538              
539             =item C<< encoding => 'UTF-8' >>
540              
541             Set this to the encoding of your template files.
542              
543             =item C<< filters => { html => \&_basic_html_filter } >>
544              
545             A hash of filters to set for use in templates.
546             The key is the name of the filter, and the value is the CODE ref, subroutine name or C.
547             The subroutine will be given one argument (the content to filter) as a string,
548             and must return the filtered string.
549             To remove a filter pass C as it's value.
550              
551             To remove all filters pass C instead of a HASH ref.
552              
553             =item C<< keep_undef => undef >>
554              
555             If set to a false value (the default),
556             then variables and calls that return C are converted to an empty string.
557              
558             =item C<< max_call_depth => 99 >>
559              
560             This sets the maximum call depth to prevent infinite recursion.
561              
562             =item C<< package => 'Plate::Template' >>
563              
564             The package name that templates are compiled and run in.
565              
566             =item C<< path => '' >>
567              
568             The path to the templates on the filesystem.
569             An empty string (the default) refers to the current directory.
570             If set to C then the filesystem will not be searched,
571             only cached templates will be served.
572              
573             =item C<< static => undef >>
574              
575             If set to a false value (the default),
576             the engine will reload and recompile templates whenever files are modified.
577              
578             If set to a true value,
579             file modification will not be checked nor will templates be reloaded.
580             While this improves performance in production, it is not recommended in development.
581              
582             =item C<< suffix => '.plate' >>
583              
584             The suffix appended to template names when searching on the filesystem.
585              
586             =item C<< umask => 077 >>
587              
588             The C used when creating cache files and directories.
589              
590             =item C<< vars => {} >>
591              
592             A hash of vars to set for use in templates.
593             This will define new local variables to be imported into the templating package when compiling and running templates.
594             If the value is not a reference it will be a constant in the templating package.
595             To remove a var pass C as it's value.
596              
597             To remove all vars pass C instead of a HASH ref.
598              
599             All templates will have access to these variables, subroutines and constants even under C.
600              
601             =back
602              
603             =cut
604              
605             sub new {
606 19     19 1 7457 my $class = shift;
607 19         275 my $self = bless {
608             auto_filter => 'html',
609             cache_code => 1,
610             cache_path => undef,
611             cache_suffix => '.pl',
612             chomp => 1,
613             filters => {
614             html => \&_basic_html_filter,
615             },
616             init => '',
617             io_layers => ':encoding(UTF-8)',
618             keep_undef => undef,
619             max_call_depth => 99,
620             mem => {},
621             once => '',
622             package => 'Plate::Template',
623             path => '',
624             static => undef,
625             suffix => '.plate',
626             umask => 077,
627             vars => {},
628             }, $class;
629 19 100       107 $self->set(@_) if @_;
630 12         161 $self;
631             }
632              
633             =head2 serve
634              
635             my $output = $plate->serve($template_name, @arguments);
636              
637             Renders a template.
638             The C<@arguments> will be passed to the template as C<@_>.
639              
640             =head2 serve_with
641              
642             my $output = $plate->serve_with($content, $template_name, @arguments);
643              
644             Renders a template with the provided content.
645              
646             The content can be passed in one of three ways.
647             If C<$content> is a string then it is the name of a template to serve.
648             If C<$content> is a SCALAR ref then it is the contents of a template to be compiled and served.
649             C<$content> may also be a CODE ref which should return the content directly.
650              
651             =cut
652              
653 92     92 1 14798 sub serve { shift->serve_with(undef, @_) }
654             sub serve_with {
655 98     98 1 197 local $Plate::_s = shift;
656 98   100     516 my($_c, $tmpl) = (shift // \&_empty, shift);
657 98         622 _local_vars $$Plate::_s{package}, $$Plate::_s{vars};
658 98 100       469 local @Plate::_c = ref $_c eq 'CODE' ? $_c : ref $_c eq 'SCALAR' ? _compile $$_c : _sub $_c;
    100          
659              
660 98 100       343 my $sub = ref $tmpl eq 'SCALAR'
661             ? _compile $$tmpl
662             : _sub $tmpl;
663 81         1413 &$sub;
664             }
665              
666             =head2 content
667              
668             % my $content = &Plate::content;
669              
670             Used from within a template to return the content passed to that template.
671              
672             =head2 has_content
673              
674             % if (Plate::has_content) { ...
675              
676             Used from within a template to determine if that template was called with content.
677              
678             =cut
679              
680             sub content {
681 51 100   51 1 403 @Plate::_c ? do { local @Plate::_c = @Plate::_c; &{pop @Plate::_c} } : undef;
  50         91  
  50         67  
  50         151  
682             }
683             sub has_content {
684 4 100   4 1 68 @Plate::_c and $Plate::_c[-1] != \&_empty;
685             }
686              
687             =head2 define
688              
689             $plate->define($template_name => $content);
690              
691             This will cache a template in memory.
692             The C<$content> is the contents of a template (as a string) to be compiled or a CODE ref.
693              
694             This is useful if you need to use templates that are not stored on the file system,
695             for example from a database or a custom subroutine.
696              
697             =head2 undefine
698              
699             $plate->undefine;
700             $plate->undefine($template_name);
701              
702             This will delete a previously cached template,
703             or all templates if the name is C.
704              
705             =cut
706              
707             sub define {
708 31 100   31 1 26302 delete $_[0]{mod}{$_[1]} if $_[0]{mod};
709 31 100       106 $_[0]{mem}{$_[1]} = ref $_[2] eq 'CODE' ? $_[2] : do {
710 30         105 local($Plate::_s, @Plate::_c) = $_[0];
711 30         188 _local_vars $$Plate::_s{package}, $$Plate::_s{vars};
712 30         96 _compile $_[2], $_[1];
713             };
714             }
715             sub undefine {
716 3 100   3 1 1813 if (defined $_[1]) {
717 2         7 delete $_[0]{mod}{$_[1]};
718 2         15 delete $_[0]{mem}{$_[1]};
719             } else {
720 1         5 delete $_[0]{mod};
721 1         2 undef %{$_[0]{mem}};
  1         6  
722             }
723             }
724              
725             =head2 does_exist
726              
727             my $exists = $plate->does_exist($template_name);
728              
729             Returns true if a template by that name is cached or exists on the filesystem.
730             No attempt will be made to compile the template.
731              
732             =head2 can_serve
733              
734             my $ok = $plate->can_serve($template);
735              
736             Returns true if the template can be served (compiles successfully),
737             otherwise it sets C<$@> to the reason for failure.
738             If C<$template> is a string then it is the name of a template to compile.
739             If C<$template> is a SCALAR ref then it is the contents of a template to be compiled.
740              
741             =cut
742              
743             sub does_exist {
744 8 100 100 8 1 2042 $_[0]{cache_code} and not $_[0]{static} and exists $_[0]{mod}{$_[1]}
      100        
745             and return -f $_[0]->_plate_file($_[1]);
746              
747 7 100 66     32 exists $_[0]{mem}{$_[1]} or -f($_[0]->_plate_file($_[1]) // $_[0]->_cache_file($_[1]));
748             }
749             sub can_serve {
750 7     7 1 23 local($Plate::_s, @Plate::_c) = $_[0];
751 7         68 _local_vars $$Plate::_s{package}, $$Plate::_s{vars};
752 7 100       14 !!eval { ref $_[1] eq 'SCALAR' ? _compile ${$_[1]} : _sub $_[1] };
  7         26  
  1         4  
753             }
754              
755             =head2 set
756              
757             $plate->set(%options);
758              
759             Set the options for this C engine.
760             Options are the same as those for L.
761              
762             =cut
763              
764             my %sigil = (
765             ARRAY => '@',
766             CODE => '&',
767             GLOB => '*',
768             HASH => '%',
769             );
770              
771             sub set {
772 51     51 1 13353 my($self, %opt) = @_;
773              
774 51         203 while (my($k, $v) = each %opt) {
775 72 100       516 if ($k eq 'encoding') {
    100          
    100          
    100          
    100          
    100          
    100          
    100          
776 4         6 $k = 'io_layers';
777 4 100       16 $v = length $v ? $v eq 'utf8' ? ':utf8' : ":encoding($v)" : '';
    100          
778             } elsif ($k eq 'path') {
779 15 100       41 $v = _path $v if length $v;
780             } elsif ($k eq 'cache_path') {
781             # A relative cache_path must start with "./" to prevent searching @INC when sourcing the file
782 11 100       36 $v = _path $v, 1 if defined $v;
783             } elsif ($k =~ /^(?:(?:cache_)?suffix|init|io_layers|once)$/) {
784 5   100     32 $v //= '';
785             } elsif ($k eq 'filters') {
786 9 100       21 if (defined $v) {
787 8 100       131 ref $v eq 'HASH' or croak "Invalid $k (not a hash reference)";
788 7         31 while (my($name, $code) = each %$v) {
789 8 100       117 $name =~ /^\w+$/
790             or croak "Invalid filter name '$name'";
791 7 100       17 if (defined $code) {
792             ref $code eq 'CODE'
793             or $code = ($code =~ /(.*)::(.*)/
794             ? $1->can($2)
795 5 100 100     207 : do {
    100          
796 1         2 my($i,$p) = 0;
797 1         6 $i++ while __PACKAGE__ eq ($p = caller $i);
798 1         14 $p->can($code)
799             })
800             or croak "Invalid subroutine '$$v{$name}' for filter '$name'";
801 4         19 $$self{filters}{$name} = $code;
802             } else {
803 2         10 delete $$self{filters}{$name};
804             }
805             }
806             } else {
807 1         2 undef %{$$self{$k}};
  1         7  
808             }
809 6         21 next;
810             } elsif ($k eq 'vars') {
811 5 100       15 if (defined $v) {
812 4 100       139 ref $v eq 'HASH' or croak "Invalid $k (not a hash reference)";
813 3         13 while (my($name, $ref) = each %$v) {
814 7 100       14 if (defined $ref) {
815 6   100     35 my $sigil = $sigil{Scalar::Util::reftype $ref // 'CODE'} // '$';
      100        
816 6 100       66 $name =~ s/^\Q$sigil\E?/$sigil ne '&' && $sigil/e;
  6         28  
817 6         27 $$self{vars}{$name} = $ref;
818             } else {
819 1         5 delete $$self{vars}{$name};
820             }
821             }
822             } else {
823 1         2 undef %{$$self{$k}};
  1         7  
824             }
825 4         14 next;
826             } elsif ($k eq 'package') {
827 3 100 100     232 defined $v and $v =~ /^[A-Z_a-z][0-9A-Z_a-z]*(?:::[0-9A-Z_a-z]+)*$/
      100        
828             or croak "Invalid package name '".($v // '')."'";
829             } elsif ($k !~ /^(?:auto_filter|cache_code|chomp|keep_undef|max_call_depth|static|umask)$/) {
830 1         203 croak "Invalid setting '$k'";
831             }
832 55         249 $$self{$k} = $v;
833             }
834              
835 44 100       99 if (defined $$self{path}) {
836 40         87 undef $!;
837 40 100       97 my $dir = length $$self{path} ? $$self{path} : '.';
838 40 100 50     1046 -d $dir and -r _ or croak "Can't set path to $dir: ".($! || 'Not accessable');
      66        
839 39 100 100     215 undef $$self{static} if $$self{static} and $$self{static} eq 'auto';
840             } else {
841 4   100     18 $$self{static} ||= 'auto';
842             }
843              
844 43 100       177 if (defined $$self{cache_path}) {
    100          
845 15         36 my $dir = $$self{cache_path};
846 15 100       248 if (-d $dir) {
847 10 50       99 -w _ or croak "Cache directory $dir is not writeable";
848             } else {
849 5         41 my $umask = umask $$self{umask};
850 5 100       470 (mkdir($dir), umask $umask)[0]
851             or croak "Can't create cache directory $dir: $!";
852             }
853             } elsif (not $$self{cache_code}) {
854 9   100     52 $$self{static} ||= 'auto';
855             }
856             }
857              
858             =head1 AUTHOR
859              
860             Vernon Lyon C<< >>
861              
862             =head1 BUGS
863              
864             Please report any bugs or feature requests on L.
865              
866             =head1 SOURCE
867              
868             The source code is hosted on L.
869             Feel free to fork the repository and submit pull requests!
870              
871             =head1 SUPPORT
872              
873             You can find documentation for this module with the perldoc command.
874              
875             perldoc Plate
876              
877             You can also read the documentation online on L.
878              
879             =head1 COPYRIGHT AND LICENSE
880              
881             Copyright (C) 2018, Vernon Lyon.
882              
883             This library is free software; you can redistribute it and/or modify
884             it under the same terms as Perl itself.
885              
886             =cut
887              
888             1;