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   35740 use parent 'DTL::Fast::Parser';
  98         22527  
  98         471  
3 98     98   4651 use strict;
  98         214  
  98         1671  
4 98     98   443 use utf8;
  98         199  
  98         334  
5 98     98   1998 use warnings FATAL => 'all';
  98         201  
  98         2877  
6            
7 98     98   485 use DTL::Fast qw(get_template);
  98         188  
  98         3375  
8 98     98   495 use DTL::Fast::Context;
  98         192  
  98         1750  
9 98     98   32166 use DTL::Fast::Tags;
  98         254  
  98         3278  
10 98     98   29993 use DTL::Fast::Filters;
  98         256  
  98         2996  
11 98     98   614 use Scalar::Util qw/weaken/;
  98         196  
  98         76446  
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 260122 my ( $proto, $template, %kwargs ) = @_;
20 962   50     2716 $template //= '';
21            
22 962         2453 $kwargs{raw_chunks} = _get_raw_chunks($template);
23 962   100     5088 $kwargs{dirs} //= [ ]; # optional dirs to look up for includes or parents
24 962   100     4182 $kwargs{file_path} //= 'inline';
25 962         2225 $kwargs{perl} = $];
26 962         1885 $kwargs{blocks} = { };
27             $kwargs{modules} //= {
28 962   50     5108 'DTL::Fast' => $DTL::Fast::VERSION,
29             };
30            
31 962         4826 my $self = $proto->SUPER::new(%kwargs);
32            
33 946         3509 return $self;
34             }
35            
36             #@Override self-linking
37             sub remember_template
38             {
39 962     962 0 1874 my ($self) = @_;
40            
41 962         2069 $self->{_template} = $self;
42 962         1733 $self->{_template_line} = 1;
43 962         3895 weaken $self->{_template};
44            
45 962         2082 return $self;
46             }
47            
48             #@Override
49             sub parse_chunks
50             {
51 962     962 0 1762 my ( $self ) = @_;
52            
53 962         1940 my ( $current_template_backup, $current_template_line_backup ) = ($CURRENT_TEMPLATE, $CURRENT_TEMPLATE_LINE);
54 962         1759 ($CURRENT_TEMPLATE, $CURRENT_TEMPLATE_LINE) = ($self, 1);
55            
56 962         2934 $self->SUPER::parse_chunks();
57            
58 946         1869 ($CURRENT_TEMPLATE, $CURRENT_TEMPLATE_LINE) = ($current_template_backup, $current_template_line_backup);
59 946         1973 return $self;
60             }
61            
62             my $reg = qr/(
63             \{\#.+?\#\}
64             |\{\%.+?\%\}
65             |\{\{.+?\}\}
66             )/xs;
67            
68             sub _get_raw_chunks
69             {
70 962     962   1888 my ( $template ) = @_;
71            
72 962         11451 my $result = [ split $reg, $template ];
73            
74 962         3229 return $result;
75             }
76            
77             #@Override
78             sub render
79             {
80 2336     2336 0 21126 my ( $self, $context ) = @_;
81            
82 2336   100     5643 $context //= { };
83            
84 2336 100 33     12772 if (ref $context eq 'HASH')
    50          
85             {
86 38         182 $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         7250 $context->push_scope();
97            
98 2336 100       6046 $context->{ns}->[- 1]->{_dtl_ssi_dirs} = $self->{ssi_dirs} if ($self->{ssi_dirs});
99 2336 100       5310 $context->{ns}->[- 1]->{_dtl_url_source} = $self->{url_source} if ($self->{url_source});
100            
101 2336         3921 my $template_path = $self->{file_path};
102            
103 2336 100       5422 if (not exists $context->{ns}->[- 1]->{_dtl_include_path}) # entry point
104             {
105 2313         4900 $context->{ns}->[- 1]->{_dtl_include_path} = [ ];
106 2313         4615 $context->{ns}->[- 1]->{_dtl_include_files} = { };
107             }
108             else # check for recursion, shouldn't this be in the include tag?
109             {
110 23 100       80 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         10 , join( "\n includes ", @{$context->{ns}->[- 1]->{_dtl_include_path}}, $template_path)
  3         31  
115             );
116             }
117             }
118            
119 2333         5311 $context->{ns}->[- 1]->{_dtl_include_files}->{$template_path} = 1;
120 2333         3461 push @{$context->{ns}->[- 1]->{_dtl_include_path}}, $template_path;
  2333         5684  
121            
122 2333         3545 my $result;
123 2333 100       4726 if ($self->{extends}) # has parent template
124             {
125 11         20 my @descendants = ();
126 11         17 my $current_descendant = $self;
127 11         21 my %inheritance = ();
128            
129 11         28 while( $current_descendant->{extends} )
130             {
131 18         35 push @descendants, $current_descendant;
132 18         41 $inheritance{$current_descendant->{file_path}} = 1;
133            
134 18         50 my $parent_template_name = $current_descendant->{extends}->render($context);
135            
136             die sprintf(
137             "Unable to resolve parent template name for %s"
138             , $current_descendant->{file_path}
139 18 50       46 ) if (not $parent_template_name);
140            
141             $current_descendant = get_template(
142             $parent_template_name
143             , dirs => $self->{dirs}
144 18         45 );
145            
146 17 50       36 if (defined $current_descendant)
147             {
148 17 100       64 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         18 (map {$_->{file_path}} @descendants),
155             $current_descendant->{file_path}
156             )
157 1         4 );
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         22 push @descendants, $current_descendant;
170 9         20 $context->{ns}->[- 1]->{_dtl_descendants} = \@descendants;
171 9         15 $context->{ns}->[- 1]->{_dtl_rendering_template} = $current_descendant;
172 9         29 $result = $current_descendant->SUPER::render($context);
173            
174             }
175             else
176             {
177 2322         4088 delete $context->{ns}->[- 1]->{_dtl_descendants};
178 2322         4069 $context->{ns}->[- 1]->{_dtl_rendering_template} = $self;
179 2322         6676 $result = $self->SUPER::render($context);
180             }
181            
182 2312         3814 pop @{$context->{ns}->[- 1]->{_dtl_include_path}};
  2312         4671  
183 2312         5329 delete $context->{ns}->[- 1]->{_dtl_include_files}->{$template_path};
184            
185 2312         7301 $context->pop_scope();
186            
187 2312         7919 return $result;
188             }
189            
190             1;