File Coverage

blib/lib/Template/Plex.pm
Criterion Covered Total %
statement 164 203 80.7
branch 38 58 65.5
condition 20 39 51.2
subroutine 33 39 84.6
pod 16 23 69.5
total 271 362 74.8


line stmt bran cond sub pod time code
1             package Template::Plex;
2              
3 4     4   378147 use strict;
  4         8  
  4         164  
4 4     4   41 use warnings;
  4         8  
  4         352  
5              
6             our $VERSION = 'v0.9.4';
7 4     4   103 use feature qw;
  4         12  
  4         724  
8 4     4   29 no warnings "experimental";
  4         24  
  4         307  
9              
10              
11 4     4   9706 use Log::ger;
  4         277  
  4         23  
12 4     4   2657 use Log::OK; #Allow control of logging from the command line
  4         9659  
  4         26  
13              
14 4     4   21655 use Symbol qw;
  4         6092  
  4         408  
15              
16 4     4   36 use constant::more KEY_OFFSET=>0;
  4         10  
  4         25  
17 4     4   689 use constant::more DEBUG=>0;
  4         7  
  4         20  
18              
19 4         42 use constant::more {plex_=>0, meta_=>1, args_=>2, sub_=>3,
20             package_=>4, init_done_flag_=>5, skip_=>6,
21             cache_=>7, slots_=>8, parent_=>9, default_result_=>10, id_=>11, ref_cache_=>12
22 4     4   624 };
  4         9  
23              
24 4     4   3123 use constant::more KEY_COUNT=>ref_cache_ - plex_ +1;
  4         8  
  4         21  
25              
26             #Template::Plex::Internal uses the field name constants so import it AFTER
27             #we define them
28 4     4   2999 use Template::Plex::Internal;
  4         17  
  4         180  
