File Coverage

blib/lib/Template/Plex/Internal.pm
Criterion Covered Total %
statement 333 387 86.0
branch 30 126 23.8
condition 14 77 18.1
subroutine 104 109 95.4
pod 0 5 0.0
total 481 704 68.3


line stmt bran cond sub pod time code
1             package Template::Plex::Internal;
2 3     3   21 use strict;
  3         6  
  3         122  
3 3     3   17 use warnings;
  3         5  
  3         347  
4              
5 3     3   16 use Template::Plex;
  3         5  
  3         135  
6              
7             #use List::Util qw;
8              
9             #use Symbol qw;
10 3     3   18 use Carp qw;
  3         5  
  3         196  
11              
12 3     3   17 use feature qw;
  3         5  
  3         562  
13 3     3   19 no warnings "experimental";
  3         5  
  3         126  
14              
15 3     3   1021 use File::Spec::Functions qw;
  3         1788  
  3         275  
16             #use File::Basename qw;
17 3     3   30 use Exporter 'import';
  3         7  
  3         1080  
18              
19              
20             #our %EXPORT_TAGS = ( 'all' => [ qw( plex plx block pl plex_clear jmap) ] );
21              
22             our @EXPORT_OK = qw;# @{ $EXPORT_TAGS{'all'} } );
23              
24              
25             my $Include=qr|\@\{\s*\[\s*include\s*\(\s*(.*?)\s*\)\s*\] \s* \}|x;
26             my $Init=qr|\@\{\s*\[\s*init\s*\{(?:.*?)\}\s*\] \s* \}|smx;
27              
28              
29             sub new; #forward declare new;
30              
31             sub lexical{
32 22     22 0 54 my $href=shift;
33 22 50 33     68 croak "NEED A HASH REF " unless ref $href eq "HASH" or !defined $href;
34 22   50     105 $href//={};
35 22         42 \my %fields=$href;
36              
37 22         36 my $string="";
38 22         124 for my $k (keys %fields){
39 12         38 $string.= "\\my \$$k=\\\$fields{$k};\n";
40             }
41 22         61 $string;
42             }
43              
44             sub bootstrap{
45 22     22   423 my $plex=shift;
46 22         45 \my $_data_=\shift;
47 22         32 my $href=shift;
48 22         102 my %opts=@_;
49              
50 22   50     67 $href//={};
51 22         35 \my %fields=$href;
52              
53 22         210 my $out="package $opts{package} {
54             use Template::Plex::Internal qw;
55             no warnings qw;
56             ";
57              
58 22         58 $out.='my $self=$plex;
59             ';
60              
61 22         31 $out.= ' \my %fields=$href;
62             ';
63 22 50       154 $out.=' my %options=%opts;
64             ' if keys %opts;
65 22         81 for($opts{use}->@*){
66 1         2 $out.="use $_;\n";
67             }
68 22         394 for($opts{inject}->@*){
69 1         7 $out.="$_\n";
70             }
71              
72 22 50       67 $out.=lexical($href) unless $opts{no_alias}; #add aliased variables from hash
73 22         286 $out.='
74             my %cache; #Stores code refs using caller as keys
75              
76             sub clear {
77             %cache=();
78             }
79              
80             sub skip{
81             goto _PLEX_SKIP;
82             }
83              
84             $plex->[Template::Plex::skip_]=\&skip;
85              
86              
87             sub init :prototype(&){
88             $self->_init(@_);
89             }
90              
91             sub slot {
92             $self->slot(@_);
93             }
94             sub fill_slot {
95             $self->fill_slot(@_);
96             }
97             sub append_slot {
98             $self->append_slot(@_);
99             }
100              
101             sub prepend_slot {
102             $self->prepend_slot(@_);
103             }
104              
105             sub fill_var{
106             my $name=shift;
107             no strict "refs";
108             $$name=shift;
109             "";
110             }
111              
112             sub append_var{
113             my $name=shift;
114             no strict "refs";
115             $$name .= shift;
116             "";
117              
118             }
119             sub prepend_var{
120             my $name=shift;
121             no strict "refs";
122             $$name = shift . $$name;
123             "";
124              
125             }
126              
127              
128             sub inherit {
129             $self->inherit(@_);
130             }
131              
132             sub load {
133             $self->load(@_);
134             }
135              
136             sub cache {
137             my @args=@_;
138             if(@args ==1){
139             # Recalling implicit cache key with path only
140             unshift @args, undef;
141             }
142             elsif(defined($args[1]) and ref($args[1]) eq "HASH"){
143             # variables hash ref given, with implicit cache id
144             unshift @args, undef;
145             }
146             else{
147             # Expect explicit cache Id
148             }
149              
150             my ($id, $path, $var, @opts)=@args;
151             #we want to cache based on the caller
152             $id=$path.join "", caller;
153             #unshift @_, $id;
154             $self->cache($id,$path, $var,@opts);
155             }
156              
157             sub immediate {
158             my @args=@_;
159             if(@args ==1){
160             # Recalling implicit cache key with path only
161             unshift @args, undef;
162             }
163             elsif(defined($args[1]) and ref($args[1]) eq "HASH"){
164             # variables hash ref given, with implicit cache id
165             unshift @args, undef;
166             }
167             else{
168             # Expect explicit cache Id
169             }
170             my ($id, $path, $var, @opts)=@args;
171             #we want to cache based on the caller
172             $id=$path.join "", caller;
173             my $template=$self->cache($id, $path,$var, @opts);
174             if($template){
175             return $template->render;
176             }
177             "";
178             }
179              
180              
181             sub {
182             no warnings \'uninitialized\';
183             no strict;
184             #my $plex=shift;
185             my $self=shift;
186              
187             \\my %fields=shift//\\%fields;
188              
189              
190             ##__START
191             return $self->prefix.
192             qq
193             {'.
194             $_data_
195             . '}
196             .$self->postfix;
197             _PLEX_SKIP:
198             "";
199             }
200             ##__END
201             };';
202              
203             };
204              
205             # First argument the template string/text. This is any valid perl code
206             # Second argument is a hash ref to default or base level fields
207             # returns a code reference which when called renders the template with the values
208             sub _prepare_template{
209 3     3   21 no warnings qw;
  3         6  
  3         2873  
210 22     22   86 my ($plex, undef, $href, %opts)=@_;
211 22   50     50 $href//={};
212 22         114 \my %fields=$href;
213 22         41 \my %meta=\%opts;
214              
215             #$plex now variable is now of base class
216 22   100     134 $plex=($opts{base}//"Template::Plex")->new($plex);
217              
218 22         475 $plex->[Template::Plex::meta_]=\%opts;
219 22         48 $plex->[Template::Plex::args_]=$href;
220              
221 22         48 my $prog=&Template::Plex::Internal::bootstrap;
222 3 50 33 3   21 my $ref=eval $prog;
  3 50 0 3   6  
  3 0 0 3   201  
  3 0 0 3   18  
  3 0 0 3   10  
  3 0 33 3   746  
  3 0 0 3   20  
  3 0 0 3   5  
  3 0 0 3   616  
  3 0 0 3   55  
  3 0 0 3   8  
  3 50 0 3   178  
  3 50 0 3   17  
  3 50 33 3   5  
  3 0 0 3   1055  
  3 0 0 3   23  
  3 0 33 3   6  
  3 0 0 3   143  
  3 0 0 3   17  
  3 0   3   6  
  3 0   3   811  
  3 0   3   22  
  3 0   3   6  
  3 0   3   212  
  3 0   3   19  
  3 0   3   7  
  3 0   3   635  
  3 50   3   19  
  3 50   1   6  
  3 50   1   593  
  3 0   1   20  
  3 0   1   6  
  3 0   1   176  
  3 0   1   18  
  3 0   1   16  
  3 0   1   978  
  3 50   2   23  
  3 50   1   6  
  3 50   1   133  
  3 0   1   17  
  3 0   1   6  
  3 0   1   797  
  3 0   1   22  
  3 0   1   6  
  3 0   1   195  
  3     4   18  
  3     1   14  
  3     1   618  
  3     1   19  
  3     1   6  
  3     1   540  
  3     1   19  
  3     1   6  
  3     2   160  
  3     1   30  
  3     1   6  
  3     2   961  
  3     1   21  
  3     2   9  
  3     1   145  
  3     5   17  
  3     5   20  
  3     5   609  
  3     6   23  
  3     1   6  
  3     2   188  
  3     5   17  
  3     5   6  
  3     3   675  
  3     3   26  
  3     3   7  
  3     3   569  
  3     1   20  
  3     3   5  
  3     4   167  
  3     3   18  
  3     6   6  
  3     4   943  
  3     2   22  
  3     2   6  
  3     1   168  
  3     6   18  
  3     2   6  
  3     1   552  
  22     0   2228  
  1     0   6  
  1     0   3  
  1     0   66  
  1         6  
  1         3  
  1         62  
  1         6  
  1         1  
  1         434  
  1         8  
  1         2  
  1         28  
  1         5  
  1         2  
  1         178  
  1         7  
  2         6  
  2         80  
  1         6  
  1         3  
  2         278  
  2         13  
  2         13  
  1         66  
  1         6  
  1         2  
  1         60  
  1         6  
  1         1  
  1         420  
  1         8  
  1         1  
  1         29  
  1         5  
  1         9  
  1         161  
  1         7  
  1         2  
  1         64  
  1         7  
  1         1  
  1         286  
  1         7  
  1         2  
  1         83  
  1         7  
  1         2  
  1         68  
  1         6  
  4         13  
  1         427  
  1         7  
  1         2  
  1         30  
  1         5  
  1         2  
  1         153  
  1         7  
  1         2  
  1         65  
  1         6  
  1         2  
  1         295  
  1         8  
  1         2  
  1         73  
  1         6  
  1         2  
  1         61  
  1         6  
  1         1  
  1         426  
  1         7  
  1         2  
  2         31  
  2         14  
  1         6  
  1         144  
  2         10  
  2         8  
  2         55  
  2         12  
  2         6  
  1         297  
  1         7  
  1         2  
  1         64  
  1         19  
  1         2  
  1         97  
  1         6  
  1         2  
  1         371  
  1         7  
  1         2  
  1         28  
  1         5  
  1         1  
  1         180  
  1         7  
  1         2  
  1         70  
  1         8  
  1         2  
  2         270  
  1         7  
  2         16  
  1         76  
  5         38  
  5         15  
  5         81  
  5         18  
  1         2  
  2         395  
  4         15  
  5         12  
  3         49  
  3         12  
  3         16  
  3         156  
  0         0  
  2         6  
  3         8  
  2         7  
  2         5  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  3         26  
  3         28  
  1         9  
  2         20  
  1         8  
  6         28  
  2         21  
  1         9  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  1         2  
  1         7  
  0         0  
  0         0  
  1         3  
  1         6  
  1         3  
  1         5  
  1         3  
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
223 22 100 66     136 if($@ and !$ref){
224 3         8 my $e=$@; #Save the error as require will nuke it
225 3         685 require Error::Show;
226 3         4904 my $context=Error::Show::context(error=>$e, program=>$prog,
227             start_mark=>'##__START',
228             end_mark=>'##__END',
229             start_offset=>2,
230             end_offset=>5,
231             limit=>1
232             );
233             # Replace the sudo filename with the file name if we have one
234 3         1304 my $filename=$meta{file};
235 3         70 $context=~s/(\(eval \d+\))/$filename/g;
236             # Rethrow the exception, translated context line numbers
237 3         22 die $context;
238             }
239 20         39 $plex->[Template::Plex::sub_]=$ref;
240 20         398 $plex;
241             }
242              
243             #a little helper to allow 'including' templates into each other
244             sub _munge {
245 1     1   9 my ($input, %options)=@_;
246              
247             #test for literals
248 1         9 my $path;
249 1 0       9 if($input =~ /^"(.*)"$/){
    0          
250             #literal
251 1         9 $path=$1;
252             }
253             elsif($input =~ /^'(.*)'$/){
254             #literal
255 1         9 $path=$1;
256             }
257             else {
258             #not supported?
259             #
260             }
261 0         0 Template::Plex::Internal->new(\&_prepare_template,$path,"",%options);
262             }
263              
264             sub _subst_inject {
265 22     22   54 \my $buffer=\(shift);
266 22         139 while($buffer=~s|$Include|_munge($1, @_)|e){
  2         14  
267             #TODO: Possible point for diagnostics?
268             };
269             }
270              
271             sub _block_fix {
272             #remove any new line immediately after a ]} pair
273 21     22   35 \my $buffer=\(shift);
274            
275 21         148 $buffer=~s/^(\s*\@\{\[.*?\]\})\n/$1/gms;
276             }
277              
278             sub _comment_strip {
279 0     1   0 \my $buffer=\(shift);
280 0         0 $buffer=~s/^\s*#.*?\n//gms;
281             }
282              
283              
284             sub _init_fix{
285 21     22   40 \my $buffer=\$_[0];
286             #Look for an init block
287             #unless($buffer=~/\@\[\{\s*init\s*\{
288 21 100       124 unless($buffer=~$Init){
289 6         17 $buffer="\@{[init{}]}".$buffer;
290             }
291             }
292              
293             my $prepare=\&_prepare_template;
294              
295             my %cache;
296              
297              
298             sub clear {
299 0     0 0 0 %cache=();
300             }
301              
302              
303             sub block :prototype(&) {
304 1     2 0 21 $_[0]->();
305 1         7 return "";
306             }
307             *pl=\*block;
308              
309              
310              
311             sub new{
312 21     22 0 53 my $plex=bless [], shift;
313 21         62 my ($prepare, $path, $args, %options)=@_;
314 21         40 my $root=$options{root};
315             #croak "plex: even number of arguments required" if (@_-1)%2;
316 21 50       52 croak "Template::Plex::Internal first argument must be defined" unless defined $path;
317             #croak "plex: at least 2 arguments needed" if ((@_-1) < 2);
318              
319 21         31 my $data=do {
320 21         78 local $/=undef;
321 21 50       78 if(ref($path) eq "GLOB"){
    100          
322             #file handle
323 0         0 $options{file}="$path";
324 0         0 <$path>;
325             }
326             elsif(ref($path) eq "ARRAY"){
327             #process as inline template
328 14         38 $options{file}="$path";
329 14         62 join "", @$path;
330             }
331             else{
332             #Assume a path
333             #Prepend the root if present
334 7         19 $options{file}=$path;
335 7 50       66 $path=catfile $root, $path if $root;
336 7         16 my $fh;
337 7 50       338 if(open $fh, "<", $path){
338             <$fh>
339 8         375 }
340             else {
341 1         7 croak "Could not open file: $path $!";
342 0         0 "";
343             }
344             }
345             };
346              
347 21   66     81 $args//={}; #set to empty hash if not defined
348            
349 22 50       80 chomp $data unless $options{no_eof_chomp};
350             # Perform inject substitution
351             #
352 22 50       85 _subst_inject($data, root=>$root) unless $options{no_include};
353             # Perform superfluous EOL removal
354             #
355 22 50       76 _block_fix($data) unless $options{no_block_fix};
356 22 50       88 _init_fix($data) unless $options{no_init_fix};
357 22 50       61 _comment_strip($data) if $options{use_comments};
358              
359 21 50       43 if($args){
360             #Only call this from top level call
361             #Returns the render sub
362              
363 21         36 state $package=0;
364 21         38 $package++;
365 21         73 $options{package}="Template::Plex::temp".$package; #force a unique package if non specified
366 21         68 $prepare->($plex, $data, $args, %options); #Prepare in the correct scope
367             }
368             else {
369 0         0 $data;
370             }
371             }
372              
373              
374             #Join map
375             sub jmap :prototype(&$@){
376 0     2 0 0 my ($sub,$delimiter)=(shift,shift); #block is first
377 0   0     0 $delimiter//=""; #delimiter is whats left
378 0         0 join $delimiter, map &$sub, @_;
379             }
380              
381              
382              
383             1;