File Coverage

blib/lib/DTL/Fast/Template.pm
Criterion Covered Total %
statement 95 98 96.9
branch 17 20 85.0
condition 9 13 69.2
subroutine 14 14 100.0
pod 0 4 0.0
total 135 149 90.6


line stmt bran cond sub pod time code
1             package DTL::Fast::Template;
2 98     98   40531 use parent 'DTL::Fast::Parser';
  98         24565  
  98         1058  
3 98     98   4332 use strict;
  98         125  
  98         1522  
4 98     98   299 use utf8;
  98         115  
  98         283  
5 98     98   1791 use warnings FATAL => 'all';
  98         117  
  98         3251  
6            
7 98     98   309 use DTL::Fast qw(get_template);
  98         124  
  98         3542  
8 98     98   366 use DTL::Fast::Context;
  98         132  
  98         1712  
9 98     98   33827 use DTL::Fast::Tags;
  98         169  
  98         2582  
10 98     98   33026 use DTL::Fast::Filters;
  98         169  
  98         2714  
11 98     98   403 use Scalar::Util qw/weaken/;
  98         109  
  98         77075  
12            
13             our $CURRENT_TEMPLATE; # global variable for linking modules
14             our $CURRENT_TEMPLATE_LINE; # global variable for source line number
15            
16             #@Override
17             sub new
18             {
19 962     962 0 234497 my( $proto, $template, %kwargs ) = @_;
20 962   50     2044 $template //= '';
21            
22 962         1771 $kwargs{'raw_chunks'} = _get_raw_chunks($template);
23 962   100     3768 $kwargs{'dirs'} //= []; # optional dirs to look up for includes or parents
24 962   100     2990 $kwargs{'file_path'} //= 'inline';
25 962         1535 $kwargs{'perl'} = $];
26 962         1298 $kwargs{'blocks'} = {};
27 962   50     3831 $kwargs{'modules'} //= {
28             'DTL::Fast' => $DTL::Fast::VERSION,
29             };
30            
31 962         4421 my $self = $proto->SUPER::new(%kwargs);
32            
33 946         3219 return $self;
34             }
35            
36             #@Override self-linking
37             sub remember_template
38             {
39 962     962 0 1044 my ($self) = @_;
40            
41 962         1467 $self->{'_template'} = $self;
42 962         1040 $self->{'_template_line'} = 1;
43 962         2519 weaken $self->{'_template'};
44            
45 962         1420 return $self;
46             }
47            
48             #@Override
49             sub parse_chunks
50             {
51 962     962 0 956 my( $self ) = @_;
52            
53 962         1083 my( $current_template_backup, $current_template_line_backup ) = ($CURRENT_TEMPLATE, $CURRENT_TEMPLATE_LINE);
54 962         1166 ($CURRENT_TEMPLATE, $CURRENT_TEMPLATE_LINE) = ($self, 1);
55            
56 962         2118 $self->SUPER::parse_chunks();
57            
58 946         1131 ($CURRENT_TEMPLATE, $CURRENT_TEMPLATE_LINE) = ($current_template_backup, $current_template_line_backup);
59 946         1367 return $self;
60             }
61            
62             my $reg = qr/(
63             \{\#.+?\#\}
64             |\{\%.+?\%\}
65             |\{\{.+?\}\}
66             )/xs;
67            
68             sub _get_raw_chunks
69             {
70 962     962   1122 my( $template ) = @_;
71            
72 962         11692 my $result = [split $reg, $template];
73            
74 962         2269 return $result;
75             }
76            
77             #@Override
78             sub render
79             {
80 2336     2336 0 19318 my( $self, $context ) = @_;
81            
82 2336   100     4413 $context //= {};
83            
84 2336 100 33     11767 if( ref $context eq 'HASH' )
    50          
85             {
86 38         256 $context = DTL::Fast::Context->new($context);
87             }
88             elsif(
89             defined $context
90             and ref $context ne 'DTL::Fast::Context'
91             )
92             {
93 0         0 die "Context must be a DTL::Fast::Context object or a HASH reference";
94             }
95            
96 2336         5018 $context->push_scope();
97            
98 2336 100       4150 $context->{'ns'}->[-1]->{'_dtl_ssi_dirs'} = $self->{'ssi_dirs'} if $self->{'ssi_dirs'};
99 2336 100       3757 $context->{'ns'}->[-1]->{'_dtl_url_source'} = $self->{'url_source'} if $self->{'url_source'};
100            
101 2336         2293 my $template_path = $self->{'file_path'};
102            
103 2336 100       3587 if( not exists $context->{'ns'}->[-1]->{'_dtl_include_path'} ) # entry point
104             {
105 2313         3224 $context->{'ns'}->[-1]->{'_dtl_include_path'} = [];
106 2313         3341 $context->{'ns'}->[-1]->{'_dtl_include_files'} = {};
107             }
108             else # check for recursion, shouldn't this be in the include tag?
109             {
110 23 100       52 if( exists $context->{'ns'}->[-1]->{'_dtl_include_files'}->{$template_path} )
111             {
112             # recursive inclusion
113             die sprintf("Recursive inclusion detected:\n%s\n"
114 3         5 , join( "\n includes ", @{$context->{'ns'}->[-1]->{'_dtl_include_path'}}, $template_path)
  3         35  
115             );
116             }
117             }
118            
119 2333         3758 $context->{'ns'}->[-1]->{'_dtl_include_files'}->{$template_path} = 1;
120 2333         1716 push @{$context->{'ns'}->[-1]->{'_dtl_include_path'}}, $template_path;
  2333         4492  
121            
122 2333         1870 my $result;
123 2333 100       3535 if ( $self->{'extends'} ) # has parent template
124             {
125 11         15 my @descendants = ();
126 11         15 my $current_descendant = $self;
127 11         17 my %inheritance = ();
128            
129 11         23 while( $current_descendant->{'extends'} )
130             {
131 18         25 push @descendants, $current_descendant;
132 18         31 $inheritance{$current_descendant->{'file_path'}} = 1;
133            
134 18         66 my $parent_template_name = $current_descendant->{'extends'}->render($context);
135            
136             die sprintf(
137             "Unable to resolve parent template name for %s"
138 18 50       31 , $current_descendant->{'file_path'}
139             ) if not $parent_template_name;
140            
141             $current_descendant = get_template(
142             $parent_template_name
143 18         44 , 'dirs' => $self->{'dirs'}
144             );
145            
146 17 50       24 if ( defined $current_descendant )
147             {
148 17 100       65 if ( $inheritance{$current_descendant->{'file_path'}} )
149             {
150             die sprintf(
151             "Recursive inheritance detected:\n%s\n"
152             , join(
153             "\n inherited from ",
154 4         25 (map {$_->{'file_path'}} @descendants),
155 1         5 $current_descendant->{'file_path'}
156             )
157             );
158             }
159             }
160             else
161             {
162             die sprintf( "Couldn't found a parent template: %s in one of the following directories: %s"
163             , $parent_template_name
164 0         0 , join( ', ', @{$self->{'dirs'}})
  0         0  
165             );
166             }
167             }
168            
169 9         11 push @descendants, $current_descendant;
170 9         18 $context->{'ns'}->[-1]->{'_dtl_descendants'} = \@descendants;
171 9         15 $context->{'ns'}->[-1]->{'_dtl_rendering_template'} = $current_descendant;
172 9         25 $result = $current_descendant->SUPER::render($context);
173            
174             }
175             else
176             {
177 2322         2312 delete $context->{'ns'}->[-1]->{'_dtl_descendants'};
178 2322         2576 $context->{'ns'}->[-1]->{'_dtl_rendering_template'} = $self;
179 2322         5704 $result = $self->SUPER::render($context);
180             }
181            
182 2312         1995 pop @{$context->{'ns'}->[-1]->{'_dtl_include_path'}};
  2312         3462  
183 2312         4049 delete $context->{'ns'}->[-1]->{'_dtl_include_files'}->{$template_path};
184            
185 2312         4793 $context->pop_scope();
186            
187 2312         6689 return $result;
188             }
189            
190             1;