File Coverage

blib/lib/Template/Alloy.pm
Criterion Covered Total %
statement 541 601 90.0
branch 391 502 77.8
condition 232 337 68.8
subroutine 37 39 94.8
pod 21 28 75.0
total 1222 1507 81.0


line stmt bran cond sub pod time code
1             package Template::Alloy;
2              
3             ###----------------------------------------------------------------###
4             # See the perldoc in Template/Alloy.pod #
5             # Copyright 2007 - 2013 - Paul Seamons #
6             # Distributed under the Perl Artistic License without warranty #
7             ###----------------------------------------------------------------###
8              
9 10     10   9970 use strict;
  10         23  
  10         357  
10 10     10   60 use warnings;
  10         18  
  10         304  
11 10     10   5253 use Template::Alloy::Exception;
  10         28  
  10         331  
12 10     10   5943 use Template::Alloy::Operator qw(play_operator define_operator);
  10         28  
  10         928  
13 10     10   7195 use Template::Alloy::VMethod qw(define_vmethod $SCALAR_OPS $ITEM_OPS $ITEM_METHODS $FILTER_OPS $LIST_OPS $HASH_OPS $VOBJS);
  10         31  
  10         10262  
14              
15             our $VERSION = '1.022';
16              
17             our $QR_PRIVATE = qr/^[_.]/;
18             our $WHILE_MAX = 1000;
19             our $MAX_EVAL_RECURSE = 50;
20             our $MAX_MACRO_RECURSE = 50;
21             our $STAT_TTL = 1;
22             our $QR_INDEX = '(?:\d*\.\d+ | \d+)';
23             our @CONFIG_COMPILETIME = qw(SYNTAX CACHE_STR_REFS ANYCASE INTERPOLATE PRE_CHOMP POST_CHOMP ENCODING
24             SEMICOLONS V1DOLLAR V2PIPE V2EQUALS AUTO_EVAL SHOW_UNDEFINED_INTERP AUTO_FILTER);
25             our @CONFIG_RUNTIME = qw(ADD_LOCAL_PATH CALL_CONTEXT DUMP VMETHOD_FUNCTIONS STRICT);
26             our $EVAL_CONFIG = {map {$_ => 1} @CONFIG_COMPILETIME, @CONFIG_RUNTIME};
27             our $EXTRA_COMPILE_EXT = '.sto';
28             our $PERL_COMPILE_EXT = '.pl';
29             our $JS_COMPILE_EXT = '.js';
30             our $GLOBAL_CACHE = {};
31              
32             ###----------------------------------------------------------------###
33              
34             our $AUTOROLE = {
35             Compile => [qw(load_perl compile_template compile_tree compile_expr)],
36             HTE => [qw(parse_tree_hte param output register_function clear_param query new_file new_scalar_ref new_array_ref new_filehandle)],
37             Parse => [qw(parse_tree parse_expr apply_precedence parse_args dump_parse_tree dump_parse_expr define_directive define_syntax)],
38             Play => [qw(play_tree _macro_sub)],
39             Stream => [qw(stream_tree)],
40             JS => [qw(load_js compile_template_js compile_tree_js play_js js_context process_js parse_tree_js process_jsr parse_tree_jsr)],
41             TT => [qw(parse_tree_tt3 process)],
42             Tmpl => [qw(parse_tree_tmpl set_delimiters set_strip set_value set_values parse_string set_dir parse_file loop_iteration fetch_loop_iteration)],
43             Velocity => [qw(parse_tree_velocity merge)],
44             };
45             my $ROLEMAP = { map { my $type = $_; map { ($_ => $type) } @{ $AUTOROLE->{$type} } } keys %$AUTOROLE };
46             my %STANDIN = ('Template' => 'TT', 'Template::Toolkit' => 'TT', 'HTML::Template' => 'HTE', 'HTML::Template::Expr' => 'HTE', 'Text::Tmpl' => 'Tmpl');
47              
48             our $AUTOLOAD;
49             sub AUTOLOAD {
50 43     43   936 my $self = shift;
51 43 100 66     595 my $meth = ($AUTOLOAD && $AUTOLOAD =~ /::(\w+)$/) ? $1 : $self->throw('autoload', "Invalid method $AUTOLOAD");
52 41 100       162 if (! $self->can($meth)) {
53 1         6 require Carp;
54 1         121 Carp::croak("Can't locate object method \"$meth\" via package ".ref($self));
55             }
56 40         227 return $self->$meth(@_);
57             }
58              
59             sub can {
60 42     42 0 1025 my ($self, $meth) = @_;
61 42 100       275 __PACKAGE__->import($ROLEMAP->{$meth}) if $ROLEMAP->{$meth};
62 42         412 return $self->SUPER::can($meth);
63             }
64              
65       0     sub DESTROY {}
66              
67             sub import {
68 126     126   8697 my $class = shift;
69 126         335 foreach my $item (@_) {
70 78 100       366 next if $item =~ /^(load|1)$/i;
71 72 100       244 if (lc $item eq 'all') {
72 2         6 local $AUTOROLE->{'JS'}; delete $AUTOROLE->{'JS'};
  2         5  
73 2         11 return $class->import(keys %$AUTOROLE);
74             }
75              
76 70         117 my $type;
77 70 100       207 if ($type = $STANDIN{$item}) {
78 7         31 (my $file = "$item.pm") =~ s|::|/|g;
79 7 100 100     46 if (! $INC{$file} || ! $item->isa(__PACKAGE__)) {
80 4 100       11 if ($INC{$file}) { require Carp; Carp::croak("Class $item is already loaded - can't override") }
  1         5  
  1         183  
81 3         255 eval "{package $item; our \@ISA = qw(".__PACKAGE__.");}";
82 3         21 $INC{$file} = __FILE__;
83 3 50       13 next if ! $AUTOROLE->{$type}; # already imported
84             }
85             }
86 69 100 66     386 $type ||= $AUTOROLE->{$item} ? $item : $ROLEMAP->{$item} || do { require Carp; Carp::croak("Invalid import option \"$item\"") };
      66        
87              
88 68         177 my $pkg = __PACKAGE__."::$type";
89 68         339 (my $file = "$pkg.pm") =~ s|::|/|g;
90 68         36666 require $file;
91              
92 10     10   93 no strict 'refs';
  10         27  
  10         78798  
93 68         218 *{__PACKAGE__."::$_"} = \&{"$pkg\::$_"} for @{ $AUTOROLE->{$type} };
  68         349  
  211         962  
  211         726  
94 68         292 $AUTOROLE->{$type} = [];
95             }
96 122         39890 return 1;
97             }
98              
99             ###----------------------------------------------------------------###
100              
101             sub new {
102 4301     4301 1 2097181 my $class = shift;
103 4301 100       17414 my $args = ref($_[0]) ? { %{ shift() } } : {@_};
  1         5  
104              
105             ### allow for lowercase args
106 4301 100       16717 if (my @keys = grep {/^[a-z][a-z_]+$/} keys %$args) {
  5377         26351  
107 253         483 @{ $args }{ map { uc $_ } @keys } = delete @{ $args }{ @keys };
  253         769  
  753         1556  
  253         696  
108             }
109              
110 4301         13974 return bless $args, $class;
111             }
112              
113             ###----------------------------------------------------------------###
114              
115 0     0 0 0 sub run { shift->process_simple(@_) }
116              
117             sub process_simple {
118 773     773 1 2589 my $self = shift;
119 773   100     1598 my $in = shift || die "Missing input";
120 772   100     1476 my $swap = shift || die "Missing variable hash";
121 771   66     1484 my $out = shift || ($self->{'STREAM'} ? \ "" : die "Missing output string ref");
122 770         1277 delete $self->{'error'};
123              
124 770         1447 eval {
125 770         1160 delete $self->{'_debug_off'};
126 770         1073 delete $self->{'_debug_format'};
127 770         1460 local $self->{'_start_top_level'} = 1;
128 770         1867 $self->_process($in, $swap, $out);
129             };
130 770 100       1888 if (my $err = $@) {
131 40 50 0     101 if ($err->type !~ /stop|return|next|last|break/) {
    0          
132 40         110 $self->{'error'} = $err;
133 40 50       102 die $err if $self->{'RAISE_ERROR'};
134 40         191 return;
135             } elsif ($err->type eq 'return' && UNIVERSAL::isa($err->info, 'HASH')) {
136 0         0 return $err->info->{'return_val'};
137             }
138             }
139 730         2075 return 1;
140             }
141              
142             sub _process {
143 5350     5350   9072 my $self = shift;
144 5350         7737 my $file = shift;
145 5350   100     14233 local $self->{'_vars'} = shift || {};
146 5350   66     10335 my $out_ref = shift || $self->throw('undef', "Missing output ref");
147 5349         11965 local $self->{'_top_level'} = delete $self->{'_start_top_level'};
148 5349         9926 my $i = length $$out_ref;
149              
150             ### parse and execute
151 5349         7735 my $doc;
152 5349         7470 eval {
153 5349 100       17498 $doc = (ref($file) eq 'HASH') ? $file : $self->load_template($file);
154              
155             ### prevent recursion
156             $self->throw('file', "recursion into '$doc->{name}'")
157 5173 100 100     27018 if ! $self->{'RECURSION'} && $self->{'_in'}->{$doc->{'name'}} && $doc->{'name'} ne 'input text';
      100        
158              
159 5167         15007 local $self->{'_in'}->{$doc->{'name'}} = 1;
160 5167         10436 local $self->{'_component'} = $doc;
161 5167 100       14490 local $self->{'_template'} = $self->{'_top_level'} ? $doc : $self->{'_template'};
162 5167         9772 local @{ $self }{@CONFIG_RUNTIME} = @{ $self }{@CONFIG_RUNTIME};
  5167         23689  
  5167         15435  
163              
164             ### run the document however we can
165 5167 100       16600 if ($self->{'STREAM'}) {
    50          
    100          
    100          
166 1356 50       3341 $self->throw('process', 'No _tree found') if ! $doc->{'_tree'};
167 1356         5027 $self->stream_tree($doc->{'_tree'});
168             } elsif ($self->{'COMPILE_JS'}) {
169 0         0 $self->play_js($doc, $out_ref);
170             } elsif ($doc->{'_perl'}) {
171 1869         47633 $doc->{'_perl'}->{'code'}->($self, $out_ref);
172             } elsif ($doc->{'_tree'}) {
173 1941         6782 $self->play_tree($doc->{'_tree'}, $out_ref);
174             } else {
175 1         3 $self->throw('process', 'No _perl and no _tree found');
176             }
177              
178             ### trim whitespace from the beginning and the end of a block or template
179 4972 100       27121 if ($self->{'TRIM'}) {
180 27         125 substr($$out_ref, $i, length($$out_ref) - $i) =~ s{ \s+ $ }{}x; # tail first
181 27         172 substr($$out_ref, $i, length($$out_ref) - $i) =~ s{ ^ \s+ }{}x;
182             }
183             };
184              
185             ### handle exceptions
186 5349 100       13586 if (my $err = $@) {
187 377 100       1248 $err = $self->exception('undef', $err) if ! UNIVERSAL::can($err, 'type');
188 377 100 66     1957 $err->doc($doc) if $doc && $err->can('doc') && ! $err->doc;
      100        
189 377 100       1262 die $err if ! $self->{'_top_level'};
190 273 100 66     735 die $err if $err->type ne 'stop' && ($err->type ne 'return' || $err->info);
      66        
191             }
192              
193 5010         20496 return 1;
194             }
195              
196             ###----------------------------------------------------------------###
197              
198             sub load_template {
199 5381     5381 1 11852 my ($self, $file) = @_;
200 5381 100       11407 $self->throw('undef', 'Undefined file passed to load_template') if ! defined $file;
201              
202 5380   66     24576 my $docs = $self->{'GLOBAL_CACHE'} || ($self->{'_documents'} ||= {});
203 5380 100       11582 $docs = $GLOBAL_CACHE if ! ref $docs;
204              
205             ### looks like a scalar ref
206 5380         8684 my $doc;
207 5380 100       12649 if (ref $file) {
    100          
    100          
    100          
208 4581 100       10403 return $file if ref $file eq 'HASH';
209              
210 4580 100 66     13484 if (! defined($self->{'CACHE_STR_REFS'}) || $self->{'CACHE_STR_REFS'}) {
211 4577         10120 my $_file = $self->string_id($file);
212 4577 100       12875 if ($docs->{$_file}) { # no-ttl necessary
213 193         355 $doc = $docs->{$_file};
214 193 100 100     670 $doc->{'_perl'} = $self->load_perl($doc) if ! $doc->{'_perl'} && $self->{'COMPILE_PERL'}; # second hit
215 193         541 return $doc;
216             }
217 4384         11370 $doc->{'_filename'} = $_file;
218             } else {
219 3 100       10 $doc->{'_no_perl'} = $self->{'FORCE_STR_REF_PERL'} ? 0 : 1;
220             }
221 4387         9071 $doc->{'_is_str_ref'} = 1;
222 4387         8289 $doc->{'_content'} = $file;
223 4387         7909 $doc->{'name'} = 'input text';
224 4387         8699 $doc->{'modtime'} = time;
225              
226             ### looks like a previously cached document
227             } elsif ($docs->{$file}) {
228 19         39 $doc = $docs->{$file};
229 19 50 33     117 if (time - $doc->{'cache_time'} < ($self->{'STAT_TTL'} || $STAT_TTL) # don't stat more than once a second
      33        
230             || $doc->{'modtime'} == (stat $doc->{'_filename'})[9]) { # otherwise see if the file was modified
231 19 100 100     78 $doc->{'_perl'} = $self->load_perl($doc) if ! $doc->{'_perl'} && $self->{'COMPILE_PERL'}; # second hit
232 19         84 return $doc;
233             }
234 0         0 delete @$doc{qw(_tree modtime _content _line_offsets _perl _js)};
235              
236             ### looks like a previously cached not-found
237             } elsif ($self->{'_not_found'}->{$file}) {
238 13         29 $doc = $self->{'_not_found'}->{$file};
239 13 100 66     109 if (time - $doc->{'cache_time'} < ($self->{'NEGATIVE_STAT_TTL'} || $self->{'STAT_TTL'} || $STAT_TTL)) { # negative cache for a second
240 7         33 die $doc->{'exception'};
241             }
242 6         17 delete $self->{'_not_found'}->{$file}; # clear cache on failure
243              
244             ### looks like a block passed in at runtime
245             } elsif ($self->{'BLOCKS'}->{$file}) {
246 235         541 my $block = $self->{'BLOCKS'}->{$file};
247 235 100       818 $block = $block->() if UNIVERSAL::isa($block, 'CODE');
248 235 100       626 if (! UNIVERSAL::isa($block, 'HASH')) {
249 4 100       16 $self->throw('block', "Unsupported BLOCK type \"$block\"") if ref $block;
250 3   66     4 $block = eval { $self->load_template(\$block) } || $self->throw('block', 'Parse error on predefined block');
251             }
252 233 100 100     1373 $doc->{'name'} = ($block->{'name'} && $block->{'name'} ne 'input text') ? $block->{'name'} : $file;
253 233 100       722 $doc->{'_filename'} = $block->{'_filename'} if $block->{'_filename'};
254 233 100       575 if ($block->{'_perl'}) {
    100          
255 81         168 $doc->{'_perl'} = $block->{'_perl'};
256             } elsif ($block->{'_tree'}) {
257 151         309 $doc->{'_tree'} = $block->{'_tree'};
258             } else {
259 1         5 $self->throw('block', "Invalid block definition (missing tree)");
260             }
261 232         596 return $doc;
262             }
263              
264             ### lookup the filename
265 4925 100 100     11816 if (! $doc->{'_filename'} && ! ref $file) {
266 538         1156 $doc->{'name'} = $file;
267 538         861 $doc->{'_filename'} = eval { $self->include_filename($file) };
  538         1252  
268 538 100       2265 if (my $err = $@) {
269             ### allow for blocks in other files
270 71 100 66     353 if ($self->{'EXPOSE_BLOCKS'} && ! $self->{'_looking_in_block_file'}) {
    50          
271 18         47 local $self->{'_looking_in_block_file'} = 1;
272 18         41 my $block_name = '';
273 18         133 OUTER: while ($file =~ s|/([^/.]+)$||) {
274 12 50       47 $block_name = length($block_name) ? "$1/$block_name" : $1;
275 12   50     31 my $ref = eval { $self->load_template($file) } || next;
276 12         36 my $_tree = $ref->{'_tree'};
277 12         35 foreach my $node (@$_tree) {
278 30 50       66 last if ! ref $node;
279 30 100       70 next if $node->[0] eq 'META';
280 18 50       44 last if $node->[0] ne 'BLOCK';
281 18 100       49 next if $block_name ne $node->[3];
282 12         22 $doc->{'_tree'} = $node->[4];
283 12         24 @{$doc}{qw(modtime _content)} = @{$ref}{qw(modtime _content)};
  12         34  
  12         29  
284             $doc->{'_perl'} = {
285             meta => {},
286             blocks => {},
287             code => $ref->{'_perl'}->{'blocks'}->{$block_name}->{'_perl'}->{'code'},
288 12 50 66     68 } if $ref->{'_perl'} && $ref->{'_perl'}->{'blocks'} && $ref->{'_perl'}->{'blocks'}->{$block_name};
      33        
289 12 0 33     29 $doc->{'_js'} = $self->load_js($doc) if $self->{'COMPILE_JS'} && $ref->{'_js'}; # have to regenerate because block is buried in js
290 12         57 return $doc;
291             }
292             }
293             } elsif ($self->{'DEFAULT'}) {
294 0 0       0 $err = '' if ($doc->{'_filename'} = eval { $self->include_filename($self->{'DEFAULT'}) });
  0         0  
295             }
296 59 50       152 if ($err) {
297             ### cache the negative error
298 59 50 66     243 if (! defined($self->{'NEGATIVE_STAT_TTL'}) || $self->{'NEGATIVE_STAT_TTL'}) {
299 59 50       234 $err = $self->exception('undef', $err) if ! UNIVERSAL::can($err, 'type');
300 59         232 $self->{'_not_found'}->{$file} = {
301             cache_time => time,
302             exception => $self->exception($err->type, $err->info." (cached)"),
303             };
304             }
305 59         331 die $err;
306             }
307             }
308             }
309              
310             ### return perl - if they want perl - otherwise - the ast
311 4854 100 100     25498 if (! $doc->{'_no_perl'} && $self->{'COMPILE_PERL'} && ($self->{'COMPILE_PERL'} ne '2' || $self->{'_tree'})) {
    50 66        
      100        
312 1742         5841 $doc->{'_perl'} = $self->load_perl($doc);
313             } elsif ($self->{'COMPILE_JS'}) {
314 0         0 $self->load_js($doc);
315             } else {
316 3112         7281 $doc->{'_tree'} = $self->load_tree($doc);
317             }
318              
319             ### cache parsed_tree in memory unless asked not to do so
320 4721 100 66     16402 if (! defined($self->{'CACHE_SIZE'}) || $self->{'CACHE_SIZE'}) {
321 4469         9261 $doc->{'cache_time'} = time;
322 4469 100       11393 if (ref $file) {
323 4024 100       16680 $docs->{$doc->{'_filename'}} = $doc if $doc->{'_filename'};
324             } else {
325 445   33     1805 $docs->{$file} ||= $doc;
326             }
327              
328             ### allow for config option to keep the cache size down
329 4469 50       9993 if ($self->{'CACHE_SIZE'}) {
330 0 0       0 if (scalar(keys %$docs) > $self->{'CACHE_SIZE'}) {
331 0         0 my $n = 0;
332 0         0 foreach my $file (sort {$docs->{$b}->{'cache_time'} <=> $docs->{$a}->{'cache_time'}} keys %$docs) {
  0         0  
333 0 0       0 delete($docs->{$file}) if ++$n > $self->{'CACHE_SIZE'};
334             }
335             }
336             }
337             }
338              
339 4721         9979 return $doc;
340             }
341              
342             sub string_id {
343 4578     4578 0 10514 my ($self, $ref) = @_;
344 4578         26690 require Digest::MD5;
345             my $str = ref($self)
346             && $self->{'ENCODING'} # ENCODING is defined
347             && eval { require Encode } # Encode.pm is available
348             && defined &Encode::encode
349 4578 100 66     24661 ? Encode::encode($self->{'ENCODING'}, $$ref)
350             : $$ref;
351 4578         20964 my $sum = Digest::MD5::md5_hex($str);
352 4578         19117 return 'Alloy_str_ref_cache/'.substr($sum,0,3).'/'.$sum;
353             }
354              
355             sub load_tree {
356 4853     4853 1 9393 my ($self, $doc) = @_;
357              
358             ### first look for a compiled optree
359 4853 100       10088 if ($doc->{'_filename'}) {
360 4850   66     14860 $doc->{'modtime'} ||= (stat $doc->{'_filename'})[9];
361 4850 100 100     17159 if ($self->{'COMPILE_DIR'} || $self->{'COMPILE_EXT'}) {
362 16         32 my $file = $doc->{'_filename'};
363 16 100       44 if ($self->{'COMPILE_DIR'}) {
    100          
364 8 50       30 $file =~ y|:|/| if $^O eq 'MSWin32';
365 8         24 $file = $self->{'COMPILE_DIR'} .'/'. $file;
366             } elsif ($doc->{'_is_str_ref'}) {
367 2   50     8 $file = ($self->include_paths->[0] || '.') .'/'. $file;
368             }
369 16 100       54 $file .= $self->{'COMPILE_EXT'} if defined($self->{'COMPILE_EXT'});
370 16 50       42 $file .= $EXTRA_COMPILE_EXT if defined $EXTRA_COMPILE_EXT;
371              
372 16 50 33     228 if (-e $file && ($doc->{'_is_str_ref'} || (stat $file)[9] == $doc->{'modtime'})) {
      66        
373 1         8 require Storable;
374 1         5 return Storable::retrieve($file);
375             }
376 15         63 $doc->{'_storable_filename'} = $file;
377             }
378             }
379              
380             ### no cached tree - we will need to load our own
381 4852   66     11996 $doc->{'_content'} ||= $self->slurp($doc->{'_filename'});
382              
383 4852 100       10493 if ($self->{'CONSTANTS'}) {
384 33   50     123 my $key = $self->{'CONSTANT_NAMESPACE'} || 'constants';
385 33   33     190 $self->{'NAMESPACE'}->{$key} ||= $self->{'CONSTANTS'};
386             }
387              
388 4852         10514 local $self->{'_component'} = $doc;
389             my $tree = eval { $self->parse_tree($doc->{'_content'}) }
390 4852   100     7549 || do { my $e = $@; $e->doc($doc) if UNIVERSAL::can($e, 'doc') && ! $e->doc; die $e }; # errors die
391              
392             ### save a cache on the fileside as asked
393 4719 100       12694 if ($doc->{'_storable_filename'}) {
394 15         31 my $dir = $doc->{'_storable_filename'};
395 15         97 $dir =~ s|/[^/]+$||;
396 15 100       245 if (! -d $dir) {
397 10         72 require File::Path;
398 10         2241 File::Path::mkpath($dir);
399             }
400 15         876 require Storable;
401 15         3550 Storable::store($tree, $doc->{'_storable_filename'});
402 15         2707 utime $doc->{'modtime'}, $doc->{'modtime'}, $doc->{'_storable_filename'};
403             }
404              
405 4719         16599 return $tree;
406             }
407              
408             ###----------------------------------------------------------------###
409              
410             ### allow for resolving full expression ASTs
411             sub play_expr {
412 28489 100   28489 1 80213 return $_[1] if ! ref $_[1]; # allow for the parse tree to store literals
413              
414 18936         26903 my $self = shift;
415 18936         24764 my $var = shift;
416 18936   100     52396 my $ARGS = shift || {};
417 18936         28533 my $i = 0;
418              
419             ### determine the top level of this particular variable access
420 18936         23698 my $ref;
421 18936         31285 my $name = $var->[$i++];
422 18936         26417 my $args = $var->[$i++];
423 18936 100       41787 if (ref $name) {
    50          
424 9292 100       18704 if (! defined $name->[0]) { # operator
425 9118 100 100     20027 return $self->play_operator($name) if wantarray && $name->[1] eq '..';
426 8926 100       26201 $ref = ($name->[1] eq '-temp-') ? $name->[2] : $self->play_operator($name);
427             } else { # a named variable access (ie via $name.foo)
428 174         394 $name = $self->play_expr($name);
429 174 50       421 if (defined $name) {
430 174 100 66     1063 return if $QR_PRIVATE && $name =~ $QR_PRIVATE; # don't allow vars that begin with _
431 171 50 66     666 return \$self->{'_vars'}->{$name} if $i >= $#$var && $ARGS->{'return_ref'} && ! ref $self->{'_vars'}->{$name};
      33        
432 171         386 $ref = $self->{'_vars'}->{$name};
433             }
434             }
435             } elsif (defined $name) {
436 9644 100 100     54159 return if $QR_PRIVATE && $name =~ $QR_PRIVATE; # don't allow vars that begin with _
437 9629 100 100     33688 return \$self->{'_vars'}->{$name} if $i >= $#$var && $ARGS->{'return_ref'} && ! ref $self->{'_vars'}->{$name};
      100        
438 9623         19960 $ref = $self->{'_vars'}->{$name};
439 9623 100       18675 if (! defined $ref) {
440 873 100 100     3803 $ref = ($name eq 'template' || $name eq 'component') ? $self->{"_$name"} : $VOBJS->{$name};
441 873 100 66     5251 $ref = $ITEM_METHODS->{$name} || $ITEM_OPS->{$name} if ! $ref && (! defined($self->{'VMETHOD_FUNCTIONS'}) || $self->{'VMETHOD_FUNCTIONS'});
      100        
      100        
442 873 100 100     3122 $ref = $self->{'_vars'}->{lc $name} if ! defined $ref && $self->{'LOWER_CASE_VAR_FALLBACK'};
443             }
444             }
445              
446 18720         26770 my %seen_filters;
447 18720         35526 while (defined $ref) {
448              
449             ### check at each point if the returned thing was a code
450 21271 100       59927 if (UNIVERSAL::isa($ref, 'CODE')) {
451 547 100 100     2312 return $ref if $i >= $#$var && $ARGS->{'return_ref'};
452 532 100       1393 my @args = $args ? map { $self->play_expr($_) } @$args : ();
  207         484  
453 532   100     1769 my $type = $self->{'CALL_CONTEXT'} || '';
454 532 100       1248 if ($type eq 'item') {
455 39         116 $ref = $ref->(@args);
456             } else {
457 493         2112 my @results = $ref->(@args);
458 490 100       2481 if ($type eq 'list') {
    100          
    50          
459 33         80 $ref = \@results;
460             } elsif (defined $results[0]) {
461 453 100       1347 $ref = ($#results > 0) ? \@results : $results[0];
462             } elsif (defined $results[1]) {
463 0         0 die $results[1]; # TT behavior - why not just throw ?
464             } else {
465 4         8 $ref = undef;
466 4         10 last;
467             }
468             }
469             }
470              
471             ### descend one chained level
472 21249 100       44639 last if $i >= $#$var;
473 3453 50       9709 my $was_dot_call = $ARGS->{'no_dots'} ? 1 : $var->[$i++] eq '.';
474 3453         5993 $name = $var->[$i++];
475 3453         5439 $args = $var->[$i++];
476              
477             ### allow for named portions of a variable name (foo.$name.bar)
478 3453 100       6534 if (ref $name) {
479 60 50       178 if (ref($name) eq 'ARRAY') {
480 60         153 $name = $self->play_expr($name);
481 60 50 33     619 if (! defined($name) || ($QR_PRIVATE && $name =~ $QR_PRIVATE) || $name =~ /^\./) {
      33        
      33        
482 0         0 $ref = undef;
483 0         0 last;
484             }
485             } else {
486 0         0 die "Shouldn't get a ". ref($name) ." during a vivify on chain";
487             }
488             }
489 3453 100 100     22590 if (! defined $name || ($QR_PRIVATE && $name =~ $QR_PRIVATE)) { # don't allow vars that begin with _
      66        
490 3         9 $ref = undef;
491 3         7 last;
492             }
493              
494             ### allow for scalar and filter access (this happens for every non virtual method call)
495 3450 100       8305 if (! ref $ref) {
496 939 100 100     3713 if ($ITEM_METHODS->{$name}) { # normal scalar op
    100          
    100          
    100          
497 223 100       718 $ref = $ITEM_METHODS->{$name}->($self, $ref, $args ? map { $self->play_expr($_) } @$args : ());
  60         189  
498              
499             } elsif ($ITEM_OPS->{$name}) { # normal scalar op
500 665 100       2219 $ref = $ITEM_OPS->{$name}->($ref, $args ? map { $self->play_expr($_) } @$args : ());
  443         1096  
501              
502             } elsif ($LIST_OPS->{$name}) { # auto-promote to list and use list op
503 9 50       48 $ref = $LIST_OPS->{$name}->([$ref], $args ? map { $self->play_expr($_) } @$args : ());
  0         0  
504              
505             } elsif (my $filter = $self->{'FILTERS'}->{$name} # filter configured in Template args
506             || $FILTER_OPS->{$name} # predefined filters in Alloy
507             || (UNIVERSAL::isa($name, 'CODE') && $name) # looks like a filter sub passed in the stash
508             || $self->list_filters->{$name}) { # filter defined in Template::Filters
509              
510 36 100 66     255 if (UNIVERSAL::isa($filter, 'CODE')) {
    50          
    100          
511 9         15 $ref = eval { $filter->($ref) }; # non-dynamic filter - no args
  9         26  
512 9 50       72 if (my $err = $@) {
513 0 0       0 $self->throw('filter', $err) if ! UNIVERSAL::can($err, 'type');
514 0         0 die $err;
515             }
516             } elsif (! UNIVERSAL::isa($filter, 'ARRAY')) {
517 0         0 $self->throw('filter', "invalid FILTER entry for '$name' (not a CODE ref)");
518              
519             } elsif (@$filter == 2 && UNIVERSAL::isa($filter->[0], 'CODE')) { # these are the TT style filters
520 9         15 eval {
521 9         21 my $sub = $filter->[0];
522 9 100       34 if ($filter->[1]) { # it is a "dynamic filter" that will return a sub
523 6 100       30 ($sub, my $err) = $sub->($self->context, $args ? map { $self->play_expr($_) } @$args : ());
  3         11  
524 6 50 33     8611 if (! $sub && $err) {
    50          
525 0 0       0 $self->throw('filter', $err) if ! UNIVERSAL::can($err, 'type');
526 0         0 die $err;
527             } elsif (! UNIVERSAL::isa($sub, 'CODE')) {
528 0 0       0 $self->throw('filter', "invalid FILTER for '$name' (not a CODE ref)")
529             if ! UNIVERSAL::can($sub, 'type');
530 0         0 die $sub;
531             }
532             }
533 9         59 $ref = $sub->($ref);
534             };
535 9 50       163 if (my $err = $@) {
536 0 0       0 $self->throw('filter', $err) if ! UNIVERSAL::can($err, 'type');
537 0         0 die $err;
538             }
539             } else { # this looks like our vmethods turned into "filters" (a filter stored under a name)
540 18 50       67 $self->throw('filter', 'Recursive filter alias \"$name\"') if $seen_filters{$name} ++;
541 18         45 $var = [$name, 0, '|', @$filter, @{$var}[$i..$#$var]]; # splice the filter into our current tree
  18         63  
542 18         37 $i = 2;
543             }
544 36 50 50     205 if (scalar keys %seen_filters
      66        
545             && $seen_filters{$var->[$i - 5] || ''}) {
546 0         0 $self->throw('filter', "invalid FILTER entry for '".$var->[$i - 5]."' (not a CODE ref)");
547             }
548             } else {
549 6         21 $ref = undef;
550             }
551              
552             } else {
553              
554             ### method calls on objects
555 2511 100 100     10505 if ($was_dot_call && UNIVERSAL::can($ref, 'can')) {
556 845 50 66     3413 return $ref if $i >= $#$var && $ARGS->{'return_ref'};
557 845   100     2694 my $type = $self->{'CALL_CONTEXT'} || '';
558 845 100       2006 my @args = $args ? map { $self->play_expr($_) } @$args : ();
  156         490  
559 845 100       2306 if ($type eq 'item') {
    100          
560 21         108 $ref = $ref->$name(@args);
561 21         331 next;
562             } elsif ($type eq 'list') {
563 21         135 $ref = [$ref->$name(@args)];
564 21         355 next;
565             }
566 803         1355 my @results = eval { $ref->$name(@args) };
  803         3787  
567 803 100       7942 if ($@) {
    50          
    0          
568 13         37 my $class = ref $ref;
569 13 50 66     319 die $@ if ref $@ || $@ !~ /Can\'t locate object method "\Q$name\E" via package "\Q$class\E"/ || $type eq 'list';
      66        
570             } elsif (defined $results[0]) {
571 790 100       1785 $ref = ($#results > 0) ? \@results : $results[0];
572 790         2488 next;
573             } elsif (defined $results[1]) {
574 0         0 die $results[1]; # TT behavior - why not just throw ?
575             } else {
576 0         0 $ref = undef;
577 0         0 last;
578             }
579             # didn't find a method by that name - so fail down to hash and array access
580             }
581              
582 1675 100       4792 if (UNIVERSAL::isa($ref, 'HASH')) {
    50          
583 1056 100 100     4112 if ($was_dot_call && exists($ref->{$name}) ) {
    100          
    100          
584 756 100 100     2872 return \ $ref->{$name} if $i >= $#$var && $ARGS->{'return_ref'} && ! ref $ref->{$name};
      66        
585 744         2136 $ref = $ref->{$name};
586             } elsif ($HASH_OPS->{$name}) {
587 171 100       634 $ref = $HASH_OPS->{$name}->($ref, $args ? map { $self->play_expr($_) } @$args : ());
  108         212  
588             } elsif ($ARGS->{'is_namespace_during_compile'}) {
589 6         44 return $var; # abort - can't fold namespace variable
590             } else {
591 123 100 100     479 return \ $ref->{$name} if $i >= $#$var && $ARGS->{'return_ref'};
592 120         343 $ref = undef;
593             }
594              
595             } elsif (UNIVERSAL::isa($ref, 'ARRAY')) {
596 619 100       3349 if ($name =~ m{ ^ -? $QR_INDEX $ }ox) {
    50          
597 155 100 100     879 return \ $ref->[$name] if $i >= $#$var && $ARGS->{'return_ref'} && ! ref $ref->[$name];
      66        
598 149         564 $ref = $ref->[$name];
599             } elsif ($LIST_OPS->{$name}) {
600 464 100       1571 $ref = $LIST_OPS->{$name}->($ref, $args ? map { $self->play_expr($_) } @$args : ());
  179         434  
601             } else {
602 0         0 $ref = undef;
603             }
604             } else {
605 0         0 $ref = undef;
606             }
607             }
608              
609             } # end of while
610              
611 18627 100       34833 if (! defined $ref) {
612 831 100       1912 $self->strict_throw($var) if $self->{'STRICT'}; # will die
613 807 100       1774 die $self->tt_var_string($var)." is undefined\n" if $self->{'_debug_undef'};
614 801         2636 $ref = $self->undefined_any($var);
615             }
616              
617 18597         128434 return $ref;
618             }
619              
620             sub set_variable {
621 6083     6083 1 12846 my ($self, $var, $val, $ARGS) = @_;
622 6083   100     23695 $ARGS ||= {};
623 6083         9540 my $i = 0;
624              
625             ### allow for the parse tree to store literals - the literal is used as a name (like [% 'a' = 'A' %])
626 6083 100       12555 $var = [$var, 0] if ! ref $var;
627              
628             ### determine the top level of this particular variable access
629 6083         10840 my $ref = $var->[$i++];
630 6083         8414 my $args = $var->[$i++];
631 6083 100       15177 if (ref $ref) {
    50          
632             ### non-named types can't be set
633 18 50       63 return if ref($ref) ne 'ARRAY';
634 18 100       63 if (! defined $ref->[0]) {
635 6 50 33     52 return if ! $ref->[1] || $ref->[1] !~ /^[\$\@]\(\)$/; # do allow @( )
636 6         25 $ref = $self->play_operator($ref);
637             } else {
638             # named access (ie via $name.foo)
639 12         27 $ref = $self->play_expr($ref);
640 12 50 33     100 if (defined $ref && (! $QR_PRIVATE || $ref !~ $QR_PRIVATE)) { # don't allow vars that begin with _
      33        
641 12 100       37 if ($#$var <= $i) {
642 6         67 return $self->{'_vars'}->{$ref} = $val;
643             } else {
644 6   50     37 $ref = $self->{'_vars'}->{$ref} ||= {};
645             }
646             } else {
647 0         0 return;
648             }
649             }
650             } elsif (defined $ref) {
651 6065 100 100     34289 return if $QR_PRIVATE && $ref =~ $QR_PRIVATE; # don't allow vars that begin with _
652 6062 100       13494 if ($#$var <= $i) {
653 5880         33646 return $self->{'_vars'}->{$ref} = $val;
654             } else {
655 182   100     960 $ref = $self->{'_vars'}->{$ref} ||= {};
656             }
657             }
658              
659 194         604 while (defined $ref) {
660              
661             ### check at each point if the returned thing was a code
662 256 100       1028 if (UNIVERSAL::isa($ref, 'CODE')) {
663 6   100     28 my $type = $self->{'CALL_CONTEXT'} || '';
664 6 50       19 my @args = $args ? map { $self->play_expr($_) } @$args : ();
  0         0  
665 6 50       17 if ($type eq 'item') {
666 0         0 $ref = $ref->(@args);
667             } else {
668 6         23 my @results = $ref->(@args);
669 6 100       43 if ($type eq 'list') {
    50          
    0          
670 3         9 $ref = \@results;
671             } elsif (defined $results[0]) {
672 3 50       14 $ref = ($#results > 0) ? \@results : $results[0];
673             } elsif (defined $results[1]) {
674 0         0 die $results[1]; # TT behavior - why not just throw ?
675             } else {
676 0         0 return;
677             }
678             }
679             }
680              
681             ### descend one chained level
682 256 50       621 last if $i >= $#$var;
683 256 100       840 my $was_dot_call = $ARGS->{'no_dots'} ? 1 : $var->[$i++] eq '.';
684 256         494 my $name = $var->[$i++];
685 256         436 my $args = $var->[$i++];
686              
687             ### allow for named portions of a variable name (foo.$name.bar)
688 256 100       549 if (ref $name) {
689 18 50       44 if (ref($name) eq 'ARRAY') {
690 18         42 $name = $self->play_expr($name);
691 18 50 33     95 if (! defined($name) || $name =~ /^[_.]/) {
692 0         0 return;
693             }
694             } else {
695 0         0 die "Shouldn't get a ".ref($name)." during a vivify on chain";
696             }
697             }
698 256 50 33     1530 if ($QR_PRIVATE && $name =~ $QR_PRIVATE) { # don't allow vars that begin with _
699 0         0 return;
700             }
701              
702             ### scalar access
703 256 50       1061 if (! ref $ref) {
    100          
704 0         0 return;
705              
706             ### method calls on objects
707             } elsif (UNIVERSAL::can($ref, 'can')) {
708 49         104 my $lvalueish;
709 49   100     183 my $type = $self->{'CALL_CONTEXT'} || '';
710 49 50       148 my @args = $args ? map { $self->play_expr($_) } @$args : ();
  0         0  
711 49 100       125 if ($i >= $#$var) {
712 40         78 $lvalueish = 1;
713 40         108 push @args, $val;
714             }
715 49 100       179 if ($type eq 'item') {
    100          
716 3         22 $ref = $ref->$name(@args);
717 3 50       63 return if $lvalueish;
718 0         0 next;
719             } elsif ($type eq 'list') {
720 3         26 $ref = [$ref->$name(@args)];
721 3 50       82 return if $lvalueish;
722 0         0 next;
723             }
724 43         81 my @results = eval { $ref->$name(@args) };
  43         346  
725 43 100       913 if (! $@) {
726 39 50       114 if (defined $results[0]) {
    0          
727 39 50       122 $ref = ($#results > 0) ? \@results : $results[0];
728             } elsif (defined $results[1]) {
729 0         0 die $results[1]; # TT behavior - why not just throw ?
730             } else {
731 0         0 return;
732             }
733 39 100       461 return if $lvalueish;
734 9         36 next;
735             }
736 4         10 my $class = ref $ref;
737 4 50 33     72 die $@ if ref $@ || $@ !~ /Can\'t locate object method "\Q$name\E" via package "\Q$class\E"/;
738             # fall on down to "normal" accessors
739             }
740              
741 207 100       657 if (UNIVERSAL::isa($ref, 'HASH')) {
    50          
742 189 100       458 if ($#$var <= $i) {
743 142         1969 return $ref->{$name} = $val;
744             } else {
745 47   100     226 $ref = $ref->{$name} ||= {};
746 47         124 next;
747             }
748              
749             } elsif (UNIVERSAL::isa($ref, 'ARRAY')) {
750 18 50       219 if ($name =~ m{ ^ -? $QR_INDEX $ }ox) {
751 18 100       59 if ($#$var <= $i) {
752 12         156 return $ref->[$name] = $val;
753             } else {
754 6   50     26 $ref = $ref->[$name] ||= {};
755 6         18 next;
756             }
757             } else {
758 0         0 return;
759             }
760              
761             }
762              
763             }
764              
765 0         0 return;
766             }
767              
768             ###----------------------------------------------------------------###
769              
770             sub _vars {
771 332     332   574 my $self = shift;
772 332 50       888 $self->{'_vars'} = shift if @_ == 1;
773 332   50     1515 return $self->{'_vars'} ||= {};
774             }
775              
776             sub include_filename {
777 559     559 1 1072 my ($self, $file) = @_;
778 559 50       1999 if ($file =~ m|^/|) {
    50          
779 0 0       0 $self->throw('file', "$file absolute paths are not allowed (set ABSOLUTE option)") if ! $self->{'ABSOLUTE'};
780 0 0       0 return $file if -e $file;
781             } elsif ($file =~ m{(^|/)\.\./}) {
782 0 0       0 $self->throw('file', "$file relative paths are not allowed (set RELATIVE option)") if ! $self->{'RELATIVE'};
783 0 0       0 return $file if -e $file;
784             }
785              
786 559         854 my @paths = @{ $self->include_paths };
  559         1211  
787 559 50 66     1918 if ($self->{'ADD_LOCAL_PATH'}
      33        
      33        
788             && $self->{'_component'}
789             && $self->{'_component'}->{'_filename'}
790             && $self->{'_component'}->{'_filename'} =~ m|^(.+)/[^/]+$|) {
791 60 100       319 ($self->{'ADD_LOCAL_PATH'} < 0) ? push(@paths, $1) : unshift(@paths, $1);
792             }
793              
794 559         1008 foreach my $path (@paths) {
795 600 100       14856 return "$path/$file" if -e "$path/$file";
796             }
797              
798 71         476 $self->throw('file', "$file: not found");
799             }
800              
801             sub include_paths {
802 562     562 0 883 my $self = shift;
803 562   66     1632 return $self->{'INCLUDE_PATHS'} ||= do {
804             # TT does this everytime a file is looked up - we are going to do it just in time - the first time
805 426   100     989 my $paths = $self->{'INCLUDE_PATH'} || ['.'];
806 426 50       1834 $paths = $paths->() if UNIVERSAL::isa($paths, 'CODE');
807 426 100       1607 $paths = $self->split_paths($paths) if ! UNIVERSAL::isa($paths, 'ARRAY');
808 426         1784 $paths; # return of the do
809             };
810             }
811              
812             sub split_paths {
813 548     548 1 1040 my ($self, $path) = @_;
814 548 100       1816 return $path if UNIVERSAL::isa($path, 'ARRAY');
815 521   50     1531 my $delim = $self->{'DELIMITER'} || ':';
816 521 50 33     3986 $delim = ($delim eq ':' && $^O eq 'MSWin32') ? qr|:(?!/)| : qr|\Q$delim\E|;
817 521         3236 return [split $delim, "$path"]; # allow objects to stringify as necessary
818             }
819              
820             sub slurp {
821 490     490 1 965 my ($self, $file) = @_;
822 490 50       19137 open(my $fh, '<', $file) || $self->throw('file', "$file couldn't be opened: $!");
823 490         13516 read $fh, my $txt, -s $file;
824              
825 490 100       2026 if ($self->{'ENCODING'}) { # thanks to Carl Franks for this addition
826 3         6 eval { require Encode };
  3         21  
827 3 50 33     21 if ($@ || ! defined &Encode::decode) {
828 0         0 warn "Encode module not found, 'ENCODING' config only available on perl >= 5.7.3\n$@";
829             } else {
830 3         14 $txt = Encode::decode($self->{'ENCODING'}, $txt);
831             }
832             }
833              
834 490         8771 return \$txt;
835             }
836              
837 38     38 1 226 sub error { shift->{'error'} }
838              
839             sub exception {
840 535     535 1 890 my $self_or_class = shift;
841 535         878 my $type = shift;
842 535         813 my $info = shift;
843 535 100       3402 return $type if UNIVERSAL::can($type, 'type');
844 522 100       1395 if (ref($info) eq 'ARRAY') {
845 100 50       278 my $hash = ref($info->[-1]) eq 'HASH' ? pop(@$info) : {};
846 100 50 50     586 if (@$info >= 2 || scalar keys %$hash) {
    100          
847 0         0 my $i = 0;
848 0         0 $hash->{$_} = $info->[$_] for 0 .. $#$info;
849 0         0 $hash->{'args'} = $info;
850 0         0 $info = $hash;
851             } elsif (@$info == 1) {
852 87         282 $info = $info->[0];
853             } else {
854 13         29 $info = $type;
855 13         37 $type = 'undef';
856             }
857             }
858 522         2810 return Template::Alloy::Exception->new($type, $info, @_);
859             }
860              
861 468     468 1 1511 sub throw { die shift->exception(@_) }
862              
863             sub context {
864 163     163 1 388 my $self = shift;
865 163         698 require Template::Alloy::Context;
866 163         1376 return Template::Alloy::Context->new({_template => $self});
867             }
868              
869             sub iterator {
870 267     267 0 476 my $self = shift;
871 267         1444 require Template::Alloy::Iterator;
872 267         1429 Template::Alloy::Iterator->new(@_);
873             }
874              
875             sub undefined_get {
876 614     614 1 1410 my ($self, $ident, $node) = @_;
877 614 50       1334 return $self->{'UNDEFINED_GET'}->($self, $ident, $node) if $self->{'UNDEFINED_GET'};
878 614         5139 return '';
879             }
880              
881             sub undefined_any {
882 801     801 1 1613 my ($self, $ident) = @_;
883 801 50       1738 return $self->{'UNDEFINED_ANY'}->($self, $ident) if $self->{'UNDEFINED_ANY'};
884 801         1542 return;
885             }
886              
887             sub strict_throw {
888 27     27 1 64 my ($self, $ident) = @_;
889 27         71 my $v = $self->tt_var_string($ident);
890 27         63 my $temp = $self->{'_template'}->{'name'};
891 27         47 my $comp = $self->{'_component'}->{'name'};
892 27 100       167 my $msg = "undefined variable: $v in $comp".($comp ne $temp ? " while processing $temp" : '');
893 27 100       102 return $self->{'STRICT_THROW'}->($self, 'var.undef', $msg, {name => $v, component => $comp, template => $temp, ident => $ident}) if $self->{'STRICT_THROW'};
894 21         69 $self->throw('var.undef', $msg);
895             }
896              
897 9   50 9 1 44 sub list_filters { shift->{'_filters'} ||= eval { require Template::Filters; $Template::Filters::FILTERS } || {} }
      33        
898              
899             sub debug_node {
900 16     16 1 44 my ($self, $node) = @_;
901 16         46 my $info = $self->node_info($node);
902 16   100     78 my $format = $self->{'_debug_format'} || $self->{'DEBUG_FORMAT'} || "\n## \$file line \$line : [% \$text %] ##\n";
903 16         160 $format =~ s{\$(file|line|text)}{$info->{$1}}g;
904 16         111 return $format;
905             }
906              
907             sub node_info {
908 102     102 0 217 my ($self, $node) = @_;
909 102         209 my $doc = $self->{'_component'};
910 102         159 my $i = $node->[1];
911 102   50     242 my $j = $node->[2] || return ''; # META can be 0
912             return {
913             file => $doc->{'name'},
914             line => 'unknown',
915             text => 'unknown',
916 102 0 33     281 } if !$doc->{'_filename'} && !$doc->{'_content'};
917 102   66     269 $doc->{'_content'} ||= $self->slurp($doc->{'_filename'});
918 102         171 my $s = substr(${ $doc->{'_content'} }, $i, $j - $i);
  102         328  
919 102         419 $s =~ s/^\s+//;
920 102         370 $s =~ s/\s+$//;
921             return {
922 102         285 file => $doc->{'name'},
923             line => $self->get_line_number_by_index($doc, $i),
924             text => $s,
925             };
926             }
927              
928             sub get_line_number_by_index {
929 3924     3924 1 8179 my ($self, $doc, $index, $include_char) = @_;
930 3924 50 33     13933 if (! $index || $index <= 0) {
931 0 0       0 return $include_char ? (1, 1) : 1;
932             }
933              
934 3924   66     9198 my $lines = $doc->{'_line_offsets'} ||= do {
935 1680   33     3432 $doc->{'_content'} ||= $self->slurp($doc->{'_filename'});
936 1680         2334 my $i = 0;
937 1680         3664 my @lines = (0);
938 1680         2566 while (1) {
939 2184         2948 $i = index(${ $doc->{'_content'} }, "\n", $i) + 1;
  2184         5469  
940 2184 100       5850 last if $i == 0;
941 504         839 push @lines, $i;
942             }
943 1680         4901 \@lines;
944             };
945              
946             ### binary search them (this is fast even on big docs)
947 3924         7528 my ($i, $j) = (0, $#$lines);
948 3924 100       8258 if ($index > $lines->[-1]) {
949 3350         5537 $i = $j;
950             } else {
951 574         841 while (1) {
952 2104 100       3903 last if abs($i - $j) <= 1;
953 1530         2555 my $k = int(($i + $j) / 2);
954 1530 100       2773 $j = $k if $lines->[$k] >= $index;
955 1530 100       2701 $i = $k if $lines->[$k] <= $index;
956             }
957             }
958 3924 100       13743 return $include_char ? ($i + 1, $index - $lines->[$i]) : $i + 1;
959             }
960              
961             sub ast_string {
962 35248     35248 1 57666 my ($self, $var) = @_;
963              
964 35248 100       60930 return 'undef' if ! defined $var;
965 33178 100       59047 return '['.join(', ', map { $self->ast_string($_) } @$var).']' if ref $var;
  29643         50511  
966 23192 100       90376 return $var if $var =~ /^(-?[1-9]\d{0,13}|0)$/;
967              
968 13037         21625 $var =~ s/([\'\\])/\\$1/g;
969 13037         34974 return "'$var'";
970             }
971              
972             sub tt_var_string {
973 36     36 1 83 my ($self, $ident) = @_;
974 36 100       96 if (! ref $ident) {
975 3 50 33     45 return $ident if $ident eq '0' || $ident =~ /^[1-9]\d{0,12}$/;
976 0         0 $ident =~ s/\'/\\\'/g;
977 0         0 return "'$ident'";
978             }
979 33         69 my $v = '';
980 33         107 for (my $i = 0; $i < @$ident; ) {
981 51         91 $v .= $ident->[$i++];
982 51 100       119 $v .= '('.join(',',map{$self->tt_var_string($_)} @{$ident->[$i-1]}).')' if $ident->[$i++];
  3         11  
  9         32  
983 51 100       165 $v .= $ident->[$i++] if $i < @$ident;
984             }
985 33         179 return $v;
986             }
987              
988             sub item_method_eval {
989 223     223 0 385 my $self = shift;
990 223 50       346 my $text = shift; return '' if ! defined $text;
  223         456  
991 223   100     600 my $args = shift || {};
992              
993 223   100     788 local $self->{'_eval_recurse'} = $self->{'_eval_recurse'} || 0;
994             $self->throw('eval_recurse', "MAX_EVAL_RECURSE $Template::Alloy::MAX_EVAL_RECURSE reached")
995 223 100 66     926 if ++$self->{'_eval_recurse'} > ($self->{'MAX_EVAL_RECURSE'} || $MAX_EVAL_RECURSE);
996              
997 193         265 my %ARGS;
998 193         595 @ARGS{ map {uc} keys %$args } = values %$args;
  27         110  
999 193         379 delete @ARGS{ grep {! $Template::Alloy::EVAL_CONFIG->{$_}} keys %ARGS };
  27         99  
1000 193 100 100     520 $self->throw("eval_strict", "Cannot disable STRICT once it is enabled") if exists $ARGS{'STRICT'} && ! $ARGS{'STRICT'};
1001              
1002 190         366 local @$self{ keys %ARGS } = values %ARGS;
1003 190         316 my $out = '';
1004 190 100       604 $self->process_simple(\$text, $self->_vars, \$out) || $self->throw($self->error);
1005 179         869 return $out;
1006             }
1007              
1008             1;
1009              
1010             ### See the perldoc in Template/Alloy.pod