File Coverage

blib/lib/HTML/Template/Parser/TreeWriter/TextXslate/Metakolon.pm
Criterion Covered Total %
statement 139 152 91.4
branch 33 44 75.0
condition 8 12 66.6
subroutine 33 36 91.6
pod 1 5 20.0
total 214 249 85.9


line stmt bran cond sub pod time code
1             package HTML::Template::Parser::TreeWriter::TextXslate::Metakolon;
2              
3 4     4   5312 use strict;
  4         9  
  4         237  
4 4     4   24 use warnings;
  4         10  
  4         171  
5              
6 4     4   25 use base qw(HTML::Template::Parser::TreeWriter);
  4         8  
  4         12859  
7             __PACKAGE__->mk_accessors(qw( expr_writer wrap_template_target special_raw_var_map ));
8              
9             sub new {
10 34     34 1 41094 my $class = shift;
11 34         219 my $self = $class->SUPER::new(@_);
12 34         631 $self->expr_writer(HTML::Template::Parser::TreeWriter::TextXslate::Metakolon::Expr->new);
13 34         646 $self->context([]);
14 34         236 $self->expr_writer->context($self->context);
15 34         458 $self->special_raw_var_map({});
16 34         240 $self;
17             }
18             sub get_type {
19 190     190 0 269 my($self, $node) = @_;
20 190         1217 my($type) = (ref($node) =~ /::([^:]+)$/);
21 190         38414 $type;
22             }
23              
24             sub get_node_children {
25 190     190 0 254 my($self, $node) = @_;
26 190         185 @{$node->children};
  190         496  
27             }
28              
29             sub is_escaped {
30 38     38 0 70 my($self, $node) = @_;
31              
32 38 100 100     184 if($node->[0] eq 'function' and $node->[1]->[1] =~ /^(form|html)$/){
33 5         16 return 1;
34             }
35 33         96 return 0;
36             }
37              
38             sub remove_escape_function {
39 5     5 0 9 my($self, $node) = @_;
40 5         13 return $node->[2];
41             }
42              
43             sub _pre_String {
44 62     62   83 my($self, $node) = @_;
45              
46 62         166 $node->text;
47             }
48              
49             sub _pre_Var {
50 38     38   54 my($self, $node) = @_;
51              
52 38         60 my $is_raw = 1;
53 38         115 my $src = $node->name_or_expr->[1];
54 38 100       242 if($self->is_escaped($src)){
55 5         8 $is_raw = 0;
56 5         11 $src = $self->remove_escape_function($src);
57             }
58 38 100       140 if(lc($node->escape) eq 'html'){
59 7         49 $is_raw = 0;
60 7         19 $node->escape(0);
61             }
62 38         11803 my $name_or_expr = $self->expr_writer->write($src);
63 38 100       141 if(defined($node->default)){
64 2         17 $name_or_expr .= " || " . $self->expr_writer->write($node->default);
65             }
66 38 50       283 if($node->escape){
67 0         0 $name_or_expr .= " | " . $node->escape;
68             }
69              
70 38 50 66     391 if($name_or_expr =~ /^\$(.*)/ and $self->special_raw_var_map->{$1}){
71 0         0 $is_raw = 1;
72             }
73 38 100       272 if($is_raw){
74 26         125 qq{[% $name_or_expr | mark_raw %]};
75             }else{
76 12         52 qq{[% $name_or_expr %]};
77             }
78             }
79              
80             sub _pre_Include {
81 9     9   15 my($self, $node) = @_;
82              
83 9 50       33 if($node->name_or_expr->[0] eq 'name'){
84             # treat as string
85 9         73 $node->name_or_expr->[1][0] = 'string';
86             }
87 9 100 66     84 if($ENV{OLD_TEMPLATE_SUFFIX} and $ENV{NEW_TEMPLATE_SUFFIX}){ # @@@
88 1 50       4 if($node->name_or_expr->[1][0] eq 'string'){
89 1         8 $node->name_or_expr->[1][1] =~ s/\.$ENV{OLD_TEMPLATE_SUFFIX}\z/.$ENV{NEW_TEMPLATE_SUFFIX}/o;
90             }
91             }
92 9         56 my $name_or_expr = $self->expr_writer->write($node->name_or_expr->[1]);
93 9         17 my $template;
94 9 100       33 if($self->wrap_template_target){ # for on-the-fly converting.
95 1         8 $template = $self->wrap_template_target . "($name_or_expr)";
96             }else{
97 8         47 $template = $name_or_expr;
98             }
99 9 100       51 if($self->current_context){
100 4         25 my $var = '$' . $self->current_context->{loop_var_name};
101 4         30 qq{[% include $template { $var } %]};
102             }else{
103 5         25 qq{[% include $template %]};
104             }
105             }
106              
107              
108             sub _pre_If {
109 5     5   11 my($self, $node) = @_;
110              
111 5         31 my $name_or_expr = $self->expr_writer->write($node->name_or_expr->[1]);
112             # @@@ @@@ @@@ @@@. Text::Xslate eval [] as true. so wrap it.
113 5         26 "[% if(_has_value($name_or_expr)){ %]";
114             }
115              
116             sub _pre_ElsIf {
117 1     1   2 my($self, $node) = @_;
118              
119 1         4 my $name_or_expr = $self->expr_writer->write($node->name_or_expr->[1]);
120 1         6 "[% }elsif(_has_value($name_or_expr)){ %]";
121             }
122              
123             sub _pre_Else {
124 1     1   4 "[% }else{ %]";
125             }
126              
127             sub _pre_IfEnd {
128 5     5   17 "[% } %]";
129             }
130              
131             sub _pre_Unless {
132 0     0   0 my($self, $node) = @_;
133              
134 0         0 my $name_or_expr = $self->expr_writer->write($node->name_or_expr->[1]);
135 0         0 "[% if(! _has_value($name_or_expr)){ %]";
136             }
137              
138             sub _pre_UnlessEnd {
139 0     0   0 "[% } %]";
140             }
141              
142             sub _pre_Loop {
143 10     10   21 my($self, $node) = @_;
144              
145 10         40 my $depth = $self->get_context_depth + 1;
146 10         72 my $loop_var_name = '_item_' . $depth;
147              
148 10         35 my $name_or_expr = $self->expr_writer->write($node->name_or_expr->[1]);
149 10         38 my $ret = "[% for $name_or_expr->\$$loop_var_name { %]";
150              
151 10         56 my $context = $self->create_and_push_context();
152 10         28 $context->{loop_var_name} = $loop_var_name;
153              
154 10         36 $ret;
155             }
156              
157             sub _pre_LoopEnd {
158 10     10   18 my($self, $node) = @_;
159 10         33 $self->pop_context();
160 10         68 "[% } %]";
161             }
162              
163             package HTML::Template::Parser::TreeWriter::TextXslate::Metakolon::Expr;
164              
165 4     4   38 use strict;
  4         7  
  4         159  
