line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
#=============================================================================== |
2
|
|
|
|
|
|
|
# |
3
|
|
|
|
|
|
|
# DESCRIPTION: Plosurin - Perl 5 implementation of Closure Templates |
4
|
|
|
|
|
|
|
# |
5
|
|
|
|
|
|
|
# AUTHOR: Aliaksandr P. Zahatski, <zahatski@gmail.com> |
6
|
|
|
|
|
|
|
#=============================================================================== |
7
|
|
|
|
|
|
|
package Plosurin; |
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
=head1 NAME |
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
Plosurin - Perl 5 implementation of Closure Templates |
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
=head1 SYNOPSIS |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
For template C<example.soy> with content: |
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
{namespace mytest} |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
/** |
20
|
|
|
|
|
|
|
* Simple test |
21
|
|
|
|
|
|
|
*/ |
22
|
|
|
|
|
|
|
{template .Hello} |
23
|
|
|
|
|
|
|
<h1>Foreach example</h1> |
24
|
|
|
|
|
|
|
{foreach $a in [1,2]} |
25
|
|
|
|
|
|
|
<p>Line: {$a}</p><br/> |
26
|
|
|
|
|
|
|
{/foreach} |
27
|
|
|
|
|
|
|
<p>Ok</p> |
28
|
|
|
|
|
|
|
{/template} |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
To get Perl 5 module (MyApp, for example), just run the following command: |
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
plosurin.p5 -package MyApp < example.soy > MyApp.pm |
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
Use template in your Perl 5 program: |
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
use MyApp; |
37
|
|
|
|
|
|
|
print &MyApp::mytest_Hello(); |
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
or get help: |
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
perldoc MyApp.pm |
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
=head1 DESCRIPTION |
44
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
Plosurin - Perl implementation of Closure Templates. |
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
=head2 Template Structure |
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
Every Soy file should have these components, in this order: |
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
=over |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
=item * A namespace declaration. |
54
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
=item * One or more template definitions. |
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
=back |
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
Here is an example template: |
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
{namespace examples.simple} |
62
|
|
|
|
|
|
|
/** |
63
|
|
|
|
|
|
|
* Says hello to a person. |
64
|
|
|
|
|
|
|
* @param name The name of the person to say hello to. |
65
|
|
|
|
|
|
|
*/ |
66
|
|
|
|
|
|
|
{template .helloName} |
67
|
|
|
|
|
|
|
Hello {$name}! |
68
|
|
|
|
|
|
|
{/template} |
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
=head2 Command Syntax |
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
Commands are instructions that you give the template compiler to create templates and add custom logic to templates. Put commands within Closure Template tags, which are delimited by braces (C<{}>). |
74
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
The first token within a tag is the command name (the print command is implied if no command is specified), and the rest of the text within the tag (if any) is referred to as the command text. Within the template you can enclose other commands to evaluate conditional expressions, iterate over data objects, or print messages. |
76
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
{/foreach} |
78
|
|
|
|
|
|
|
{if length($items) > 5} |
79
|
|
|
|
|
|
|
{msg desc="Says hello to the user."} |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
If a command has a corresponding end command, then the end command's name is a C</> followed by the name of the start command, e.g. foreach and C</foreach>. |
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
=cut |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
package Plo::File; |
86
|
2
|
|
|
2
|
|
126792
|
use Plosurin::SoyTree; |
|
2
|
|
|
|
|
6
|
|
|
2
|
|
|
|
|
91
|
|
87
|
2
|
|
|
2
|
|
15
|
use base 'Soy::base'; |
|
2
|
|
|
|
|
6
|
|
|
2
|
|
|
|
|
1059
|
|
88
|
|
|
|
|
|
|
our $VERSION = '0.01'; |
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
sub new { |
91
|
6
|
|
|
6
|
|
17
|
my $class = shift; |
92
|
6
|
50
|
33
|
|
|
42
|
my $self = bless( ( $#_ == 0 ) ? shift : {@_}, ref($class) || $class ); |
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
#set namespace |
95
|
6
|
|
|
|
|
24
|
my $namespace = $self->{namespace}->{id}; |
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
#set src file |
98
|
6
|
|
|
|
|
15
|
my $file = $self->{file}; |
99
|
6
|
|
|
|
|
10
|
foreach my $tmpl ( @{ $self->{templates} } ) { |
|
6
|
|
|
|
|
21
|
|
100
|
12
|
|
|
|
|
25
|
$tmpl->{namespace} = $namespace; |
101
|
12
|
|
|
|
|
28
|
$tmpl->{srcfile} = $file; |
102
|
|
|
|
|
|
|
} |
103
|
|
|
|
|
|
|
|
104
|
6
|
|
|
|
|
121
|
$self; |
105
|
|
|
|
|
|
|
} |
106
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
sub namespace { |
108
|
7
|
|
|
7
|
|
19
|
$_[0]->{namespace}->{id}; |
109
|
|
|
|
|
|
|
} |
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
sub childs { |
112
|
1
|
|
|
1
|
|
3
|
my $self = shift; |
113
|
1
|
|
|
|
|
3
|
return [ $self->templates ]; |
114
|
|
|
|
|
|
|
} |
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
=head2 templates |
117
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
Return array of tempaltes |
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
=cut |
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
sub templates { |
123
|
6
|
|
|
6
|
|
22
|
my $self = shift; |
124
|
6
|
|
|
|
|
10
|
@{ $self->{templates} }; |
|
6
|
|
|
|
|
35
|
|
125
|
|
|
|
|
|
|
} |
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
package Plo::template; |
128
|
2
|
|
|
2
|
|
18
|
use strict; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
45
|
|
129
|
2
|
|
|
2
|
|
12
|
use warnings; |
|
2
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
57
|
|
130
|
2
|
|
|
2
|
|
11
|
use Plosurin::SoyTree; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
52
|
|
131
|
2
|
|
|
2
|
|
11
|
use base 'Soy::base'; |
|
2
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
1425
|
|
132
|
|
|
|
|
|
|
our $VERSION = '0.01'; |
133
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
sub new { |
135
|
12
|
|
|
12
|
|
26
|
my $class = shift; |
136
|
12
|
50
|
33
|
|
|
255
|
bless( ( $#_ == 0 ) ? shift : {@_}, ref($class) || $class ); |
137
|
|
|
|
|
|
|
} |
138
|
|
|
|
|
|
|
|
139
|
2
|
|
|
2
|
|
15
|
sub body { $_[0]->{template_block}->{raw_template} } |
140
|
8
|
|
|
8
|
|
30
|
sub name { $_[0]->{template_block}->{start_template}->{name} } |
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
sub comment { |
143
|
3
|
|
|
3
|
|
5
|
return join "\n", map { $_->{raw_str} } @{ $_[0]->{header}->{h_comment} }; |
|
5
|
|
|
|
|
37
|
|
|
3
|
|
|
|
|
9
|
|
144
|
|
|
|
|
|
|
} |
145
|
3
|
50
|
|
3
|
|
12
|
sub params { exists $_[0]->{header}->{h_params} ? @{ $_[0]->{header}->{h_params} } : ()} |
|
3
|
|
|
|
|
15
|
|
146
|
1
|
|
|
1
|
|
3
|
sub full_name { my $self = shift; $self->{namespace} . $self->name } |
|
1
|
|
|
|
|
4
|
|
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
sub namespace { |
149
|
0
|
|
|
0
|
|
0
|
$_[0]->{namespace}->{id}; |
150
|
|
|
|
|
|
|
} |
151
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
#parse body and return Soy tree |
153
|
|
|
|
|
|
|
sub childs { |
154
|
2
|
|
|
2
|
|
7
|
my $self = shift; |
155
|
|
|
|
|
|
|
my $plo = new Plosurin::SoyTree( |
156
|
|
|
|
|
|
|
src => $self->body, |
157
|
|
|
|
|
|
|
offset => $self->{template_block}->{matchline}, |
158
|
|
|
|
|
|
|
srcfile => $self->{srcfile} |
159
|
2
|
|
|
|
|
7
|
); |
160
|
2
|
50
|
|
|
|
7
|
die $plo unless ref $plo; |
161
|
|
|
|
|
|
|
|
162
|
2
|
|
|
|
|
7
|
my $reduced = $plo->reduced_tree; |
163
|
2
|
|
|
|
|
10
|
return $reduced; |
164
|
|
|
|
|
|
|
} |
165
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
1; |
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
package Plo::h_params; |
169
|
|
|
|
|
|
|
our $VERSION = '0.01'; |
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
sub new { |
172
|
15
|
|
|
15
|
|
33
|
my $class = shift; |
173
|
15
|
50
|
33
|
|
|
299
|
bless ( ($#_ == 0) ? shift : {@_}, ref($class) || $class); |
174
|
|
|
|
|
|
|
} |
175
|
|
|
|
|
|
|
|
176
|
4
|
|
|
4
|
|
15
|
sub name { $_[0]->{id} } |
177
|
0
|
|
|
0
|
|
0
|
sub is_notreq {$_[0]->{is_notreq} } |
178
|
0
|
|
|
0
|
|
0
|
sub comment {$_[0]->{raw_str}} |
179
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
1; |
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
package Plosurin; |
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
=head1 Perl 5 code generator API |
185
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
use Plosurin; |
187
|
|
|
|
|
|
|
my $p = new Plosurin::; |
188
|
|
|
|
|
|
|
my $in_fd = new IO::File:: "< $infile" or die "$infile: $!"; |
189
|
|
|
|
|
|
|
my $nodes = $p->parse( $in, "file_name.soy"); |
190
|
|
|
|
|
|
|
say $p->as_perl5( { package => "MyApp::Templates" }, $nodes ); |
191
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
=cut |
194
|
|
|
|
|
|
|
|
195
|
2
|
|
|
2
|
|
52
|
use strict; |
|
2
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
57
|
|
196
|
2
|
|
|
2
|
|
11
|
use warnings; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
67
|
|
197
|
2
|
|
|
2
|
|
20
|
use v5.10; |
|
2
|
|
|
|
|
8
|
|
198
|
|
|
|
|
|
|
our $VERSION = '0.2'; |
199
|
2
|
|
|
2
|
|
14
|
use Regexp::Grammars; |
|
2
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
84
|
|
200
|
2
|
|
|
2
|
|
378
|
use Plosurin::Grammar; |
|
2
|
|
|
|
|
6
|
|
|
2
|
|
|
|
|
76
|
|
201
|
2
|
|
|
2
|
|
483
|
use Plosurin::Context; |
|
2
|
|
|
|
|
6
|
|
|
2
|
|
|
|
|
49
|
|
202
|
2
|
|
|
2
|
|
10
|
use Plosurin::SoyTree; |
|
2
|
|
|
|
|
9
|
|
|
2
|
|
|
|
|
35
|
|
203
|
2
|
|
|
2
|
|
445
|
use Plosurin::To::Perl5; |
|
2
|
|
|
|
|
6
|
|
|
2
|
|
|
|
|
60
|
|
204
|
2
|
|
|
2
|
|
464
|
use Plosurin::Writer::Perl5; |
|
2
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
241
|
|
205
|
|
|
|
|
|
|
our $file = "???"; |
206
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
sub new { |
208
|
3
|
|
|
3
|
0
|
276
|
my $class = shift; |
209
|
3
|
50
|
33
|
|
|
36
|
bless( ( $#_ == 0 ) ? shift : {@_}, ref($class) || $class ); |
210
|
|
|
|
|
|
|
} |
211
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
sub parse { |
213
|
6
|
|
|
6
|
0
|
25
|
my $self = shift; |
214
|
6
|
|
|
|
|
13
|
my $ref = shift; |
215
|
6
|
|
|
|
|
10
|
our $file = shift; |
216
|
6
|
|
|
|
|
43
|
my $r = qr{ |
217
|
|
|
|
|
|
|
<extends: Plosurin::Template::Grammar> |
218
|
|
|
|
|
|
|
<matchline> |
219
|
|
|
|
|
|
|
\A <File> \Z |
220
|
|
|
|
|
|
|
}xms; |
221
|
6
|
50
|
|
|
|
174
|
if ( $ref =~ $r ) { |
222
|
6
|
|
|
|
|
78
|
return {%/}->{File}; |
223
|
|
|
|
|
|
|
} |
224
|
0
|
|
|
|
|
0
|
undef; |
225
|
|
|
|
|
|
|
} |
226
|
|
|
|
|
|
|
|
227
|
|
|
|
|
|
|
=head2 as_perl5 { package=>"MyApp::Tmpl" }, $node1[, $noden] |
228
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
Export nodes as perl5 package |
230
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
=cut |
232
|
|
|
|
|
|
|
|
233
|
2
|
|
|
2
|
|
18
|
use Data::Dumper; |
|
2
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
554
|
|
234
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
sub as_perl5 { |
236
|
1
|
|
|
1
|
1
|
12
|
my $self = shift; |
237
|
1
|
|
|
|
|
2
|
my $opt = shift; |
238
|
1
|
50
|
|
|
|
4
|
return " need at least one $file" unless scalar(@_); |
239
|
1
|
50
|
|
|
|
4
|
my @files = map { ( ref($_) eq 'ARRAY' ) ? @{$_} : ($_) } @_; |
|
1
|
|
|
|
|
7
|
|
|
0
|
|
|
|
|
0
|
|
240
|
1
|
|
|
|
|
3
|
my @alltemplates = (); |
241
|
|
|
|
|
|
|
|
242
|
1
|
|
50
|
|
|
4
|
my $package = $opt->{package} || die " |
243
|
|
|
|
|
|
|
use as_perl5( { package => ... } ) !"; |
244
|
|
|
|
|
|
|
|
245
|
1
|
|
|
|
|
6
|
my $ctx = new Plosurin::Context(@files); |
246
|
|
|
|
|
|
|
|
247
|
1
|
|
|
|
|
10
|
my $p5 = new Plosurin::To::Perl5( |
248
|
|
|
|
|
|
|
'context' => $ctx, |
249
|
|
|
|
|
|
|
'writer' => new Plosurin::Writer::Perl5, |
250
|
|
|
|
|
|
|
'package' => $package, |
251
|
|
|
|
|
|
|
); |
252
|
1
|
|
|
|
|
8
|
$p5->start_write(); |
253
|
1
|
|
|
|
|
5
|
$p5->write(@files); |
254
|
1
|
|
|
|
|
4
|
$p5->end_write(); |
255
|
1
|
|
|
|
|
4
|
my $res = $p5->wr->{code}; |
256
|
1
|
50
|
|
|
|
10
|
wantarray() ? ( $res, @{ $p5->{tmpls} } ) : $res; |
|
0
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
} |
258
|
|
|
|
|
|
|
|
259
|
|
|
|
|
|
|
1; |
260
|
|
|
|
|
|
|
__END__ |
261
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
=head1 SEE ALSO |
263
|
|
|
|
|
|
|
|
264
|
|
|
|
|
|
|
Closure Templates Documentation L<http://code.google.com/closure/templates/docs/overview.html> |
265
|
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
Perl 6 implementation L<https://github.com/zag/plosurin> |
267
|
|
|
|
|
|
|
|
268
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
=head1 AUTHOR |
270
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
Zahatski Aliaksandr, <zag@cpan.org> |
272
|
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
=head1 COPYRIGHT AND LICENSE |
274
|
|
|
|
|
|
|
|
275
|
|
|
|
|
|
|
Copyright (C) 2011 by Zahatski Aliaksandr |
276
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or modify |
278
|
|
|
|
|
|
|
it under the same terms as Perl itself. |
279
|
|
|
|
|
|
|
|
280
|
|
|
|
|
|
|
=cut |
281
|
|
|
|
|
|
|
|