File Coverage

blib/lib/Plosurin/SoyTree.pm
Criterion Covered Total %
statement 387 410 94.3
branch 29 46 63.0
condition 16 31 51.6
subroutine 117 121 96.6
pod 3 5 60.0
total 552 613 90.0


line stmt bran cond sub pod time code
1             #===============================================================================
2             #
3             # DESCRIPTION: util for tree
4             #
5             # AUTHOR: Aliaksandr P. Zahatski, <zahatski@gmail.com>
6             #===============================================================================
7              
8             =head1 NAME
9              
10             Plosurin::SoyTree - syntax tree
11              
12             =head1 SYNOPSIS
13              
14             my $plo = new Plosurin::SoyTree( src => $self->body );
15              
16             =head1 DESCRIPTION
17              
18             Plosurin::SoyTree - syntax tree
19              
20             =cut
21              
22             package Soy::Actions;
23 4     4   111443 use strict;
  4         21  
  4         133  
24 4     4   26 use warnings;
  4         11  
  4         117  
25 4     4   55 use v5.10;
  4         14  
26 4     4   31 use Data::Dumper;
  4         8  
  4         544  
27             our $VERSION = '0.01';
28              
29             sub new {
30 19     19   35 my $class = shift;
31 19 50 33     139 bless( ( $#_ == 0 ) ? shift : {@_}, ref($class) || $class );
32             }
33              
34             1;
35              
36             package Soy::base;
37 4     4   26 use Data::Dumper;
  4         11  
  4         1467  
38             our $VERSION = '0.01';
39              
40             sub new {
41 413     413   784 my $class = shift;
42 413 50 33     8482 bless( ( $#_ == 0 ) ? shift : {@_}, ref($class) || $class );
43             }
44              
45             # return undef if ok
46             # else string with [error] Bad value
47             # or [warn] not inited variable
48              
49             sub check {
50 0     0   0 my $self = shift;
51 0         0 return undef; #ok
52             }
53              
54             sub attrs {
55 61     61   85 my $self = shift;
56 61   100     159 my $attr = $self->{attribute} || [];
57 61         92 my %attr = ();
58 61         92 foreach my $rec (@$attr) {
59 9         23 $attr{ $rec->{name} } = $rec->{value};
60             }
61 61         154 return \%attr;
62             }
63              
64             sub childs {
65 60     60   82 my $self = shift;
66 60 50       115 if (@_) {
67 0         0 $self->{content} = shift;
68             }
69 60 100       137 return [] unless exists $self->{content};
70 22         31 [ @{ $self->{content} } ];
  22         60  
71             }
72              
73             sub dump {
74 57     57   84 my $self = shift;
75 57         106 my $childs = $self->childs;
76 57         74 my $res = {};
77 57 100       106 if ( scalar(@$childs) ) {
78             $res->{childs} = [
79             map {
80 20         32 { ref( $_->{obj} ) => $_->{obj}->dump }
81 24         63 } @$childs
82             ];
83             }
84 57 100       80 if ( scalar( keys %{ $self->attrs } ) ) {
  57         113  
85 3         9 $res->{attrs} = $self->attrs;
86             }
87              
88 57         214 $res;
89              
90             }
91             1;
92              
93             package Soy::command_print;
94 4     4   34 use base 'Soy::base';
  4         8  
  4         1792  
95             our $VERSION = '0.01';
96             1;
97              
98             package Soy::raw_text;
99 4     4   33 use base 'Soy::base';
  4         11  
  4         1130  
100             our $VERSION = '0.01';
101             1;
102              
103             package Soy::command_elseif;
104 4     4   34 use base 'Soy::base';
  4         8  
  4         996  
105 4     4   29 use Data::Dumper;
  4         8  
  4         180  
106 4     4   26 use strict;
  4         9  
  4         84  
107 4     4   28 use warnings;
  4         8  
  4         421  
108             our $VERSION = '0.01';
109              
110             sub dump {
111 4     4   5 my $self = shift;
112 4         12 return { %{ $self->SUPER::dump() },
113 4         5 expression => $self->{expression}->dump };
114             }
115             1;
116              
117             package Soy::command_call_self;
118 4     4   27 use base 'Soy::base';
  4         16  
  4         1045  
119 4     4   30 use strict;
  4         8  
  4         104  
120 4     4   26 use warnings;
  4         10  
  4         126  
121 4     4   22 use Data::Dumper;
  4         9  
  4         452  
122             our $VERSION = '0.01';
123              
124             sub dump {
125 3     3   8 my $self = shift;
126 3         13 my $res = $self->SUPER::dump;
127 3         7 $res->{template} = $self->{tmpl_name};
128 3         8 $res;
129             }
130             1;
131              
132             package Soy::command_call;
133 4     4   68 use Plosurin::SoyTree;
  4         10  
  4         126  
134 4     4   26 use base 'Soy::command_call_self';
  4         18  
  4         1167  
135 4     4   67 use strict;
  4         9  
  4         87  
136 4     4   20 use warnings;
  4         7  
  4         287  
137             our $VERSION = '0.01';
138             1;
139              
140             package Soy::command_else;
141 4     4   25 use base 'Soy::base';
  4         7  
  4         1152  
142 4     4   32 use strict;
  4         6  
  4         87  
143 4     4   19 use warnings;
  4         9  
  4         231  
144             our $VERSION = '0.01';
145             1;
146              
147             package Soy::command_if;
148 4     4   27 use base 'Soy::base';
  4         5  
  4         1087  
149 4     4   29 use strict;
  4         7  
  4         72  
150 4     4   31 use warnings;
  4         9  
  4         136  
151 4     4   51 use v5.10;
  4         14  
152 4     4   27 use Data::Dumper;
  4         8  
  4         955  
153             our $VERSION = '0.01';
154              
155             sub dump {
156 5     5   12 my $self = shift;
157 5         12 my %ifs = ();
158             $ifs{'if'} =
159 5         7 { %{ $self->SUPER::dump }, expression => $self->{expression}->dump, };
  5         16  
160 5 100       17 if ( exists $self->{commands_elseif} ) {
161 3         8 my $elseifs = $self->{commands_elseif};
162             $ifs{elseif} = [
163             map {
164 3         6 { ref($_) => $_->dump }
  4         13  
165             } @$elseifs
166             ];
167              
168             }
169 5 100       14 if ( my $elseif = $self->{command_else} ) {
170              
171 4         13 $ifs{else} = { ref($elseif) => $elseif->dump() };
172             }
173              
174 5         14 \%ifs;
175             }
176             1;
177              
178             package Soy::command_param;
179 4     4   32 use base 'Soy::base';
  4         6  
  4         1039  
180 4     4   30 use warnings;
  4         7  
  4         99  
181 4     4   17 use strict;
  4         9  
  4         114  
182 4     4   41 use Data::Dumper;
  4         9  
  4         871  
183             our $VERSION = '0.01';
184              
185             sub as_perl5 {
186 0     0   0 my $self = shift;
187              
188             # my $ctx = shift;
189             #die Dumper($self);
190             #die $self->childs
191 0         0 my $str = join ' . ', map { $_->as_perl5(@_) } @{ $self->childs };
  0         0  
  0         0  
192 0         0 return qq!'$self->{name}' => $str!;
193             }
194              
195             sub dump {
196 4     4   7 my $self = shift;
197 4         7 my %res = ( %{ $self->SUPER::dump() }, name => $self->{name}, );
  4         9  
198 4 100       15 $res{value} = $self->{value} if exists $self->{value};
199 4         10 \%res;
200             }
201              
202             package Soy::command_param_self;
203 4     4   31 use base 'Soy::command_param';
  4         7  
  4         1386  
204             our $VERSION = '0.01';
205             1;
206              
207             package Soy::Node;
208             our $VERSION = '0.01';
209 4     4   32 use base 'Soy::base';
  4         9  
  4         1472  
210              
211             sub childs {
212 78     78   221 [ $_[0]->{obj} ];
213             }
214              
215             sub as_perl5 {
216 0     0   0 my $self = shift;
217 0         0 return $self->{obj}->as_perl5(@_);
218             }
219              
220             package Soy::command_import;
221 4     4   30 use strict;
  4         7  
  4         93  
222 4     4   30 use warnings;
  4         9  
  4         181  
223             our $VERSION = '0.01';
224 4     4   22 use base 'Soy::base';
  4         9  
  4         1118  
225             1;
226              
227             # $VAR1 = bless( {
228             # 'matchline' => 1,
229             # '' => '{foreach $i in [1..10]}ok{ifempty} oo{/foreach}',
230             # 'command_foreach_ifempty' => bless( {
231             # 'matchline' => 1,
232             # '' => '{ifempty} oo',
233             # 'content' => [
234             # bless( {
235             # 'matchline' => 1,
236             # 'obj' => bless( {
237             # '' => ' oo'
238             # }, 'Soy::raw_text' ),
239             # '' => ' oo',
240             # 'matchpos' => 34
241             # }, 'Soy::Node' )
242             # ],
243             # 'matchpos' => 25
244             # }, 'Soy::command_foreach_ifempty' ),
245             # 'expression' => bless( {
246             # '' => '[1..10]'
247             # }, 'Soy::expressiong' ),
248             # 'content' => [
249             # bless( {
250             # 'matchline' => 1,
251             # 'obj' => bless( {
252             # '' => 'ok'
253             # }, 'Soy::raw_text' ),
254             # '' => 'ok',
255             # 'matchpos' => 23
256             # }, 'Soy::Node' )
257             # ],
258             # 'local_var' => bless( {
259             # '' => '$i'
260             # }, 'Soy::expressiong' ),
261             # 'srcfile' => 'test'
262             # }, 'Soy::command_foreach' );
263              
264             package Soy::command_foreach;
265 4     4   28 use strict;
  4         7  
  4         89  
266 4     4   22 use warnings;
  4         7  
  4         161  
267 4     4   25 use base 'Soy::base';
  4         8  
  4         1823  
268             our $VERSION = '0.01';
269              
270             sub get_var_name {
271 1     1   2 my $self = shift;
272 1         3 my $name = $self->{local_var}->{''};
273 1 50       12 $name =~ /\$(\w+)/ ? $1 : undef;
274             }
275              
276             sub get_ifempty {
277 2     2   4 my $self = shift;
278 2         9 $self->{command_foreach_ifempty};
279             }
280              
281             sub dump {
282 2     2   4 my $self = shift;
283             my %res = (
284 2         4 %{ $self->SUPER::dump() },
  2         9  
285              
286             # expression => $self->{expression}
287             );
288 2 100       9 if ( exists $self->{command_foreach_ifempty} ) {
289 1         5 my $ife = $self->{command_foreach_ifempty};
290 1         7 $res{ifempty} = $ife->dump;
291              
292             }
293 2         7 \%res;
294             }
295              
296             package Soy::command_foreach_ifempty;
297 4     4   33 use strict;
  4         7  
  4         112  
298 4     4   31 use warnings;
  4         8  
  4         145  
299 4     4   25 use base 'Soy::base';
  4         7  
  4         1151  
300             our $VERSION = '0.01';
301             1;
302              
303             package Soy::expressiong;
304 4     4   29 use strict;
  4         6  
  4         103  
305 4     4   22 use warnings;
  4         11  
  4         120  
306 4     4   1519 use Regexp::Grammars;
  4         18545  
  4         28  
307 4     4   1734 use Plosurin::Grammar;
  4         11  
  4         173  
308 4     4   2057 use Plosurin::Utl::ExpMapVariables;
  4         12  
  4         111  
309 4     4   27 use Data::Dumper;
  4         7  
  4         182  
310 4     4   25 use base 'Soy::base';
  4         11  
  4         1396  
311             our $VERSION = '0.02';
312              
313              
314             =head2 parse {map_of_variables}
315              
316             my $e = new Soy::Expresion('1+2');
317             $e->parse({w=>"local_variable"});
318              
319              
320             =cut
321              
322             sub parse {
323 5     5   13 my $self = shift;
324 5         9 my $var_map = shift;
325 5         11 my $template_params = shift;
326 5         16 my $txt = $self->{''};
327 5         36 my $q = qr{
328             <extends: Plosurin::Exp::Grammar>
329             <nocontext:>
330             <expr>
331             }xms;
332 5 50       146 if ( $txt =~ $q ) {
333 5         17 my $tree = $/{expr};
334 5         56 my $p = new Plosurin::Utl::ExpMapVariables(
335             vars => $var_map,
336             params => $template_params
337             );
338 5         31 $p->visit($tree);
339 5         40 return $tree;
340             }
341 0         0 else { return "BAD" }
342             }
343              
344             package Soy::Expression;
345 4     4   103 use strict;
  4         10  
  4         98  
346 4     4   21 use warnings;
  4         6  
  4         97  
347 4     4   20 use Regexp::Grammars;
  4         9  
  4         23  
348 4     4   712 use Plosurin::Grammar;
  4         10  
  4         97  
349 4     4   19 use base 'Soy::expressiong';
  4         7  
  4         1552  
350             our $VERSION = '0.01';
351              
352             sub new {
353 2     2   663 my $class = shift;
354 2 50 33     29 bless( ( $#_ == 0 ) ? { '' => shift } : {@_}, ref($class) || $class );
355             }
356              
357             1;
358              
359              
360             package Exp::base;
361 4     4   32 use Data::Dumper;
  4         11  
  4         184  
362 4     4   23 use base 'Soy::base';
  4         12  
  4         1665  
363             our $VERSION = '0.01';
364              
365             sub new {
366 1605     1605   2965 my $class = shift;
367 1605 50 33     34792 bless( ( $#_ == 0 ) ? shift : {@_}, ref($class) || $class );
368             }
369              
370             sub childs {
371 8     8   13 my $self = shift;
372 8         36 return [];
373             }
374              
375             sub as_perl5 {
376 0     0   0 my $self = shift;
377 0         0 die "Method as_perl5 not implemented for " . ref($self);
378             }
379              
380             package Exp::Var;
381 4     4   31 use strict;
  4         7  
  4         86  
382 4     4   18 use warnings;
  4         48  
  4         125  
383 4     4   32 use Data::Dumper;
  4         8  
  4         179  
384 4     4   24 use base 'Exp::base';
  4         6  
  4         1597  
385             our $VERSION = '0.01';
386              
387             sub as_perl5 {
388 4     4   9 my $self = shift;
389 4         27 return "\$$self->{Ident}";
390             }
391              
392             package Exp::Digit;
393 4     4   31 use strict;
  4         10  
  4         111  
394 4     4   71 use warnings;
  4         8  
  4         137  
395 4     4   21 use Data::Dumper;
  4         7  
  4         197  
396 4     4   23 use base 'Exp::base';
  4         10  
  4         1297  
397             our $VERSION = '0.01';
398              
399             sub as_perl5 {
400 6     6   10 my $self = shift;
401 6         26 return $self->{''};
402             }
403              
404             package Exp::add;
405 4     4   34 use strict;
  4         6  
  4         100  
406 4     4   20 use warnings;
  4         9  
  4         125  
407 4     4   30 use Data::Dumper;
  4         8  
  4         219  
408 4     4   39 use base 'Exp::base';
  4         10  
  4         1511  
409             our $VERSION = '0.01';
410              
411             sub as_perl5 {
412 3     3   4 my $self = shift;
413 3         9 return $self->{a}->as_perl5() . $self->{op} . $self->{b}->as_perl5();
414             }
415              
416             sub childs {
417 3     3   5 my $self = shift;
418 3         12 return [ $self->{a}, $self->{b} ];
419             }
420              
421             package Exp::mult;
422 4     4   38 use strict;
  4         10  
  4         137  
423 4     4   22 use warnings;
  4         15  
  4         122  
424 4     4   25 use Data::Dumper;
  4         17  
  4         231  
425 4     4   23 use base 'Exp::add';
  4         9  
  4         1344  
426             our $VERSION = '0.01';
427             1;
428              
429             package Exp::String;
430 4     4   30 use strict;
  4         7  
  4         101  
431 4     4   20 use warnings;
  4         7  
  4         119  
432 4     4   22 use Data::Dumper;
  4         8  
  4         199  
433 4     4   26 use base 'Exp::base';
  4         6  
  4         1562  
434             our $VERSION = '0.01';
435              
436             sub as_perl5 {
437 2     2   3 my $self = shift;
438 2         8 return "'$self->{value}'";
439             }
440              
441             package Exp::list;
442 4     4   29 use strict;
  4         8  
  4         128  
443 4     4   21 use warnings;
  4         8  
  4         124  
444 4     4   21 use Data::Dumper;
  4         9  
  4         220  
445 4     4   32 use base 'Exp::base';
  4         12  
  4         1605  
446             our $VERSION = '0.01';
447              
448              
449             sub childs {
450 4     4   8 my $self = shift;
451 4 50       14 if (@_) {
452 0         0 $self->{expr} = \@_;
453             }
454 4         16 return $self->{expr};
455             }
456              
457             sub as_perl5 {
458 2     2   13 my $self = shift;
459 2         7 return '[' . join( ",", map { $_->as_perl5() } @{ $self->childs } ) . "]";
  6         20  
  2         8  
460             }
461              
462             package Plosurin::SoyTree;
463 4     4   38 use strict;
  4         7  
  4         102  
464 4     4   21 use warnings;
  4         15  
  4         130  
465 4     4   51 use v5.10;
  4         13  
466 4     4   24 use Data::Dumper;
  4         7  
  4         220  
467 4     4   37 use Plosurin::Grammar;
  4         8  
  4         108  
468 4     4   29 use Regexp::Grammars;
  4         7  
  4         17  
469 4     4   2629 use version; our $VERSION = qv('0.0.1');
  4         7943  
  4         23  
470              
471             =head2 new
472              
473             my $st = new Plosurin::SoyTree(
474             src => "txt",
475             srcfile=>"filesrc",
476             offset=>0
477             );
478              
479             =cut
480              
481             sub new {
482 19     19 1 383 my $class = shift;
483 19 50 33     132 my $self = bless( ( $#_ == 0 ) ? shift : {@_}, ref($class) || $class );
484 19   100     95 $self->{srcfile} //= "UNKNOWN";
485 19   100     70 $self->{offset} //= 0;
486 19 50       56 if ( my $src = $self->{src} ) {
487 19 50       48 unless ( $self->{_tree} = $self->parse($src) ) { return $self->{_tree} }
  0         0  
488             }
489 19         70 $self;
490             }
491              
492             =head2 parse
493              
494             return [node1, node2]
495              
496             =cut
497              
498             sub parse {
499 19     19 1 34 my $self = shift;
500 19   50     46 my $str = shift || return [];
501 19   33     252 my $q = shift || qr{
502             <extends: Plosurin::Grammar>
503             # <debug:step>
504             \A <[content]>* \Z
505             }xms;
506 19 50       120 if ( $str =~ $q->with_actions( new Soy::Actions:: ) ) {
507 19         80 my $raw_tree = {%/};
508              
509             #setup filename and offsets
510 4     4   1905 use Plosurin::Utl::SetLinePos;
  4         12  
  4         1961  
511             my $line_num_visiter = new Plosurin::Utl::SetLinePos::
512             srcfile => $self->{srcfile},
513 19         164 offset => $self->{offset};
514 19         80 $line_num_visiter->visit( $raw_tree->{content} );
515              
516             #check errors
517 19         121 return $raw_tree;
518             }
519             else {
520 0         0 "bad template";
521             }
522             }
523              
524             =head2 raw
525              
526             return syntax tree
527              
528             =cut
529              
530             sub raw_tree {
531 19 50   19 0 113 $_[0]->{_tree} || {};
532             }
533              
534             =head2 reduce_tree
535              
536             Union raw_text nodes
537              
538             =cut
539              
540             sub reduced_tree {
541 19     19 0 87 my $self = shift;
542 19   50     53 my $tree = shift || $self->raw_tree->{content} || return [];
543 19         38 my @res = ();
544 19         40 my @tmp = @$tree; #copy for protect from modify orig tree
545 19         51 while ( my $node = shift @tmp ) {
546              
547             #skip first node
548             #skip all non text nodes
549 20 50 66     79 if ( ref( $node->{obj} ) ne 'Soy::raw_text' || scalar(@res) == 0 ) {
550             ## if ( my $sub_tree = $node->{obj}->childs ) {
551             ## $node->{obj}->childs( $self->reduced_tree($sub_tree) );
552             ###### $self->reduced_tree($sub_tree);
553             # }
554 20         42 push @res, $node;
555 20         54 next;
556             }
557 0         0 my $prev = pop @res;
558 0 0       0 unless ( ref( $prev->{obj} ) eq 'Soy::raw_text' ) {
559 0         0 push @res, $prev;
560             }
561             else {
562              
563             #now union !
564             $node->{obj} = Soy::raw_text->new(
565 0         0 { '' => $prev->{obj}->{''} . $node->{obj}->{''} } );
566 0         0 $node->{matchline} = $prev->{matchline};
567 0         0 $node->{matchpos} = $node->{matchpos};
568             }
569 0         0 push @res, $node;
570             }
571 19         50 \@res;
572             }
573              
574             =head2 dump_tree($obj1 [, $objn])
575              
576             Minimalistic tree
577             return [ "clasname", {key1=>key2} ]
578              
579             =cut
580              
581             sub dump_tree {
582 15     15 1 47 my $self = shift;
583 15         22 my @res = ();
584 15 50       24 foreach my $rec ( @{ shift || [] } ) {
  15         38  
585 15         27 my $obj = $rec->{obj};
586 15         63 push @res, { ref($obj) => $obj->dump() };
587             }
588 15         34 \@res;
589             }
590             1;
591             __END__
592              
593             =head1 SEE ALSO
594              
595             Closure Templates Documentation L<http://code.google.com/closure/templates/docs/overview.html>
596              
597             Perl 6 implementation L<https://github.com/zag/plosurin>
598              
599              
600             =head1 AUTHOR
601              
602             Zahatski Aliaksandr, <zag@cpan.org>
603              
604             =head1 COPYRIGHT AND LICENSE
605              
606             Copyright (C) 2011 by Zahatski Aliaksandr
607              
608             This library is free software; you can redistribute it and/or modify
609             it under the same terms as Perl itself.
610              
611             =cut
612