File Coverage

blib/lib/Template/Tiny.pm
Criterion Covered Total %
statement 53 59 89.8
branch 19 24 79.1
condition 5 6 83.3
subroutine 9 9 100.0
pod 2 3 66.6
total 88 101 87.1


line stmt bran cond sub pod time code
1             package Template::Tiny;
2              
3             # Load overhead: 40k
4              
5 4     4   97435 use 5.00503;
  4         15  
  4         174  
6 4     4   26 use strict;
  4         9  
  4         5194  
7              
8             $Template::Tiny::VERSION = '1.12';
9              
10             # Evaluatable expression
11             my $EXPR = qr/ [a-z_][\w.]* /xs;
12              
13             # Opening [% tag including whitespace chomping rules
14             my $LEFT = qr/
15             (?:
16             (?: (?:^|\n) [ \t]* )? \[\%\-
17             |
18             \[\% \+?
19             ) \s*
20             /xs;
21              
22             # Closing %] tag including whitespace chomping rules
23             my $RIGHT = qr/
24             \s* (?:
25             \+? \%\]
26             |
27             \-\%\] (?: [ \t]* \n )?
28             )
29             /xs;
30              
31             # Preparsing run for nesting tags
32             my $PREPARSE = qr/
33             $LEFT ( IF | UNLESS | FOREACH ) \s+
34             (
35             (?: \S+ \s+ IN \s+ )?
36             \S+ )
37             $RIGHT
38             (?!
39             .*?
40             $LEFT (?: IF | UNLESS | FOREACH ) \b
41             )
42             ( .*? )
43             (?:
44             $LEFT ELSE $RIGHT
45             (?!
46             .*?
47             $LEFT (?: IF | UNLESS | FOREACH ) \b
48             )
49             ( .+? )
50             )?
51             $LEFT END $RIGHT
52             /xs;
53              
54             # Condition set
55             my $CONDITION = qr/
56             \[\%\s
57             ( ([IUF])\d+ ) \s+
58             (?:
59             ([a-z]\w*) \s+ IN \s+
60             )?
61             ( $EXPR )
62             \s\%\]
63             ( .*? )
64             (?:
65             \[\%\s \1 \s\%\]
66             ( .+? )
67             )?
68             \[\%\s \1 \s\%\]
69             /xs;
70              
71             sub new {
72 13     13 1 28206 bless { @_[1..$#_] }, $_[0];
73             }
74              
75             # Copy and modify
76             sub preprocess {
77 3     3 0 7 my $self = shift;
78 3         6 my $text = shift;
79 3         12 $self->_preprocess(\$text);
80 3         11 return $text;
81             }
82              
83             sub process {
84 10     10 1 4619 my $self = shift;
85 10         19 my $copy = ${shift()};
  10         24  
86 10   50     41 my $stash = shift || {};
87              
88 10         18 local $@ = '';
89 10         39 local $^W = 0;
90              
91             # Preprocess to establish unique matching tag sets
92 10         32 $self->_preprocess( \$copy );
93              
94             # Process down the nested tree of conditions
95 10         41 my $result = $self->_process( $stash, $copy );
96 10 50       27 if ( @_ ) {
    0          
97 10         16 ${$_[0]} = $result;
  10         47  
98             } elsif ( defined wantarray ) {
99 0         0 require Carp;
100 0         0 Carp::carp('Returning of template results is deprecated in Template::Tiny 0.11');
101 0         0 return $result;
102             } else {
103 0         0 print $result;
104             }
105             }
106              
107              
108              
109              
110              
111             ######################################################################
112             # Support Methods
113              
114             # The only reason this is a standalone is so we can
115             # do more in-depth testing.
116             sub _preprocess {
117 13     13   22 my $self = shift;
118 13         21 my $copy = shift;
119              
120             # Preprocess to establish unique matching tag sets
121 13         17 my $id = 0;
122 13         1691 1 while $$copy =~ s/
123             $PREPARSE
124             /
125 20         71 my $tag = substr($1, 0, 1) . ++$id;
126 20 100       2099 "\[\% $tag $2 \%\]$3\[\% $tag \%\]"
127             . (defined($4) ? "$4\[\% $tag \%\]" : '');
128             /sex;
129             }
130              
131             sub _process {
132 30     30   77 my ($self, $stash, $text) = @_;
133              
134 30         403 $text =~ s/
135             $CONDITION
136             /
137             ($2 eq 'F')
138             ? $self->_foreach($stash, $3, $4, $5)
139 18 100       58 : eval {
    100          
140 16   100     45 $2 eq 'U'
141             xor
142             !! # Force boolification
143             $self->_expression($stash, $4)
144             }
145             ? $self->_process($stash, $5)
146             : $self->_process($stash, $6)
147             /gsex;
148              
149             # Resolve expressions
150 30         410 $text =~ s/
151             $LEFT ( $EXPR ) $RIGHT
152             /
153 34         60 eval {
154 34         75 $self->_expression($stash, $1)
155             . '' # Force stringification
156             }
157             /gsex;
158              
159             # Trim the document
160 30 100       106 $text =~ s/^\s*(.+?)\s*\z/$1/s if $self->{TRIM};
161              
162 30         446 return $text;
163             }
164              
165             # Special handling for foreach
166             sub _foreach {
167 2     2   9 my ($self, $stash, $term, $expr, $text) = @_;
168              
169             # Resolve the expression
170 2         6 my $list = $self->_expression($stash, $expr);
171 2 50       10 unless ( ref $list eq 'ARRAY' ) {
172 0         0 return '';
173             }
174              
175             # Iterate
176 4         22 return join '', map {
177 2         4 $self->_process( { %$stash, $term => $_ }, $text )
178             } @$list;
179             }
180              
181             # Evaluates a stash expression
182             sub _expression {
183 52     52   69 my $cursor = $_[1];
184 52         167 my @path = split /\./, $_[2];
185 52         101 foreach ( @path ) {
186             # Support for private keys
187 74 100       183 return undef if substr($_, 0, 1) eq '_';
188              
189             # Split by data type
190 72         110 my $type = ref $cursor;
191 72 100       171 if ( $type eq 'ARRAY' ) {
    100          
    50          
192 5 100       19 return '' unless /^(?:0|[0-9]\d*)\z/;
193 4         10 $cursor = $cursor->[$_];
194             } elsif ( $type eq 'HASH' ) {
195 65         170 $cursor = $cursor->{$_};
196             } elsif ( $type ) {
197 2         9 $cursor = $cursor->$_();
198             } else {
199 0         0 return '';
200             }
201             }
202 49         426 return $cursor;
203             }
204              
205             1;
206              
207             __END__