File Coverage

blib/lib/Template/Plexsite.pm
Criterion Covered Total %
statement 44 216 20.3
branch 0 36 0.0
condition 0 57 0.0
subroutine 15 34 44.1
pod 11 18 61.1
total 70 361 19.3


line stmt bran cond sub pod time code
1             package Template::Plexsite;
2              
3 1     1   16 use v5.36;
  1         4  
4              
5 1     1   7 use feature qw;
  1         2  
  1         218  
6              
7 1     1   9 use Log::ger;
  1         2  
  1         9  
8 1     1   1880 use Log::OK;
  1         2  
  1         9  
9              
10 1     1   342 use feature qw;
  1         2  
  1         74  
11 1     1   6 no warnings "experimental";
  1         2  
  1         88  
12              
13             #use Template::Plex::Internal;
14 1     1   13 use parent "Template::Plex";
  1         2  
  1         8  
15              
16             our $VERSION="v0.1.1";
17 1     1   129 use File::Basename qw;
  1         3  
  1         79  
18 1     1   6 use File::Spec::Functions qw;
  1         2  
  1         60  
19 1     1   7 use File::Path qw;
  1         2  
  1         77  
20 1     1   7 use Data::Dumper;
  1         3  
  1         78  
21              
22 1     1   7 use constant::more KEY_OFFSET=>Template::Plex::KEY_COUNT+Template::Plex::KEY_OFFSET;
  1         8  
  1         5  
23 1     1   243 use constant::more ("dependencies_=".KEY_OFFSET,qw);
  1         2  
  1         5  
24 1     1   487 use constant::more KEY_COUNT=> output_path_- dependencies_+1;
  1         2  
  1         4  
