File Coverage

blib/lib/Template/Plex.pm
Criterion Covered Total %
statement 136 165 82.4
branch 29 42 69.0
condition 13 24 54.1
subroutine 32 38 84.2
pod 15 21 71.4
total 225 290 77.5


line stmt bran cond sub pod time code
1             package Template::Plex;
2              
3 2     2   155944 use strict;
  2         8  
  2         56  
4 2     2   10 use warnings;
  2         4  
  2         60  
5              
6 2     2   12 use version; our $VERSION = version->declare('v0.5.0');
  2         4  
  2         11  
7 2     2   179 use feature qw;
  2         4  
  2         182  
8 2     2   12 no warnings "experimental";
  2         4  
  2         88  
9              
10              
11 2     2   3539 use Log::ger;
  2         101  
  2         11  
12 2     2   533 use Log::OK; #Allow control of logging from the command line
  2         5  
  2         21  
13              
14 2     2   18112 use Symbol qw;
  2         1545  
  2         132  
15              
16 2     2   15 use constant KEY_OFFSET=>0;
  2         4  
  2         157  
17 2         13 use enum ("plex_=0",qw
18              
19             cache_
20             slots_ parent_ default_result_
21 2     2   938 >);
  2         2246  
22              
23 2     2   2093 use constant KEY_COUNT=>default_result_ - plex_ +1;
  2         4  
  2         110  
24              
25             #Template::Plex::Internal uses the field name constants so import it AFTER
26             #we define them
27 2     2   866 use Template::Plex::Internal;
  2         6  
  2         4441  
