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)(?:(.*?)^%%\g-2>(?:\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
|
|
|
|
|
|
|
(%%def|%%filter|%%perl)>(?:\R|\z)| |
49
|
|
|
|
|
|
|
(&&)>|\z |
50
|
|
|
|
|
|
|
)'mosx; |
51
|
|
|
|
|
|
|
my $re_run = qr'(.*?)(?: |
52
|
|
|
|
|
|
|
^%\h*(\V*?)\h*(?:\R|\z)| |
53
|
|
|
|
|
|
|
^<%(perl)>(?:\R|\z)(?:(.*?)^%\g-2>(?:\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
|
|
|
|
|
|
|
(%def|%filter|%perl)>(?:\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> 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> tag without opening <$tag...> tag at $line" |
202
|
|
|
|
|
|
|
: "Opening <$_[3]...> tag without closing $_[3]> 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
|
|
|
|
|
|
|
%perl> |
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
|
|
|
|
|
|
|
%def> |
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
|
|
|
|
|
|
|
%filter> |
504
|
|
|
|
|
|
|
|
505
|
|
|
|
|
|
|
<%filter bold> |
506
|
|
|
|
|
|
|
<& _ &> |
507
|
|
|
|
|
|
|
%filter> |
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; |