166 4     4   22 use warnings;
  4         10  
  4         837  
167              
168 4     4   25 use base qw(HTML::Template::Parser::TreeWriter);
  4         8  
  4         46458  
169              
170             my %op_to_name = (
171             'not' => 'not_sym',
172             '!' => 'not',
173             );
174              
175             foreach my $bin_operator (qw(or and || && > >= < <= != == le ge eq ne lt gt + - * / % =~ !~)){
176             $op_to_name{$bin_operator} = 'binary';
177             }
178              
179             sub get_type {
180 114     114   155 my($self, $node) = @_;
181              
182 114         209 my $type = $node->[0]; # 'op', 'variable', 'function' ....
183 114 100       340 if($node->[0] eq 'op'){
184 19         54 my $op_name = $op_to_name{$node->[1]};
185 19 50       47 die "Unknown op_name[$node->[1]]\n" unless $op_name;
186 19         46 $type .= '_' . $op_name;
187             }
188 114         339 $type;
189             }
190              
191             sub get_node_children {
192 0     0   0 my($self, $node) = @_;
193 0         0 die "internal error\n"; # use custom map function.
194             }
195              
196             ################################################################
197             # bin_op
198             sub _main_op_binary {
199 17     17   28 my($self, $node) = @_;
200              
201 17         49 my %op_translate_table = (
202             'eq' => '==',
203             'ne' => '!=',
204             );
205 17   33     84 my $op = $op_translate_table{$node->[1]} || $node->[1];
206              
207 17         77 '(' . $self->write($node->[2]) . ' ' . $op . ' ' . $self->write($node->[3]) . ')';
208             }
209              
210             ################################################################
211             # op_not_sym
212             sub _main_op_not_sym {
213 1     1   4 my($self, $node) = @_;
214              
215 1         5 '(' . 'not ' . $self->write($node->[2]) . ')';
216             }
217              
218             ################################################################
219             # op_not
220             sub _main_op_not {
221 1     1   3 my($self, $node) = @_;
222              
223 1         7 '(' . '!' . $self->write($node->[2]) . ')';
224             }
225              
226             ################################################################
227             # function
228             sub _pre_function {
229 8     8   18 my($self, $node) = @_;
230 8         27 my $name = $node->[1]->[1];
231              
232 8 50       26 if($self->_is_static_function($name)){
233 0         0 $name;
234             }else{
235 8         34 '$'.$name;
236             }
237             }
238              
239             sub _map_function {
240 8     8   15 my($self, $node) = @_;
241              
242 8         12 my @chilren_out;
243 8         29 for(my $i = 2;$i < @$node;$i ++){ # 0:'function', 1:['name', 'function_name'], 2:param1, 3:param2, ....
244 13         26 my $child_node = $node->[$i];
245 13         43 push(@chilren_out, $self->write($child_node));
246             }
247 8         37 @chilren_out;
248             }
249              
250             sub _join_function {
251 8     8   17 my($self, $node, $chilren_out) = @_;
252              
253 8         45 '(' . join(',', @$chilren_out) . ')';
254             }
255              
256             sub _is_static_function { # @@@
257 8     8   29 my($self, $name) = @_;
258              
259 8 50       27 return 1 if($name eq 'not');
260 8         30 0;
261             }
262              
263             ################################################################
264             # string
265             sub _main_string {
266 10     10   24 my($self, $node) = @_;
267              
268 10         41 qq{'$node->[1]'};
269             }
270              
271             ################################################################
272             # variable
273             sub _main_variable {
274 47     47   72 my($self, $node) = @_;
275              
276             # @@@ TODO
277             # need to suport path-like-variable. ex) ../foo /foo
278 47 100       152 if($self->current_context){
279 12 100       128 if($node->[1] =~ /^__counter__$/){
    50          
    50          
    50          
    50          
280             # You can get the iterator index in "for" statements as "$~ITERATOR_VAR":
281 2         9 sprintf('$~%s.count', $self->current_context->{loop_var_name});
282             }elsif($node->[1] =~ /^__first__$/){
283 0         0 sprintf('($~%s.count == 1)', $self->current_context->{loop_var_name});
284             }elsif($node->[1] =~ /^__last__$/){
285 0         0 sprintf('($~%s.count == $~%s.size)',
286             $self->current_context->{loop_var_name},
287             $self->current_context->{loop_var_name});
288             }elsif($node->[1] =~ /^__inner__$/){
289 0         0 sprintf('($~%s.count != 1 && $~%s.count == $~%s.size)',
290             $self->current_context->{loop_var_name},
291             $self->current_context->{loop_var_name},
292             $self->current_context->{loop_var_name});
293             }elsif($node->[1] =~ /^__odd__$/){
294 0         0 sprintf('($~%s.count %% 2)', $self->current_context->{loop_var_name});
295             }else{
296 10         15 my @loop_var_list;
297 10         13 foreach my $context (reverse @{ $self->context }){
  10         26  
298 19         73 push(@loop_var_list, $context->{loop_var_name});
299             }
300 19         162 sprintf(q!_choise_var('%s', $%s, %s)!,
301             $node->[1],
302             $node->[1],
303 10         23 join(',', (map { '$' . $_ } @loop_var_list)));
304             }
305             }else{
306 35         145 '$' . $node->[1];
307             }
308             }
309              
310             ################################################################
311             # number
312             sub _main_number {
313 27     27   50 my($self, $node) = @_;
314              
315 27         97 $node->[1];
316             }
317              
318             ################################################################
319             # default
320             sub _main_default {
321 2     2   5 my($self, $node) = @_;
322              
323 2         10 qq{"$node->[1]"};
324             }
325              
326             ################################################################
327             # regexp
328             sub _main_regexp {
329 1     1   4 my($self, $node) = @_;
330              
331 1         4 $node->[1];
332             }
333              
334             1;