28              
29             our %top_level_cache;
30             sub new {
31 21     21 0 44 my ($package, $plex)=@_;
32 21         34 my $self=[];
33 21         49 $self->[plex_]=$plex;
34 21         48 $self->[cache_]={};
35 21         61 bless $self, $package;
36             }
37             sub get_cache {
38 0     0 0 0 $_[0][cache_];
39             }
40              
41             #Returns a template loaded and intialised
42             sub load {
43 21     21 1 3596 my ($self, $path, $vars, %opts)=@_;
44 21         39 my $template;
45 21 100       55 if(ref($self)){
46 6         8 Log::OK::TRACE and log_trace __PACKAGE__." instance load called for $path";
47 6         19 \my %fields=$self->args;
48              
49 6         13 my %options=$self->meta->%{qw}; #copy
50 6 100       40 $template=Template::Plex::Internal->new(\&Template::Plex::Internal::_prepare_template, $path, $vars?$vars:\%fields, %opts?%opts:%options);
    100          
51              
52             }
53             else{
54 15         21 Log::OK::TRACE and log_trace __PACKAGE__." class load called for $path";
55             #called on package
56 15         68 $template=Template::Plex::Internal->new(\&Template::Plex::Internal::_prepare_template, $path, $vars, %opts);
57              
58             }
59 19         94 $template->setup;
60 19         51 $template;
61             }
62              
63             #Returns a template which was already loaded can called from the callers position
64             sub cache {
65 10     10 1 367 my ($self, $id, $path, $vars, %opts)=@_;
66 10         15 Log::OK::TRACE and log_trace __PACKAGE__." cache: $path";
67 10   66     40 $id//=$path.join "", caller; #Set if undefined
68 10 100       37 if(ref($self)){
69 4 50       13 $self->[cache_]{$id} and return $self->[cache_]{$id};
70              
71 4         26 my $template=$self->load($path, $vars,%opts);
72 4   33     109 $self->[cache_]{$id}//=$template;
73             }
74             else{
75 6 100       18 $top_level_cache{$id} and return $top_level_cache{$id};
76              
77 5         15 my $template=$self->load($path, $vars,%opts);
78 5   33     39 $top_level_cache{$id}//=$template;
79              
80             }
81             }
82             sub immediate {
83 4     4 1 1662 my ($self, $id, $path, $vars, @opts)=@_;
84              
85 4         8 Log::OK::TRACE and log_trace __PACKAGE__." cache: $path";
86 4   33     50 $id//=$path.join "", caller; #Set if undefined
87            
88 4         14 my $template=$self->cache($id, $path, $vars,@opts);
89 4 50       15 return $template->render if $template;
90 0         0 "";
91              
92             }
93              
94             sub _plex_ {
95 0     0   0 $_[0][Template::Plex::plex_];
96             }
97              
98 8     8 1 35 sub meta :lvalue { $_[0][Template::Plex::meta_]; }
99              
100 9     9 1 24 sub args :lvalue{ $_[0][Template::Plex::args_]; }
101              
102 59     59 0 133 sub init_done_flag:lvalue{ $_[0][Template::Plex::init_done_flag_]; }
103              
104              
105             sub _render {
106             #sub in plex requires self as first argument
107 41     41   1026 return $_[0][sub_](@_);
108             }
109              
110             sub skip {
111 21     21 1 21 Log::OK::DEBUG and log_debug("Template::Plex: Skipping Template: ".$_[0]->meta->{file});
112 21         416 $_[0]->[skip_]->();
113             }
114              
115             #A call to this method will run the sub an preparation
116             #and immediately stop rendering the template
117             sub _init {
118 41     41   78 my ($self, $sub)=@_;
119            
120 41 100       390 return if $self->[init_done_flag_];
121 21         28 Log::OK::DEBUG and log_debug("Template::Plex: Initalising Template: ".$self->meta->{file});
122 21 50       104 unless($self->isa("Template::Plex")){
123             #if($self->[meta_]{package} ne caller){
124 0         0 Log::OK::ERROR and log_error("Template::Plex: init must only be called within a template: ".$self->meta->{file});
125 0         0 return;
126             }
127              
128 21         52 $self->pre_init;
129 21         432 $sub->();
130 21         55 $self->post_init;
131              
132 21         37 $self->[init_done_flag_]=1;
133 21         50 $self->skip;
134 0         0 ""; #Must return an empty string
135             }
136              
137       21 1   sub pre_init {
138              
139             }
140              
141       21 1   sub post_init {
142              
143             }
144       41 0   sub prefix {
145             }
146       19 0   sub postfix {
147             }
148              
149             #Execute the template in setup mode
150             sub setup {
151 21     21 0 58 my $self=shift;
152             #Test that the caller is not the template package
153 21         30 Log::OK::DEBUG and log_debug("Template::Plex: Setup Template: ".$self->meta->{file});
154 21 50       69 if($self->[meta_]{package} eq caller){
155             #Log::OK::ERROR and log_error("Template::Plex: setup must only be called outside a template: ".$self->meta->{file});
156             # return;
157             }
158 21         40 $self->[init_done_flag_]=undef;
159 21         71 $self->render(@_);
160            
161             #Check if an init block was used
162 21 50       55 unless($self->[init_done_flag_]){
163 0         0 Log::OK::WARN and log_warn "Template::Plex ignoring no \@{[init{...}]} block in template from ". $self->meta->{file};
164 0         0 $self->[init_done_flag_]=1;
165             }
166 21         36 "";
167             }
168              
169             # Slotting and Inheritance
170             #
171             #
172              
173             #Marks a slot in a parent template.
174             #A child template can fill this out by calling fill_slot on the parent
175             sub slot {
176 6     6 1 16 my ($self, $slot_name, $default_value)=@_;
177 6   100     18 $slot_name//="default"; #If no name assume default
178              
179 6         7 Log::OK::TRACE and log_trace __PACKAGE__.": Template called slot: $slot_name";
180 6         12 my $data=$self->[slots_]{$slot_name};
181 6         8 my $output="";
182            
183 6   66     14 $data//=$default_value;
184 6 100       27 if($data->isa("Template::Plex")){
185             #render template
186 3 100       12 if($slot_name eq "default"){
187 2         4 Log::OK::TRACE and log_trace __PACKAGE__.": copy default slot";
188 2   50     7 $output.=$self->[default_result_]//"";
189             }
190             else {
191 1         2 Log::OK::TRACE and log_trace __PACKAGE__.": render non default template slot";
192 1         6 $output.=$data->render;
193             }
194             }
195             else {
196 3         5 Log::OK::TRACE and log_trace __PACKAGE__.": render non template slot";
197             #otherwise treat as text
198 3   50     11 $output.=$data//"";
199             }
200 6         129 $output
201             }
202              
203             sub fill_slot {
204 3     3 1 21 my ($self)=shift;
205 3         7 my $parent=$self->[parent_];
206 3 50       22 unless($parent){
207 0         0 Log::OK::WARN and log_warn __PACKAGE__.": No parent setup for: ". $self->meta->{file};
208 0         0 return;
209             }
210              
211 3 50       15 unless(@_){
212             #An unnamed fill spec implies the default slot
213 0         0 $parent->[slots_]{default}=$self;
214             }
215             else{
216             #5.36 multi element for loop
217             #disabled for backwards compatability
218             #
219             #for my ($k,$v)(@_){
220             # $parent->[slots_]{$k}=$v;
221             #}
222              
223 3         30 my %fillers=@_;
224 3         13 for (keys %fillers){
225 3         19 $parent->[slots_]{$_}=$fillers{$_};
226             }
227             }
228 3         56 "";
229             }
230              
231             sub append_slot {
232 0     0 1 0 my($self)=shift;
233 0         0 my $parent=$self->[parent_];
234 0 0       0 unless($parent){
235              
236 0         0 Log::OK::WARN and log_warn __PACKAGE__.": No parent setup for ". $self->meta->{file};
237             return
238 0         0 }
239             else{
240 0         0 my %fillers=@_;
241 0         0 for(keys %fillers){
242 0         0 $parent->[slots_]{$_}.=$fillers{$_};
243             }
244             }
245             }
246              
247             sub prepend_slot {
248 0     0 1 0 my($self)=shift;
249 0         0 my $parent=$self->[parent_];
250 0 0       0 unless($parent){
251              
252 0         0 Log::OK::WARN and log_warn __PACKAGE__.": No parent setup for ". $self->meta->{file};
253             return
254 0         0 }
255             else{
256 0         0 my %fillers=@_;
257 0         0 for(keys %fillers){
258 0         0 $parent->[slots_]{$_}=$fillers{$_}.$parent->[slots_]{$_};
259             }
260             }
261             }
262              
263              
264              
265             sub inherit {
266 2     2 1 5 my ($self, $path)=@_;
267 2         3 Log::OK::DEBUG and log_debug __PACKAGE__.": Inherit: $path";
268             #If any parent variables have be setup load the parent template
269              
270             #Setup the parent. Cached with path
271 2         4 my $p=$self->load($path, $self->args, $self->meta->%*);
272 2         5 $p->[slots_]={};
273              
274             #Add this template to the default slot
275 2         5 $p->[slots_]{default}=$self;
276 2         6 $self->[parent_]=$p;
277             }
278              
279             sub render {
280 59     59 1 1410 my ($self, $fields, $top_down)=@_;
281             #We don't call parent render if we are uninitialised
282              
283              
284            
285             #If the template uninitialized, we just do a first pass
286 59 100       111 unless($self->init_done_flag){
287              
288 21         58 return $self->_render;
289              
290             }
291              
292 38         47 Log::OK::TRACE and log_trace __PACKAGE__.": render :".$self->meta->{file}." flag: ".($top_down//"");
293              
294             #locate the 'top level' template and call downwards
295 38         55 my $p=$self;
296 38 100       74 if(!$top_down){
297 18         41 while($p->[parent_]){
298 2         4 $p=$p->[parent_];
299             }
300 18         42 $p->render($fields,1);
301             }
302             else{
303             #This is Normal template or top of hierarchy
304             #child has called parent and parent is the top
305             #
306             #Turn it around and call back down the chain
307             #
308              
309 20         25 Log::OK::TRACE and log_trace __PACKAGE__.": render: no parent bottom up. assume normal render";
310             #Check slots. Slots indicate we need to call the child first
311 20 100 66     52 if($self->[slots_] and $self->[slots_]->%*){
312 2         3 Log::OK::TRACE and log_trace __PACKAGE__.": render: rendering default slot";
313 2         18 $self->[default_result_]=$self->[slots_]{default}->render($fields,1);
314             }
315              
316             #now call render on self. This renders non hierarchial templates
317 20         26 Log::OK::TRACE and log_trace __PACKAGE__.": render: rendering body and sub templates";
318 20         41 my $total=$self->_render($fields); #Call down the chain with top_down flag
319 20         48 $self->[default_result_]=""; #Clear
320 20         91 return $total;
321             }
322             }
323              
324 0     0 1 0 sub parent {$_[0][parent_];}
325              
326              
327              
328              
329              
330              
331              
332             sub DESTROY {
333 0 0   0   0 delete_package $_[0][package_] if $_[0][package_];
334             }
335              
336             #Internal testing use only
337             sub __internal_test_proxy__ {
338 1     1   6 "PROXY";
339             }
340              
341             1;