25              
26              
27             # Resolves a plt dir path to the first index found in the plt dir. Root (src
28             # root) must be supplied
29             sub _first_index_path {
30 0     0     my $self=shift;
31 0           my $path=shift;
32 0           my $root=shift;
33              
34             # Plexsite can also use a plt directory as a parent. Here we need to resolve
35             # to the first index.plex.* file located in the dir
36             #my $root=$self->meta->{root};
37 0           my $tpath;
38              
39 0 0 0       if($path =~ /\.plt$/ and -d "$root/$path"){
40             # Match the first index file. Prefer file will plex/plx as the second last extension
41             #First index.*.plex file
42 0           Log::OK::DEBUG and log_debug __PACKAGE__." testing for index at $root/$path";
43 0           ($tpath)= < $root/$path/index.plex.* $root/$path/index.plx.* $root/$path/index.*.plx $root/$path/index.*.plex >;
44 0           Log::OK::DEBUG and log_debug "Found first path: $tpath";
45             #$tpath =~ s|^$root/||;
46 0           $tpath = abs2rel($tpath, $root);
47             }
48              
49 0   0       $tpath//=$path;
50              
51 0           $tpath;
52             }
53              
54             sub new {
55 0     0 0   my $package=shift;
56 0           $package->SUPER::new(@_);
57             }
58              
59             # Take a path (relative to src) to a plex/plx or plt to use as base class
60             # First index file is use if plt is specified
61             # Overrides Template::Plex
62             #
63             sub inherit {
64 0     0 1   my $self=shift;
65 0           my $tpath=$_[0];
66 0 0         unless($tpath){
67 0           Log::OK::INFO and log_info "undefined parent template. Disabling inheritance";
68 0           return;
69             }
70              
71             # Plexsite can also use a plt directory as a parent. Here we need to resolve
72             # to the first index.plex.* file located in the dir
73 0           my $root=$self->meta->{root};
74 0           $tpath=$self->_first_index_path($tpath, $root);
75              
76             #TODO: Check that output has been called
77 0           my $table=$self->args->{table}->table;
78 0           my $entry=$table->{$self->args->{plt}};
79 0 0         unless($entry->{output}){
80 0           Log::OK::ERROR and log_error "inhert called before output in ". $self->args->{plt} ;
81             }
82 0           $self->SUPER::inherit($tpath);
83             }
84              
85             # Locates the first index.*.plex file in a plt directory and loads it
86             # as the body of the plt template.
87             #
88             # Adds important subroutines into the template namespace for resolving relative paths
89             #
90             sub load {
91 0     0 1   my ($self, $path, $args, %options)=@_;
92 0           Log::OK::TRACE and log_trace __PACKAGE__.": load called for $path";
93 0           my $meta={};
94 0 0         $meta=$self->meta if ref $self;
95              
96             #Force a template root for calls to super load
97 0   0       my $root=$options{root}//=$meta->{root};
98              
99             #Path can be to a plt dir. If so find the index file and load it
100 0           my $tpath=$self->_first_index_path($path, $root);
101              
102             #This is needed to make static class method work to load
103 0           my %l_options=$meta->%*;
104 0           $l_options{_input_path}=$path;
105 0           $l_options{root}=$root;
106 0   0       $l_options{base}=$options{base}//"Template::Plexsite";
107 0           $l_options{use}=["Template::Plexsite::Common",
108             ];
109             #wrappers subs to inject
110             $l_options{inject}=[
111 0           'sub output{
112             $self->output(@_);
113             }'
114             ,
115             'sub navi{
116             $self->navi(@_);
117             }'
118             ,
119             'sub locale {
120             $self->locale(@_);
121             }'
122             ,
123             'sub res {
124             $self->add_resource(@_);
125             }'
126             ,
127             'sub plt_res {
128             $self->add_plt_resource(@_);
129             }',
130             'sub existing_res {
131             $self->existing_resource(@_);
132             }',
133              
134             'sub sys_path_src{
135             $self->sys_path_src(@_);
136             }',
137             'sub sys_path_build{
138             $self->sys_path_build(@_);
139             }',
140             'sub plt_path{
141             $self->plt_path(@_);
142             }',
143             'sub lander {
144             $self->lander(@_);
145             }'
146              
147             ];
148              
149 0           my $template=$self->SUPER::load($tpath, $args, %l_options);
150 0           $template;
151             }
152              
153             sub pre_init {
154              
155 0     0 1   $_[0][input_path_]=$_[0]->meta->{_input_path};
156              
157             }
158              
159             sub post_init {
160 0     0 1   my ($self)=@_;
161             #Test if we have a local and load it
162 0           Log::OK::DEBUG and log_debug __PACKAGE__." post_init: ". $self->meta->{_input_path};
163 0           my $root=$self->meta->{root};
164 0           my $locale=$self->args->{locale};
165 0           for ( $self->meta->{_input_path}) {
166 0 0 0       if(/\.plt$/ and -d "$root/$_/$locale" ){
167 0           Log::OK::DEBUG and log_debug __PACKAGE__." post_init looking for locale ".$self->args->{locale};
168 0   0       $self->[locale_sub_template_]//=$self->locale;
169             }
170             }
171             }
172              
173             sub no_locale_out{
174 0     0 0   my $self=shift;
175 0           $self->args->{no_locale_out}=1;
176             }
177              
178             #Adds a resource. Input is relatative to root (src)
179             #Output dir tree mirrors the in put tree
180             #If the table entry specifies a target field, this overrides the plt path
181             #This is most useful when a template renders other templates as content instead of links
182             #
183             sub add_resource {
184 0     0 0   my ($self, $input, @options)=@_;
185             #use the URLTable object in args
186 0           my $table=$self->args->{table};
187 0           $input=$table->add_resource($input, @options);
188            
189             #return the output relative path directly
190 0   0       my $path=$table->map_input_to_output($input, $self->args->{target}//$self->args->{plt});
191 0           return $path;
192              
193            
194             }
195              
196             # Returns a path usable by IO (open etc). The input path is relative to either the src or build directory
197             #
198             sub sys_path_src {
199 0     0 1   my $self=shift;
200 0           my $path=shift;
201 0           my $root=$self->meta->{root};
202             # Return the path relative to the the root (src) dir
203 0           $root."/".$path;
204             }
205              
206             sub sys_path_build {
207 0     0 1   my $self=shift;
208 0           my $path=shift;
209 0           my $root=$self->args->{html_root};
210             # Return the path relative to the the root (src) dir
211 0           $root."/".$path;
212             }
213              
214              
215             # Returns a relative path from the current document to the resource expected
216             # to already exist in the output/build dir
217             # USE CASE: External data (ie video and jpack data) might already exist in the build directory.
218             # This function will give the required path for the document to access the file, without adding it as
219             # an explicit resource in the url table (which is only for input resources)
220             #
221             # NOTES: ASSUMES THE REFERENCE IS FILE NOT A DIRECTORY. ADD AN ARBITART COMPONENT TO REF IF IT IS A DIR
222             #
223             sub existing_resource {
224 0     0 1   my $self=shift;
225 0           my $path=shift;
226 0           my $root=$self->args->{html_root};
227 0           my $target="/".$root."/".$path;
228            
229 1     1   2045 use Data::Dumper;
  1         2  
  1         3371  
230             # Get the output location of this template
231 0           my $ref="/".$root."/".$self->output_path;
232              
233             # make a relative path from ref to target
234 0           abs2rel($target, dirname $ref);
235            
236              
237             }
238              
239              
240              
241             #resolves an input file relative to the nearest plt dir.
242             #Sets up the output so it is also relative to the output dir
243             sub add_plt_resource {
244 0     0 0   my ($self, $input, %options)=@_;
245             #input is relative to the closes plt dir
246 0           my $plt_dir=$self->[input_path_];
247 0   0       while($plt_dir ne "." and basename($plt_dir)!~/plt$/){
248 0           $plt_dir=dirname $plt_dir;
249             }
250 0           $options{output}=catfile dirname($self->output_path), $input;
251 0           my $plt_input= catfile($plt_dir,$input);
252 0           $self->add_resource(
253             $plt_input,
254             %options
255             );
256            
257             }
258              
259             # Path to a file inside a plt template. DOES NOT ADD AS RESOURCE
260             sub plt_path {
261 0     0 1   my ($self, $input, %options)=@_;
262             #input is relative to the closes plt dir
263 0           my $plt_dir=$self->[input_path_];
264 0   0       while($plt_dir ne "." and basename($plt_dir)!~/plt$/){
265 0           $plt_dir=dirname $plt_dir;
266             }
267 0           $options{output}=catfile dirname($self->output_path), $input;
268 0           my $plt_input= catfile($plt_dir,$input);
269             ########################
270             # $self->add_resource( #
271             # $plt_input, #
272             # %options #
273             # ); #
274             ########################
275            
276             }
277              
278              
279              
280             # Construct the output path base on:
281             # locale if defined
282             # output location (dir)
283             # output name if defined or basename of input template (minus the plex)
284             sub output_path {
285 0     0 0   my $self=shift;
286 0           \my %config = $self->args;
287 0 0         return unless $config{output}; #no output path when no output setup
288              
289 0           my $name=$config{output}{name};
290 0 0         unless($name){
291             #No explict output name so use the basename of input
292             #without any plex suffix
293 0           $name =basename $self->meta->{file};
294 0           $name=~s/\.plex$|\.plx$//; #Ending in plex/plx extension
295 0           $name=~s/(?:\.plex|\.plx)(?=\.)//; #Not ending in plex/plx extension
296             }
297              
298 0           my $no_locale=$config{output}{no_locale};
299             my @comps=(
300             $no_locale?():($config{locale}//()), #add locale only if we want it
301 0 0 0       $config{output}{location}||(), #If no location ensure an empty list
      0        
302             #to force root
303             $name);
304 0           my $path=catfile @comps;
305             }
306              
307              
308             #When called updates the computed table entry output field
309             #CALLED FROM WITHING A TEMLPATE
310             sub output {
311 0     0 1   my $self=shift;
312 0           my %options=@_;
313 0   0       my $output=$self->args->{output}||={};
314              
315 0           for(keys %options){
316              
317             # Clean up the location so it doesn't start with a slash
318             # otherwise it breaks the output_path function
319             #
320 0 0         if($_ eq "location"){
321 0           $options{$_}=~s|^/||;
322             }
323            
324 0           $output->{$_}=$options{$_};
325             }
326             #$output->{order}//=0;
327             #update the table entry
328 0           my $table=$self->args->{table}->table;
329 0           my $entry=$table->{$self->args->{plt}};
330 0           $entry->{output}=$self->output_path;
331             }
332              
333             #Sets the values for a navigation item in a tree like structure
334             #CALLED FROM WITHIN A TEMPLATE
335             sub navi {
336 0     0 0   my($self,%options)=@_;
337             #Options include:
338             # path: the path in the navitaiton tree
339             # href: the explicit href for anchor. If not supplied defaul it the current page?
340             # order: relative ordering to other items at the same level
341             # label: whats actually shown
342             # icon: graphics
343              
344            
345              
346             # URL table
347 0           my $table=$self->args->{table}->table;
348              
349             # Table entry
350 0           my $entry=$table->{$self->args->{plt}};
351              
352 0           \my %config=$entry->{template}{config};
353             # Split the path and navigate to the level
354 0           my @part=split m|/|, $options{path};
355              
356 0           my $parent=$config{nav}; #Root of nav object
357 0           my $inc_path="";
358 0           for my $part (@part){
359 0   0       $parent = $parent->{$part}//={
360             _data => {
361             path=>$inc_path
362             }
363             };
364 0           $inc_path .= "/";
365             }
366              
367              
368             #Copy the values
369 0           my $data=$parent->{_data};
370 0           for my ($k, $v) (%options){
371 0           $data->{$k}=$v;
372             }
373              
374             # Set the order to match render order if one wasn't supplied
375 0   0       $data->{order}//=$entry->{template}{config}{output}{order};
376              
377             # If no href use the plt or the target
378 0   0       $data->{href}//=$self->args->{target}//$self->args->{plt};
      0        
379              
380             #If just a fragment fix it to the plt path or target path
381 0 0         if($data->{href} =~ /^#/){
382             # Fragment ... append plt path
383 0   0       $data->{href}=($self->args->{target}//$self->args->{plt}).$data->{href};
384             }
385             }
386              
387              
388             sub lander {
389 0     0 1   my $self=shift;
390 0           my %options=@_;
391              
392 0           my $table=$self->args->{table}->table;
393 0           my $entry=$table->{$self->args->{plt}};
394 0           $entry->{lander}=\%options;
395              
396            
397             }
398              
399             #Only works for plt templates
400             # Like a load call, but uses the information about the locale to
401             # load a sub template
402             sub locale {
403 0     0 1   my ($self, $lang_code)=@_;
404 0 0         return $self->[locale_sub_template_] if $self->[locale_sub_template_];
405              
406 0           Log::OK::TRACE and log_trace __PACKAGE__." locale";
407 0           my $dir=$self->meta->{_input_path};
408 0           my $basename=basename $self->meta->{file};
409 0 0         unless($lang_code){
410 0           $lang_code=$self->args->{locale};
411             }
412 0           my $lang_template;
413 0 0         if($lang_code){
414 0   0       $lang_template=catfile $dir,$lang_code//(), $basename;
415 0           try {
416 0           $self->[locale_sub_template_]=$self->load($lang_template, $self->args, $self->meta->%*);
417             }
418             catch($e){
419 0           Log::OK::WARN and log_warn __PACKAGE__." Could not render template $lang_template. Using empty tempalte instead";
420 0           Log::OK::WARN and log_warn __PACKAGE__." $e";
421 0           $self->[locale_sub_template_]=Template::Plex->load([""]);#, $self->args, $self->meta->%*);
422              
423             }
424             }
425             else{
426             #Log::OK::WARN and log_warn __PACKAGE__." no file found for locale=>$lang_code";
427              
428 0           $lang_template=[""];
429             #Dummy template
430             #Log::OK::WARN and log_warn __PACKAGE__." attempt to render non existent locale template. Using empty tempalte instead";
431 0           $self->[locale_sub_template_]=Template::Plex->load([""]);#, $self->args, $self->meta->%*);
432             }
433             }
434              
435             sub build{
436 0     0 0   my $self=shift;
437 0           my ($fields)=@_;
438            
439 0           my $result=$self->SUPER::render(@_);
440              
441              
442             #unless($fields->{no_file}){
443 0           my $file=catfile $self->args->{html_root}, $self->output_path;
444 0           mkpath dirname $file; #make dir for output
445              
446 0           my $fh;
447 0 0         unless(open $fh, ">", $file){
448 0           Log::OK::ERROR and log_error "Could not open output location file $file";
449             }
450              
451 0           Log::OK::DEBUG and log_debug("writing to file $file");
452 0           print $fh $result;
453 0           close $fh;
454              
455             #copy any resources this template neeeds?
456              
457              
458             # Setup lander
459             #
460              
461 0           my $table=$self->args->{table}->table;
462 0           my $entry=$table->{$self->args->{plt}};
463 0           my $lander=$entry->{lander};
464              
465 0 0         if($lander){
466 0   0       $lander->{location}//="";
467 0   0       $lander->{name}//="index.lander";
468 0   0       $lander->{type}//="refresh";
469              
470            
471 0           my $html_root=$self->args->{html_root};
472 0           my $link=catfile($html_root, $lander->{location}, $lander->{name});
473              
474 0 0         if( -e $link){
475 0           Log::OK::INFO and log_info("removing existing lander link");
476 0           unlink $link;
477             }
478              
479 0           for($lander->{type}){
480 0 0         if(/refresh/){
    0          
481             # Spit out a html with meta tag for refresh
482 0           open my $fh, ">", $link;
483 0           print $fh qq|
484            
485            
486 0          
487            
488            
489             |;
490              
491             }
492             elsif(/symlink/){
493             #Log::OK::INFO and log_info("Lander for ".$self->output_path." => ".$self->[lander_]);
494              
495 0           symlink $self->output_path, $link;#$self->args->{input};
496             }
497             else{
498             # Unkown lander config
499             }
500             }
501             }
502             #}
503 0           $result;
504             }
505              
506              
507              
508              
509              
510             1;
511              
512             __END__