File Coverage

blib/lib/Plosurin/SoyTree.pm
Criterion Covered Total %
statement 370 393 94.1
branch 28 44 63.6
condition 15 28 53.5
subroutine 111 115 96.5
pod 3 5 60.0
total 527 585 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   107446 use strict;
  4         25  
  4         129  
24 4     4   23 use warnings;
  4         9  
  4         107  
25 4     4   58 use v5.10;
  4         14  
26 4     4   629 use Data::Dumper;
  4         6868  
  4         512  
27             our $VERSION = '0.01';
28              
29             sub new {
30 19     19   39 my $class = shift;
31 19 50 33     146 bless( ( $#_ == 0 ) ? shift : {@_}, ref($class) || $class );
32             }
33              
34             1;
35              
36             package Soy::base;
37 4     4   28 use Data::Dumper;
  4         8  
  4         1423  
38             our $VERSION = '0.01';
39              
40             sub new {
41 413     413   762 my $class = shift;
42 413 50 33     8469 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     157 my $attr = $self->{attribute} || [];
57 61         120 my %attr = ();
58 61         106 foreach my $rec (@$attr) {
59 9         23 $attr{ $rec->{name} } = $rec->{value};
60             }
61 61         200 return \%attr;
62             }
63              
64             sub childs {
65 60     60   85 my $self = shift;
66 60 50       109 if (@_) {
67 0         0 $self->{content} = shift;
68             }
69 60 100       144 return [] unless exists $self->{content};
70 22         28 [ @{ $self->{content} } ];
  22         54  
71             }
72              
73             sub dump {
74 57     57   75 my $self = shift;
75 57         119 my $childs = $self->childs;
76 57         81 my $res = {};
77 57 100       104 if ( scalar(@$childs) ) {
78             $res->{childs} = [
79             map {
80 20         37 { ref( $_->{obj} ) => $_->{obj}->dump }
81 24         62 } @$childs
82             ];
83             }
84 57 100       83 if ( scalar( keys %{ $self->attrs } ) ) {
  57         114  
85 3         8 $res->{attrs} = $self->attrs;
86             }
87              
88 57         223 $res;
89              
90             }
91             1;
92              
93             package Soy::command_print;
94 4     4   32 use base 'Soy::base';
  4         8  
  4         1782  
95             our $VERSION = '0.01';
96             1;
97              
98             package Soy::raw_text;
99 4     4   32 use base 'Soy::base';
  4         9  
  4         1153  
100             our $VERSION = '0.01';
101             1;
102              
103             package Soy::command_elseif;
104 4     4   31 use base 'Soy::base';
  4         11  
  4         1043  
105 4     4   29 use Data::Dumper;
  4         9  
  4         178  
106 4     4   22 use strict;
  4         9  
  4         95  
107 4     4   28 use warnings;
  4         10  
  4         457  
108             our $VERSION = '0.01';
109              
110             sub dump {
111 4     4   7 my $self = shift;
112 4         11 return { %{ $self->SUPER::dump() },
113 4         6 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         1063  
119 4     4   27 use strict;
  4         8  
  4         92  
120 4     4   20 use warnings;
  4         8  
  4         105  
121 4     4   21 use Data::Dumper;
  4         9  
  4         453  
122             our $VERSION = '0.01';
123              
124             sub dump {
125 3     3   7 my $self = shift;
126 3         10 my $res = $self->SUPER::dump;
127 3         9 $res->{template} = $self->{tmpl_name};
128 3         7 $res;
129             }
130             1;
131              
132             package Soy::command_call;
133 4     4   61 use Plosurin::SoyTree;
  4         20  
  4         122  
134 4     4   21 use base 'Soy::command_call_self';
  4         19  
  4         1186  
135 4     4   43 use strict;
  4         7  
  4         84  
136 4     4   19 use warnings;
  4         8  
  4         236  
137             our $VERSION = '0.01';
138             1;
139              
140             package Soy::command_else;
141 4     4   26 use base 'Soy::base';
  4         7  
  4         1151  
142 4     4   29 use strict;
  4         7  
  4         84  
143 4     4   20 use warnings;
  4         7  
  4         282  
144             our $VERSION = '0.01';
145             1;
146              
147             package Soy::command_if;
148 4     4   24 use base 'Soy::base';
  4         9  
  4         1045  
149 4     4   29 use strict;
  4         8  
  4         68  
150 4     4   30 use warnings;
  4         15  
  4         150  
151 4     4   54 use v5.10;
  4         15  
152 4     4   30 use Data::Dumper;
  4         16  
  4         946  
153             our $VERSION = '0.01';
154              
155             sub dump {
156 5     5   12 my $self = shift;
157 5         11 my %ifs = ();
158             $ifs{'if'} =
159 5         7 { %{ $self->SUPER::dump }, expression => $self->{expression}->dump, };
  5         19  
160 5 100       18 if ( exists $self->{commands_elseif} ) {
161 3         8 my $elseifs = $self->{commands_elseif};
162             $ifs{elseif} = [
163             map {
164 3         6 { ref($_) => $_->dump }
  4         11  
165             } @$elseifs
166             ];
167              
168             }
169 5 100       16 if ( my $elseif = $self->{command_else} ) {
170              
171 4         13 $ifs{else} = { ref($elseif) => $elseif->dump() };
172             }
173              
174 5         15 \%ifs;
175             }
176             1;
177              
178             package Soy::command_param;
179 4     4   30 use base 'Soy::base';
  4         8  
  4         1023  
180 4     4   27 use warnings;
  4         9  
  4         94  
181 4     4   19 use strict;
  4         7  
  4         120  
182 4     4   37 use Data::Dumper;
  4         8  
  4         855  
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         10  
198 4 100       14 $res{value} = $self->{value} if exists $self->{value};
199 4         12 \%res;
200             }
201              
202             package Soy::command_param_self;
203 4     4   31 use base 'Soy::command_param';
  4         8  
  4         1394  
204             our $VERSION = '0.01';
205             1;
206              
207             package Soy::Node;
208             our $VERSION = '0.01';
209 4     4   29 use base 'Soy::base';
  4         8  
  4         1488  
210              
211             sub childs {
212 78     78   220 [ $_[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   29 use strict;
  4         7  
  4         109  
222 4     4   28 use warnings;
  4         7  
  4         204  
223             our $VERSION = '0.01';
224 4     4   32 use base 'Soy::base';
  4         7  
  4         1108  
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   29 use strict;
  4         7  
  4         85  
266 4     4   18 use warnings;
  4         9  
  4         122  
267 4     4   22 use base 'Soy::base';
  4         7  
  4         1859  
268             our $VERSION = '0.01';
269              
270             sub get_var_name {
271 1     1   3 my $self = shift;
272 1         3 my $name = $self->{local_var}->{''};
273 1 50       11 $name =~ /\$(\w+)/ ? $1 : undef;
274             }
275              
276             sub get_ifempty {
277 2     2   4 my $self = shift;
278 2         8 $self->{command_foreach_ifempty};
279             }
280              
281             sub dump {
282 2     2   5 my $self = shift;
283             my %res = (
284 2         4 %{ $self->SUPER::dump() },
  2         7  
285              
286             # expression => $self->{expression}
287             );
288 2 100       10 if ( exists $self->{command_foreach_ifempty} ) {
289 1         4 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   34 use strict;
  4         9  
  4         94  
298 4     4   31 use warnings;
  4         15  
  4         148  
299 4     4   23 use base 'Soy::base';
  4         8  
  4         1141  
300             our $VERSION = '0.01';
301             1;
302              
303             package Soy::expressiong;
304 4     4   29 use strict;
  4         10  
  4         87  
305 4     4   20 use warnings;
  4         9  
  4         1964  
306 4     4   2638 use Regexp::Grammars;
  4         36826  
  4         35  
307 4     4   2144 use Plosurin::Grammar;
  4         14  
  4         189  
308 4     4   2144 use Plosurin::Utl::ExpMapVariables;
  4         13  
  4         108  
309 4     4   26 use Data::Dumper;
  4         6  
  4         187  
310 4     4   24 use base 'Soy::base';
  4         8  
  4         1298  
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   759 my $self = shift;
324 5         10 my $var_map = shift;
325 5         14 my $template_params = shift;
326 5         15 my $txt = $self->{''};
327 5         35 my $q = qr{
328             <extends: Plosurin::Exp::Grammar>
329             <nocontext:>
330             <expr>
331             }xms;
332 5 50       148 if ( $txt =~ $q ) {
333 5         19 my $tree = $/{expr};
334 5         62 my $p = new Plosurin::Utl::ExpMapVariables(
335             vars => $var_map,
336             params => $template_params
337             );
338 5         29 $p->visit($tree);
339 5         55 return $tree;
340             }
341 0         0 else { return "BAD" }
342             }
343              
344              
345             package Exp::base;
346 4     4   124 use Data::Dumper;
  4         7  
  4         229  
347 4     4   26 use base 'Soy::base';
  4         8  
  4         1751  
348             our $VERSION = '0.01';
349              
350             sub new {
351 1605     1605   2943 my $class = shift;
352 1605 50 33     34723 bless( ( $#_ == 0 ) ? shift : {@_}, ref($class) || $class );
353             }
354              
355             sub childs {
356 8     8   15 my $self = shift;
357 8         35 return [];
358             }
359              
360             sub as_perl5 {
361 0     0   0 my $self = shift;
362 0         0 die "Method as_perl5 not implemented for " . ref($self);
363             }
364              
365             package Exp::Var;
366 4     4   33 use strict;
  4         9  
  4         95  
367 4     4   23 use warnings;
  4         10  
  4         103  
368 4     4   59 use Data::Dumper;
  4         9  
  4         174  
369 4     4   24 use base 'Exp::base';
  4         8  
  4         1542  
370             our $VERSION = '0.01';
371              
372             sub as_perl5 {
373 4     4   9 my $self = shift;
374 4         30 return "\$$self->{Ident}";
375             }
376              
377             package Exp::Digit;
378 4     4   32 use strict;
  4         8  
  4         92  
379 4     4   23 use warnings;
  4         8  
  4         106  
380 4     4   20 use Data::Dumper;
  4         43  
  4         171  
381 4     4   24 use base 'Exp::base';
  4         7  
  4         1343  
382             our $VERSION = '0.01';
383              
384             sub as_perl5 {
385 6     6   9 my $self = shift;
386 6         29 return $self->{''};
387             }
388              
389             package Exp::add;
390 4     4   31 use strict;
  4         8  
  4         102  
391 4     4   21 use warnings;
  4         7  
  4         119  
392 4     4   23 use Data::Dumper;
  4         7  
  4         193  
393 4     4   25 use base 'Exp::base';
  4         7  
  4         1455  
394             our $VERSION = '0.01';
395              
396             sub as_perl5 {
397 3     3   4 my $self = shift;
398 3         8 return $self->{a}->as_perl5() . $self->{op} . $self->{b}->as_perl5();
399             }
400              
401             sub childs {
402 3     3   5 my $self = shift;
403 3         10 return [ $self->{a}, $self->{b} ];
404             }
405              
406             package Exp::mult;
407 4     4   29 use strict;
  4         7  
  4         110  
408 4     4   21 use warnings;
  4         6  
  4         142  
409 4     4   24 use Data::Dumper;
  4         6  
  4         188  
410 4     4   26 use base 'Exp::add';
  4         8  
  4         1289  
411             our $VERSION = '0.01';
412             1;
413              
414             package Exp::String;
415 4     4   29 use strict;
  4         8  
  4         87  
416 4     4   21 use warnings;
  4         7  
  4         132  
417 4     4   24 use Data::Dumper;
  4         8  
  4         182  
418 4     4   23 use base 'Exp::base';
  4         16  
  4         1520  
419             our $VERSION = '0.01';
420              
421             sub as_perl5 {
422 2     2   3 my $self = shift;
423 2         7 return "'$self->{value}'";
424             }
425              
426             package Exp::list;
427 4     4   29 use strict;
  4         10  
  4         153  
428 4     4   23 use warnings;
  4         8  
  4         110  
429 4     4   19 use Data::Dumper;
  4         11  
  4         219  
430 4     4   27 use base 'Exp::base';
  4         11  
  4         1638  
431             our $VERSION = '0.01';
432              
433              
434             sub childs {
435 4     4   8 my $self = shift;
436 4 50       14 if (@_) {
437 0         0 $self->{expr} = \@_;
438             }
439 4         13 return $self->{expr};
440             }
441              
442             sub as_perl5 {
443 2     2   13 my $self = shift;
444 2         6 return '[' . join( ",", map { $_->as_perl5() } @{ $self->childs } ) . "]";
  6         25  
  2         7  
445             }
446              
447             package Plosurin::SoyTree;
448 4     4   30 use strict;
  4         7  
  4         202  
449 4     4   31 use warnings;
  4         10  
  4         128  
450 4     4   54 use v5.10;
  4         15  
451 4     4   28 use Data::Dumper;
  4         7  
  4         182  
452 4     4   25 use Plosurin::Grammar;
  4         6  
  4         115  
453 4     4   21 use Regexp::Grammars;
  4         9  
  4         31  
454 4     4   2909 use version; our $VERSION = qv('0.0.1');
  4         7743  
  4         24  
455              
456             =head2 new
457              
458             my $st = new Plosurin::SoyTree(
459             src => "txt",
460             srcfile=>"filesrc",
461             offset=>0
462             );
463              
464             =cut
465              
466             sub new {
467 19     19 1 410 my $class = shift;
468 19 50 33     148 my $self = bless( ( $#_ == 0 ) ? shift : {@_}, ref($class) || $class );
469 19   100     96 $self->{srcfile} //= "UNKNOWN";
470 19   100     68 $self->{offset} //= 0;
471 19 50       57 if ( my $src = $self->{src} ) {
472 19 50       52 unless ( $self->{_tree} = $self->parse($src) ) { return $self->{_tree} }
  0         0  
473             }
474 19         64 $self;
475             }
476              
477             =head2 parse
478              
479             return [node1, node2]
480              
481             =cut
482              
483             sub parse {
484 19     19 1 32 my $self = shift;
485 19   50     44 my $str = shift || return [];
486 19   33     256 my $q = shift || qr{
487             <extends: Plosurin::Grammar>
488             # <debug:step>
489             \A <[content]>* \Z
490             }xms;
491 19 50       148 if ( $str =~ $q->with_actions( new Soy::Actions:: ) ) {
492 19         83 my $raw_tree = {%/};
493              
494             #setup filename and offsets
495 4     4   2140 use Plosurin::Utl::SetLinePos;
  4         12  
  4         1841  
496             my $line_num_visiter = new Plosurin::Utl::SetLinePos::
497             srcfile => $self->{srcfile},
498 19         167 offset => $self->{offset};
499 19         81 $line_num_visiter->visit( $raw_tree->{content} );
500              
501             #check errors
502 19         123 return $raw_tree;
503             }
504             else {
505 0         0 "bad template";
506             }
507             }
508              
509             =head2 raw
510              
511             return syntax tree
512              
513             =cut
514              
515             sub raw_tree {
516 19 50   19 0 111 $_[0]->{_tree} || {};
517             }
518              
519             =head2 reduce_tree
520              
521             Union raw_text nodes
522              
523             =cut
524              
525             sub reduced_tree {
526 19     19 0 93 my $self = shift;
527 19   50     56 my $tree = shift || $self->raw_tree->{content} || return [];
528 19         44 my @res = ();
529 19         39 my @tmp = @$tree; #copy for protect from modify orig tree
530 19         55 while ( my $node = shift @tmp ) {
531              
532             #skip first node
533             #skip all non text nodes
534 20 50 66     74 if ( ref( $node->{obj} ) ne 'Soy::raw_text' || scalar(@res) == 0 ) {
535             ## if ( my $sub_tree = $node->{obj}->childs ) {
536             ## $node->{obj}->childs( $self->reduced_tree($sub_tree) );
537             ###### $self->reduced_tree($sub_tree);
538             # }
539 20         46 push @res, $node;
540 20         56 next;
541             }
542 0         0 my $prev = pop @res;
543 0 0       0 unless ( ref( $prev->{obj} ) eq 'Soy::raw_text' ) {
544 0         0 push @res, $prev;
545             }
546             else {
547              
548             #now union !
549             $node->{obj} = Soy::raw_text->new(
550 0         0 { '' => $prev->{obj}->{''} . $node->{obj}->{''} } );
551 0         0 $node->{matchline} = $prev->{matchline};
552 0         0 $node->{matchpos} = $node->{matchpos};
553             }
554 0         0 push @res, $node;
555             }
556 19         54 \@res;
557             }
558              
559             =head2 dump_tree($obj1 [, $objn])
560              
561             Minimalistic tree
562             return [ "clasname", {key1=>key2} ]
563              
564             =cut
565              
566             sub dump_tree {
567 15     15 1 48 my $self = shift;
568 15         25 my @res = ();
569 15 50       22 foreach my $rec ( @{ shift || [] } ) {
  15         37  
570 15         26 my $obj = $rec->{obj};
571 15         57 push @res, { ref($obj) => $obj->dump() };
572             }
573 15         39 \@res;
574             }
575             1;
576             __END__
577              
578             =head1 SEE ALSO
579              
580             Closure Templates Documentation L<http://code.google.com/closure/templates/docs/overview.html>
581              
582             Perl 6 implementation L<https://github.com/zag/plosurin>
583              
584              
585             =head1 AUTHOR
586              
587             Zahatski Aliaksandr, <zag@cpan.org>
588              
589             =head1 COPYRIGHT AND LICENSE
590              
591             Copyright (C) 2011 by Zahatski Aliaksandr
592              
593             This library is free software; you can redistribute it and/or modify
594             it under the same terms as Perl itself.
595              
596             =cut
597