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)(?:(.*?)^%%\g-2>(?:\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
|
|
|
|
|
|
|
(%%def|%%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\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|%perl)>(?:\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> 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> 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
|
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
|
|
|
|
|
|
|
%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 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
|
|
|
|
|
|
|
%def> |
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; |