29              
30             our %top_level_cache;
31             sub new {
32 24     24 0 59 my ($package, $plex)=@_;
33 24         43 my $self=[];
34             #$self->[plex_]=$plex;
35 24         77 $self->[cache_]={};
36 24         59 $self->[slots_]={};
37 24         78 bless $self, $package;
38             }
39              
40             sub get_cache {
41 0     0 0 0 $_[0][cache_];
42             }
43              
44             #Returns a template loaded and intialised
45             sub load {
46 24     24 1 681147 my ($self, $path, $vars, %opts)=@_;
47 24         48 my $template;
48 24 100       79 if(ref($self)){
49 6         8 DEBUG and Log::OK::TRACE and log_trace __PACKAGE__." instance load called for $path";
50 6         16 \my %fields=$self->args;
51              
52 6         17 my %options=$self->meta->%{qw}; #copy
53 6 100       16 if(%opts){
54 2         4 $opts{caller}=$self;
55             }
56             else {
57 4         11 $options{caller}=$self;
58             }
59            
60 6 100       52 $template=Template::Plex::Internal->new(\&Template::Plex::Internal::_prepare_template, $path, $vars?$vars:\%fields, %opts?%opts:%options);
    100          
61              
62             }
63             else{
64 18         27 DEBUG and Log::OK::TRACE and log_trace __PACKAGE__." class load called for $path";
65             #called on package
66 18         39 my $dummy=[];
67 18         118 $dummy->[Template::Plex::meta_]={file=>(caller)[1]};
68 18         49 bless $dummy, "Template::Plex";
69 18         102 $opts{caller}=$dummy;
70              
71 18         159 $template=Template::Plex::Internal->new(\&Template::Plex::Internal::_prepare_template, $path, $vars, %opts);
72              
73             }
74 22         123 $template->setup;
75 22         88 $template;
76             }
77              
78             #Returns a template which was already loaded can called from the callers position
79             #
80             #TODO: special case where the second argument is a hash ref or undef
81             # This indicates no id was specified so use implicit cache entry
82             # path must always be defined.
83             # eg
84             # cache undef, "path", .... ; #will use explicit cache key
85             # cache "path", {var}; #Use implicit cache key
86             # cache "path"; #Use implicit cache key
87             #
88             # This tidies up the common use case for cached templates
89             sub cache {
90 12     12 1 554 my $self=shift;
91 12         36 my @args=@_;
92              
93 12 50 33     75 if(@args ==1){
    50          
94             # Recalling implicit cache key with path only
95 0         0 unshift @args, undef;
96             }
97             elsif(defined($args[1]) and ref($args[1]) eq "HASH"){
98             # variables hash ref given, with implicit cache id
99 0         0 unshift @args, undef;
100             }
101             else{
102             # Expect explicit cache Id
103             }
104              
105 12         36 my ($id, $path, $vars, %opts)=@args;
106              
107             #my ($self, $id, $path, $vars, %opts)=@_;
108 12         18 DEBUG and Log::OK::TRACE and log_trace __PACKAGE__." cache: $path";
109 12   66     49 $id//=$path.join "", caller; #Set if undefined
110             #say STDERR "-=----IN CACHE id=$id, path=$path, vars=", %$vars, %opts;
111             #use Data::Dumper;
112             #say STDERR Dumper [$id, $path, $vars, \%opts];
113             #sleep 1;
114 12 100       31 if(ref($self)){
115 4         10 my $c=$self->[cache_]{$id};
116 4 50       29 if($c){
117 0         0 return $c;
118             }
119             else {
120 4         17 my $template=$self->load($path, $vars, %opts);
121 4         15 $template->[id_]=$id;
122 4         9 $template->[ref_cache_]=$self->[cache_];
123            
124 4   33     131 $self->[cache_]{$id}//=$template;
125             }
126             }
127             else{
128 8         17 my $c=$top_level_cache{$id};
129 8 100       21 if($c){
130 2         7 return $c
131             }
132             else {
133 6         29 my $template=$self->load($path, $vars, %opts);
134 6         23 $template->[id_]=$id;
135 6         17 $template->[ref_cache_]=\%top_level_cache;
136 6   33     55 $top_level_cache{$id}//=$template;
137             }
138             }
139             }
140              
141             #TODO: add parameter checking as per cache
142             sub immediate {
143 6     6 1 247317 DEBUG and Log::OK::TRACE and log_trace __PACKAGE__." immediate!!";
144            
145 6         17 my $self=shift;
146 6         22 my @args=@_;
147 6 50 33     62 if(@args ==1){
    50          
148             # Recalling implicit cache key with path only
149 0         0 unshift @args, undef;
150             }
151             elsif(defined($args[1]) and ref($args[1]) eq "HASH"){
152             # variables hash ref given, with implicit cache id
153 0         0 unshift @args, undef;
154             }
155             else{
156             # Expect explicit cache Id, path, vars and options
157             }
158              
159 6         19 my ($id, $path, $vars, @opts)=@args;
160              
161              
162 6         13 DEBUG and Log::OK::TRACE and log_trace __PACKAGE__." immediate: $path";
163 6   66     48 $id//=$path.join "", caller; #Set if undefined
164            
165 6         24 my $template=$self->cache($id, $path, $vars, @opts);
166 6 50       32 return $template->render($vars) if $template;
167 0         0 "";
168              
169             }
170              
171              
172             #########################################
173             # sub _plex_ { #
174             # $_[0][Template::Plex::plex_]; #
175             # } #
176             #########################################
177              
178 10     10 1 61 sub meta :lvalue { $_[0][Template::Plex::meta_]; }
179              
180 9     9 1 26 sub args :lvalue{ $_[0][Template::Plex::args_]; }
181              
182 66     66 0 196 sub init_done_flag:lvalue{ $_[0][Template::Plex::init_done_flag_]; }
183              
184              
185             sub _render {
186             #sub in plex requires self as first argument
187 46     46   1646 return $_[0][sub_](@_);
188             }
189              
190             sub skip {
191 24     24 1 34 DEBUG and Log::OK::DEBUG and log_debug("Template::Plex: Skipping Template: ".$_[0]->meta->{file});
192 24         600 $_[0]->[skip_]->();
193             }
194              
195             #A call to this method will run the sub an preparation
196             #and immediately stop rendering the template
197             sub _init {
198 46     46   98 my ($self, $sub)=@_;
199            
200 46 100       514 return if $self->[init_done_flag_];
201 24         30 DEBUG and Log::OK::DEBUG and log_debug("Template::Plex: Initalising Template: ".$self->meta->{file});
202 24 50       142 unless($self->isa("Template::Plex")){
203             #if($self->[meta_]{package} ne caller){
204 0         0 DEBUG and Log::OK::ERROR and log_error("Template::Plex: init must only be called within a template: ".$self->meta->{file});
205 0         0 return;
206             }
207              
208 24         73 $self->pre_init;
209 24         686 $sub->();
210 24         104 $self->post_init;
211              
212 24         45 $self->[init_done_flag_]=1;
213 24         68 $self->skip;
214 0         0 ""; #Must return an empty string
215             }
216              
217       24 1   sub pre_init {
218              
219             }
220              
221       24 1   sub post_init {
222              
223             }
224       46 0   sub prefix {
225             }
226       21 0   sub postfix {
227             }
228              
229             #Execute the template in setup mode
230             sub setup {
231 24     24 0 57 my $self=shift;
232             #Test that the caller is not the template package
233 24         40 DEBUG and Log::OK::DEBUG and log_debug("Template::Plex: Setup Template: ".$self->meta->{file});
234 24 50       126 if($self->[meta_]{package} eq caller){
235             #Log::OK::ERROR and log_error("Template::Plex: setup must only be called outside a template: ".$self->meta->{file});
236             # return;
237             }
238 24         58 $self->[init_done_flag_]=undef;
239 24         96 $self->render(@_);
240            
241             #Check if an init block was used
242 24 50       79 unless($self->[init_done_flag_]){
243 0         0 DEBUG and Log::OK::WARN and log_warn "Template::Plex ignoring no \@{[init{...}]} block in template from ". $self->meta->{file};
244 0         0 $self->[init_done_flag_]=1;
245             }
246 24         84 "";
247             }
248              
249             # Slotting and Inheritance
250             #
251             #
252              
253             #Marks a slot in a parent template.
254             #A child template can fill this out by calling fill_slot on the parent
255             sub slot {
256 6     6 1 10 my ($self, $slot_name, $default_value)=@_;
257 6   100     12 $slot_name//="default"; #If no name assume default
258              
259 6         8 my $root=$self->find_root;
260 6         9 DEBUG and Log::OK::TRACE and log_trace __PACKAGE__.": Template called slot: $slot_name";
261 6         11 my $data=$root->[slots_]{$slot_name};
262 6         7 my $output="";
263            
264 6   66     12 $data//=$default_value;
265 6 100 66     34 if(defined($data) and ref $data and $data->isa("Template::Plex")){
      66        
266             #render template
267 3 100       7 if($slot_name eq "default"){
268 2         2 DEBUG and Log::OK::TRACE and log_trace __PACKAGE__.": copy default slot";
269 2   50     9 $output.=$self->[default_result_]//"";
270             }
271             else {
272 1         1 DEBUG and Log::OK::TRACE and log_trace __PACKAGE__.": render non default template slot";
273 1         3 $output.=$data->render;
274             }
275             }
276             else {
277 3         4 DEBUG and Log::OK::TRACE and log_trace __PACKAGE__.": render non template slot";
278             #otherwise treat as text
279 3   50     4 $output.=$data//"";
280             }
281 6         88 $output
282             }
283              
284             sub fill_slot {
285 3     3 1 24 my ($self)=shift;
286             #my $parent=$self->[parent_]//$self;
287 3         12 my $parent=$self->find_root;
288 3 50       6 unless($parent){
289 0         0 DEBUG and Log::OK::WARN and log_warn __PACKAGE__.": No parent setup for: ". $self->meta->{file};
290 0         0 return;
291             }
292              
293 3 50       6 unless(@_){
294             #An unnamed fill spec implies the default slot to which this template will be rendered
295 0         0 $parent->[slots_]{default}=$self;
296             }
297             else{
298             #5.36 multi element for loop
299             #disabled for backwards compatability
300             #
301             #for my ($k,$v)(@_){
302             # $parent->[slots_]{$k}=$v;
303             #}
304              
305 3         7 for(my $i=0; $i<@_; $i+=2){
306 3         10 $parent->[slots_]{$_[$i]}=$_[$i+1];
307             }
308              
309             }
310 3         35 "";
311             }
312              
313             sub append_slot {
314 0     0 1 0 my($self)=shift;
315             #my $parent=$self->[parent_]//$self;
316 0         0 my $parent=$self->find_root;
317 0 0       0 unless($parent){
318              
319 0         0 DEBUG and Log::OK::WARN and log_warn __PACKAGE__.": No parent setup for ". $self->meta->{file};
320             return
321 0         0 }
322             else{
323 0         0 for(my $i=0; $i<@_; $i+=2){
324 0         0 $parent->[slots_]{$_[$i]}.=$_[$i+1];
325             }
326             }
327             }
328              
329             sub prepend_slot {
330 0     0 1 0 my($self)=shift;
331             #my $parent=$self->[parent_]//$self;
332 0         0 my $parent=$self->find_root;
333 0 0       0 unless($parent){
334              
335 0         0 DEBUG and Log::OK::WARN and log_warn __PACKAGE__.": No parent setup for ". $self->meta->{file};
336             return
337 0         0 }
338             else{
339 0         0 for(my $i=0; $i<@_; $i+=2){
340 0         0 $parent->[slots_]{$_[$i]}= $_[$i+1]. $parent->[slots_]{$_[$i]}
341             }
342             }
343             }
344              
345              
346              
347              
348             sub inherit {
349 2     2 1 5 my ($self, $path, $root)=@_;
350 2         1 DEBUG and Log::OK::DEBUG and log_debug __PACKAGE__.": Inherit: $path";
351             #If any parent variables have be setup load the parent template
352              
353 2 50       5 if($path=~/::/){
354             # Package name...
355 0         0 eval "require $path";
356 0         0 ($path, $root)=$path->template_path;
357             }
358              
359             #Setup the parent. Cached with path
360 2         5 my %options=$self->meta->%*;
361 2 50       5 if($root){
362 0         0 $options{root}=$root;
363             }
364              
365             #my $p=$self->load($path, $self->args, $self->meta->%*);
366 2         4 my $p=$self->load($path, $self->args, %options);
367             #$p->[slots_]={};
368              
369             #Add this template to the default slot
370 2         6 $p->[slots_]{default}=$self;
371 2         20 $self->[parent_]=$p;
372             }
373              
374             sub render {
375 66     66 1 1867 my ($self, $fields, $top_down)=@_;
376             #We don't call parent render if we are uninitialised
377              
378              
379            
380             #If the template uninitialized, we just do a first pass
381 66 100       162 unless($self->init_done_flag){
382              
383 24         68 return $self->_render;
384              
385             }
386              
387 42         55 DEBUG and Log::OK::TRACE and log_trace __PACKAGE__.": render :".$self->meta->{file}." flag: ".($top_down//"");
388              
389             #locate the 'top level' template and call downwards
390 42         197 my $p=$self;
391 42 100       82 if(!$top_down){
392 20         56 while($p->[parent_]){
393 2         4 $p=$p->[parent_];
394             }
395 20         59 $p->render($fields,1);
396             }
397             else{
398             #This is Normal template or top of hierarchy
399             #child has called parent and parent is the top
400             #
401             #Turn it around and call back down the chain
402             #
403              
404 22         32 DEBUG and Log::OK::TRACE and log_trace __PACKAGE__.": render: no parent bottom up. assume normal render";
405             #Check slots. Slots indicate we need to call the child first
406 22 100 66     105 if($self->[slots_] and $self->[slots_]->%*){
407 2         2 DEBUG and Log::OK::TRACE and log_trace __PACKAGE__.": render: rendering default slot";
408 2 50       12 $self->[default_result_]=$self->[slots_]{default}->render($fields,1) if defined $self->[slots_]{default};
409             }
410              
411             #now call render on self. This renders non hierarchial templates
412 22         34 DEBUG and Log::OK::TRACE and log_trace __PACKAGE__.": render: rendering body and sub templates";
413 22         50 my $total=$self->_render($fields); #Call down the chain with top_down flag
414 22         88 $self->[default_result_]=""; #Clear
415 22         148 return $total;
416             }
417             }
418              
419 0     0 1 0 sub parent {$_[0][parent_];}
420              
421             sub find_root {
422 9     9 0 9 my $self=shift;
423 9         10 my $p=$self;
424 9         15 while($p->[parent_]){
425 11         15 $p=$p->[parent_];
426             }
427 9         11 return $p;
428             }
429              
430             # the callee is reomved from refernece cache if an ID is present.
431             # internal variables are released
432             #
433             sub cleanup {
434             #use Data::Dumper;
435             #say STDERR Dumper $_[0];
436 0   0 0 1 0 for($_[0][id_]//()){
437 0         0 delete $_[0][ref_cache_]{$_};
438             }
439 0         0 delete_package $_[0][meta_]{package};# if $_[0][package_];
440 0         0 $_[0]->@*=();
441 0         0 $_[0]=undef;
442             }
443              
444              
445              
446             sub DESTROY {
447             #say STDERR "DESTROY";
448 0 0   0   0 delete_package $_[0][meta_]{package} if $_[0][meta_]{package};
449             }
450              
451             #Internal testing use only
452             sub __internal_test_proxy__ {
453 1     1   7 "PROXY";
454             }
455              
456             1;