File Coverage

blib/lib/Text/Template/Simple/Base/Compiler.pm
Criterion Covered Total %
statement 118 126 93.6
branch 51 72 70.8
condition 32 48 66.6
subroutine 12 12 100.0
pod n/a
total 213 258 82.5


line stmt bran cond sub pod time code
1             ## no critic (ProhibitUnusedPrivateSubroutines)
2             package Text::Template::Simple::Base::Compiler;
3 60     60   288 use strict;
  60         65  
  60         1334  
4 60     60   198 use warnings;
  60         62  
  60         1340  
5              
6 60     60   195 use Text::Template::Simple::Util qw(:all);
  60         64  
  60         7124  
7 60     60   259 use Text::Template::Simple::Constants qw(:all);
  60         89  
  60         80321  
8              
9             our $VERSION = '0.90';
10              
11             sub _init_compile_opts {
12 506     506   485 my $self = shift;
13 506   100     1128 my $opt = shift || {};
14              
15 506 50       1128 fatal('tts.base.compiler._compile.opt') if ref $opt ne 'HASH';
16              
17             # set defaults
18 506   100     1726 $opt->{id} ||= EMPTY_STRING; # id is AUTO
19 506   100     1471 $opt->{map_keys} ||= 0; # use normal behavior
20 506   100     1115 $opt->{chkmt} ||= 0; # check mtime of file template?
21 506   100     1050 $opt->{_sub_inc} ||= 0; # are we called from a dynamic include op?
22 506   100     1303 $opt->{_filter} ||= EMPTY_STRING; # any filters?
23              
24             # first element is the shared names. if it's not defined, then there
25             # are no shared variables from top level
26 506 100 100     1179 if ( ref $opt->{_share} eq 'ARRAY' && ! defined $opt->{_share}[0] ) {
27 12         19 delete $opt->{_share};
28             }
29              
30 506   100     1550 $opt->{as_is} = $opt->{_sub_inc} && $opt->{_sub_inc} == T_STATIC;
31              
32 506         738 return $opt;
33             }
34              
35             sub _validate_chkmt {
36 250     250   316 my($self, $chkmt_ref, $tmpx) = @_;
37 250         315 ${$chkmt_ref} = $self->[TYPE] eq 'FILE'
38             ? (stat $tmpx)[STAT_MTIME]
39 250 100       2395 : do {
40 2 50       7 DEBUG && LOG( DISABLE_MT =>
41             'Disabling chkmt. Template is not a file');
42 2         6 0;
43             };
44 250         350 return;
45             }
46              
47             sub _compile_cache {
48 18     18   41 my($self, $tmp, $opt, $id_ref, $code_ref) = @_;
49 18         22 my $method = $opt->{id};
50 18   66     54 my $auto_id = ! $method || $method eq 'AUTO';
51 18 100       49 ${ $id_ref } = $self->connector('Cache::ID')->new->generate(
  18         22  
52             $auto_id ? ( $tmp ) : ( $method, 'custom' )
53             );
54              
55             # prevent overwriting the compiled version in cache
56             # since we need the non-compiled version
57 18 50       48 ${ $id_ref } .= '_1' if $opt->{as_is};
  0         0  
58              
59 18         56 ${ $code_ref } = $self->cache->hit( ${$id_ref}, $opt->{chkmt} );
  18         26  
  18         72  
60 18 50 33     36 LOG( CACHE_HIT => ${$id_ref} ) if DEBUG && ${$code_ref};
  0         0  
  0         0  
61 18         32 return;
62             }
63              
64             sub _compile {
65 506     506   1422 my $self = shift;
66 506   33     1055 my $tmpx = shift || fatal('tts.base.compiler._compile.notmp');
67 506   100     1675 my $param = shift || [];
68 506         1070 my $opt = $self->_init_compile_opts( shift );
69              
70 506 50       977 fatal('tts.base.compiler._compile.param') if ref $param ne 'ARRAY';
71              
72 506         1469 my $tmp = $self->_examine( $tmpx );
73 502 50       1017 return $tmp if $self->[TYPE] eq 'ERROR';
74              
75 502 100       920 if ( $opt->{_sub_inc} ) {
76             # TODO:generate a single error handler for includes, merge with _include()
77             # tmpx is a "file" included from an upper level compile()
78 266         640 my $etitle = $self->_include_error( T_DYNAMIC );
79 266         566 my $exists = $self->io->file_exists( $tmpx );
80 266 50       516 return $etitle . " '$tmpx' is not a file" if not $exists;
81             # TODO: remove this second call somehow, reduce to a single call
82 266         499 $tmp = $self->_examine( $exists ); # re-examine
83 266         348 $self->[NEEDS_OBJECT]++; # interpolated includes will need that
84             }
85              
86 502 100       1324 $self->_validate_chkmt( \$opt->{chkmt}, $tmpx ) if $opt->{chkmt};
87              
88 502 50 33     800 LOG( COMPILE => $opt->{id} ) if DEBUG && defined $opt->{id};
89              
90 502         503 my $cache_id = EMPTY_STRING;
91              
92 502         361 my($CODE);
93 502 100       981 $self->_compile_cache( $tmp, $opt, \$cache_id, \$CODE ) if $self->[CACHE];
94              
95 502         1066 $self->cache->id( $cache_id ); # if $cache_id;
96 502 100       1023 $self->[FILENAME] = $self->[TYPE] eq 'FILE' ? $tmpx : $self->cache->id;
97              
98 502 100       1010 my($shead, @sparam) = $opt->{_share} ? @{$opt->{_share}} : ();
  6         12  
99              
100 502 50 33     764 LOG(
101             SHARED_VARS => "Adding shared variables ($shead) from a dynamic include"
102             ) if DEBUG && $shead;
103              
104 502 100       1742 $CODE = $self->_cache_miss( $cache_id, $shead, \@sparam, $opt, $tmp ) if ! $CODE;
105              
106 502         464 my @args;
107 502 100       1032 push @args, $self if $self->[NEEDS_OBJECT]; # must be the first
108 502 100       821 push @args, @sparam if @sparam;
109 502 100       764 push @args, @{ $self->[ADD_ARGS] } if $self->[ADD_ARGS];
  12         26  
110 502         528 push @args, @{ $param };
  502         547  
111 502         9735 my $out = $CODE->( @args );
112              
113             $self->_call_filters( \$out, split RE_FILTER_SPLIT, $opt->{_filter} )
114 500 100       5692 if $opt->{_filter};
115              
116 500         2283 return $out;
117             }
118              
119             sub _cache_miss {
120 498     498   681 my($self, $cache_id, $shead, $sparam, $opt, $tmp) = @_;
121             # we have a cache miss; parse and compile
122 498 50       741 LOG( CACHE_MISS => $cache_id ) if DEBUG;
123              
124 498         439 my $restore_header;
125 498 100       752 if ( $shead ) {
126 6         6 my $param_x = join q{,}, ('shift') x @{ $sparam };
  6         13  
127 6         18 my $shared = sprintf q~my(%s) = (%s);~, $shead, $param_x;
128 6         8 $restore_header = $self->[HEADER];
129 6   50     28 $self->[HEADER] = $shared . q{;} . ( $self->[HEADER] || EMPTY_STRING );
130             }
131              
132 498         388 my %popt = ( %{ $opt }, cache_id => $cache_id, as_is => $opt->{as_is} );
  498         2867  
133 498         1671 my $parsed = $self->_parse( $tmp, \%popt );
134 498         1439 my $CODE = $self->cache->populate( $cache_id, $parsed, $opt->{chkmt} );
135 498 100       774 $self->[HEADER] = $restore_header if $shead;
136 498         1245 return $CODE;
137             }
138              
139             sub _call_filters {
140 4     4   9 my($self, $oref, @filters) = @_;
141 4         6 my $fname = $self->[FILENAME];
142              
143 4         10 APPLY_FILTERS: foreach my $filter ( @filters ) {
144 6         58 my $fref = DUMMY_CLASS->can( 'filter_' . $filter );
145 6 50       15 if ( ! $fref ) {
146 0         0 ${$oref} .= "\n[ filter warning ] Can not apply undefined filter"
  0         0  
147             . " $filter to $fname\n";
148 0         0 next;
149             }
150 6         15 $fref->( $self, $oref );
151             }
152              
153 4         42 return;
154             }
155              
156             sub _wrap_compile {
157 500     500   508 my $self = shift;
158 500 50       822 my $parsed = shift or fatal('tts.base.compiler._wrap_compile.parsed');
159 500 50 33     1111 LOG( CACHE_ID => $self->cache->id ) if $self->[WARN_IDS] && $self->cache->id;
160 500 0       784 LOG( COMPILER => $self->[SAFE] ? 'Safe' : 'Normal' ) if DEBUG;
    50          
161 500         414 my($CODE, $error);
162              
163 500 100       788 my $compiler = $self->[SAFE] ? COMPILER_SAFE : COMPILER;
164              
165 500         2258 $CODE = $compiler->compile( $parsed );
166              
167 500 50       2371 if( $error = $@ ) {
168 0         0 my $error2;
169 0 0       0 $error .= $error2 if $error2;
170             }
171              
172 500         1336 return $CODE, $error;
173             }
174              
175             sub _mini_compiler {
176             # little dumb compiler for internal templates
177 280     280   254 my $self = shift;
178 280   33     465 my $template = shift || fatal('tts.base.compiler._mini_compiler.notmp');
179 280   33     442 my $param = shift || fatal('tts.base.compiler._mini_compiler.noparam');
180 280   100     405 my $opt = shift || {};
181              
182 280 50       543 fatal('tts.base.compiler._mini_compiler.opt') if ref $opt ne 'HASH';
183 280 50       440 fatal('tts.base.compiler._mini_compiler.param') if ref $param ne 'HASH';
184              
185 280         202 foreach my $var ( keys %{ $param } ) {
  280         796  
186 898         1008 my $str = $param->{$var};
187 898         7574 $template =~ s{<%\Q$var\E%>}{$str}xmsg;
188             }
189              
190 280 100       3010 $template =~ s{\s+}{ }xmsg if $opt->{flatten}; # remove extra spaces
191 280         735 return $template;
192             }
193              
194             1;
195              
196             __END__
197              
198             =pod
199              
200             =head1 NAME
201              
202             Text::Template::Simple::Base::Compiler - Base class for Text::Template::Simple
203              
204             =head1 SYNOPSIS
205              
206             Private module.
207              
208             =head1 DESCRIPTION
209              
210             This document describes version C<0.90> of C<Text::Template::Simple::Base::Compiler>
211             released on C<5 July 2016>.
212              
213             Private module.
214              
215             =head1 AUTHOR
216              
217             Burak Gursoy <burak@cpan.org>.
218              
219             =head1 COPYRIGHT
220              
221             Copyright 2004 - 2016 Burak Gursoy. All rights reserved.
222              
223             =head1 LICENSE
224              
225             This library is free software; you can redistribute it and/or modify
226             it under the same terms as Perl itself, either Perl version 5.24.0 or,
227             at your option, any later version of Perl 5 you may have available.
228             =cut