File Coverage

blib/lib/Templ/Template.pm
Criterion Covered Total %
statement 152 176 86.3
branch 25 48 52.0
condition 5 15 33.3
subroutine 36 40 90.0
pod 0 18 0.0
total 218 297 73.4


line stmt bran cond sub pod time code
1             package Templ::Template;
2              
3 1     1   4 use Exporter;
  1         2  
  1         55  
4             push @ISA, 'Exporter';
5             @EXPORT = qw(add_header add_tag);
6              
7 1     1   4 use strict;
  1         2  
  1         20  
8 1     1   5 use warnings;
  1         1  
  1         26  
9              
10 1     1   5 use Carp qw(carp croak confess);
  1         7  
  1         65  
11 1     1   5 use Scalar::Util qw(blessed openhandle);
  1         2  
  1         124  
12 1     1   773 use File::Spec::Functions qw(rel2abs);
  1         807  
  1         61  
13 1     1   739 use IO::File;
  1         9838  
  1         137  
14 1     1   968 use Data::Dumper;
  1         10187  
  1         65  
15 1     1   570 use Templ::Parser::Print;
  1         2  
  1         26  
16 1     1   477 use Templ::Parser::Return;
  1         2  
  1         24  
17 1     1   5 use Templ::Util qw(expand_isa);
  1         1  
  1         43  
18 1     1   5 use Digest::MD5 qw(md5);
  1         2  
  1         63  
19 1     1   4 use overload '""' => \&as_perl, '&{}' => \&as_sub;
  1         2  
  1         8  
20              
21             my %templ_cache = ();
22              
23             ##############################################################################
24             # Subclass import functions
25              
26             sub add_header ($) {
27              
28 1     1 0 2 my $target_class = caller; # The class name of the template we are
29             # adding a header to
30 1         2 my $header = shift; # Header to associate with the template
31              
32 1     1   158 no strict 'refs';
  1         2  
  1         28  
33 1     1   5 no warnings 'once';
  1         1  
  1         105  
34 1         2 push @{ $target_class . '::TEMPL_HEADERS' }, $header;
  1         7  
35              
36             }
37              
38             sub add_tag ($$;%) {
39              
40 6     6 0 11 my $target_class = caller; # The class name of the template we are
41             # adding a tag to
42 6         9 my $char = shift; # Character to associate with the tag
43 6         7 my $tag_class = shift; # The tag's class name we're adding to
44             # the calling template
45              
46 1     1   5 no strict 'refs';
  1         1  
  1         255  
47 6         343 eval "
48             require Templ::Tag::$tag_class;
49             require $tag_class;
50             ";
51 6 50       23 if ( scalar keys %{ 'Templ::Tag::' . $tag_class . '::' } ) {
  6 0       27  
52 6         12 $tag_class = 'Templ::Tag::' . $tag_class;
53             }
54 0         0 elsif ( not scalar keys %{ $tag_class . '::' } ) {
55 0         0 croak "Unable to resolve Templ::Tag class $tag_class";
56             }
57              
58 6         8 push @{ $target_class . '::TEMPL_TAGS' },
  6         47  
59             $tag_class->new( 'char' => $char, @_ );
60              
61             }
62              
63             ##############################################################################
64             # Class methods
65              
66             sub new {
67              
68 4     4 0 27 my $class = shift; # Might be a partial class if called from get()
69 4 0 33     16 if ( not defined $class || ref $class || $class !~ m/^(\w+\:\:)*\w+$/ ) {
      33        
70 0         0 croak "Can only be called as __PACKAGE__->new";
71             }
72 4         288 eval "require Templ::Template::$class; require $class;";
73 1     1   6 no strict 'refs';
  1         2  
  1         128  
74 4 100       19 if ( scalar keys %{ 'Templ::Template::' . $class . '::' } ) {
  4 50       25  
75 3         7 $class = 'Templ::Template::' . $class;
76             }
77 1         7 elsif ( not scalar keys %{ $class . '::' } ) {
78 0         0 croak "Unable to resolve Templ::Template class $class";
79             }
80              
81 4         11 my $self = bless {}, $class;
82 4         25 $self->resolve_source( @_ );
83              
84 4         36 return $self;
85             }
86              
87             # Creates a new Templ::Template* object of the passed type
88             sub get {
89 3     3 0 6 my $class = shift;
90 1     1   4 no warnings 'uninitialized';
  1         2  
  1         148  
91 3         38 my $id = md5( join "\n", ( caller(1), @_ ) );
92 3 50       13 if ( not defined $templ_cache{$id} ) { $templ_cache{$id} = new( @_ ); }
  3         90  
93 3         13 return $templ_cache{$id};
94             }
95              
96             ##############################################################################
97             # Hybrid class/object methods
98              
99             sub tags {
100 4   33 4 0 14 my $class = ref( $_[0] ) || $_[0];
101 4         9 my @tags = ();
102 4         10 foreach my $this_class ( expand_isa($class) ) {
103 1     1   4 no strict 'refs';
  1         2  
  1         118  
104 15 100       17 next unless scalar( @{ $this_class . '::TEMPL_TAGS' } );
  15         60  
105 7         9 push @tags, @{ $this_class . '::TEMPL_TAGS' };
  7         26  
106             }
107 4 50       20 return wantarray ? @tags : \@tags;
108             }
109              
110             sub header {
111 4   33 4 0 16 my $class = ref( $_[0] ) || $_[0];
112 4         9 my @headers = ();
113 4         14 foreach my $this_class ( expand_isa($class) ) {
114 1     1   5 no strict 'refs';
  1         1  
  1         969  
115 15 100       17 next unless scalar( @{ $this_class . '::TEMPL_HEADERS' } );
  15         73  
116 3         4 push @headers, @{ $this_class . '::TEMPL_HEADERS' };
  3         10  
117             }
118 4         13 return join '', map {"$_\n"} @headers;
  3         17  
119             }
120              
121             ##############################################################################
122             # Object methods
123              
124             # Get the template contents of the object
125             sub templ_code {
126 4     4 0 9 my $self = shift;
127 4         16 return $self->{'templ_code'};
128             }
129              
130             sub resolve_source {
131            
132 4     4 0 9 my $self = shift;
133 4         6 my $source = shift;
134            
135 4 50       14 return unless defined $source;
136            
137 4         22 $self->clear;
138              
139 4 100 33     26 if (not ref $source) {
    50          
    100          
    50          
140 2         7 $self->{'templ_code'} = $source;
141             }
142             elsif (ref($source) eq 'ARRAY') {
143 0         0 $self->{'templ_code'} = join '', @{$source};
  0         0  
144             }
145             elsif ( ref($source) eq 'SCALAR' ) {
146 1 50       34 croak "Unable to stat file '$source'" unless -f $$source;
147 1         13 my $fh = IO::File->new($$source, 'r');
148 1 50       139 defined($fh) || croak "Unable to open file ".$$source.": $!";
149 1         35 $self->{'templ_code'} = join '', $fh->getlines;
150 1         89 $fh->close;
151             }
152 0         0 elsif ( openhandle($source) || eval { $source->can('getline') }) {
153 1         5 local $/ = undef;
154 1         28 $self->{'templ_code'} = <$source>;
155 1         38 close $source;
156             }
157             else {
158 0         0 croak "Unrecognized Templ source parameter: ".Dumper($source);
159             }
160             }
161              
162             # Returns an eval-able string perl block which returns the output of the
163             # template
164             sub as_perl {
165 1     1 0 2 my $self = shift;
166 1 50       5 if ( not defined $self->{'as_perl'} ) {
167 1         5 $self->{'as_perl'} = '{'
168             . Templ::Parser::Return->new()->parse($self)
169             . '}';
170             }
171 1         55 return $self->{'as_perl'};
172             }
173              
174             # Returns an eval-able string perl block which returns the output of the
175             # template, with newline-spanning strings split into multiple perl code lines
176             sub as_pretty_perl {
177 0     0 0 0 my $self = shift;
178 0 0       0 if ( not defined $self->{'as_pretty_perl'} ) {
179 0         0 $self->{'as_pretty_perl'} = '{'
180             . Templ::Parser::Return->new( 'prettyify' => 1 )->parse($self)
181             . '}';
182             }
183 0         0 return $self->{'as_pretty_perl'};
184             }
185              
186             # Returns a code reference to a block-based handler for the template
187             sub as_sub {
188 3     3 0 5 my $self = shift;
189 3 100       12 if ( not defined $self->{'as_sub'} ) {
190 2         3 my $sub;
191 1     1   6 eval '$sub = sub {' . Templ::Parser::Return->new()->parse($self) . '}';
  1         2  
  1         163  
  2         17  
192 2 50       16 $@ && croak $@;
193 2         74 $self->{'as_sub'} = $sub;
194             }
195 3         81 return $self->{'as_sub'};
196             }
197              
198             # Runs the return handler on the passed params... in other words, executes
199             # the template and returns the results
200             sub render {
201 3     3 0 1246 my $self = shift;
202 3         13 $self->as_sub->(@_);
203             }
204              
205             # Runs the print handler on the passed params... in other words it executes
206             # the template in such a way that the output is sent to the select()ed FH
207             sub as_print {
208 0     0 0 0 my $self = shift;
209 0 0       0 if ( not defined $self->{'as_print'} ) {
210 0         0 $self->{'as_print'} = '{'
211             . Templ::Parser::Print->new()->parse($self)
212             . '}';
213             }
214 0         0 return $self->{'as_print'};
215             }
216              
217             # Returns an eval-able string perl block which returns the output of the
218             # template, with newline-spanning strings split into multiple lines
219             sub as_pretty_print {
220 0     0 0 0 my $self = shift;
221 0 0       0 if ( not defined $self->{'as_pretty_print'} ) {
222 0         0 $self->{'as_pretty_print'} = '{'
223             . Templ::Parser::Print->new( 'prettyify' => 1 )->parse($self)
224             . '}';
225             }
226 0         0 return $self->{'as_pretty_print'};
227             }
228              
229             # Returns a code reference to a printing handler for this template
230             sub as_print_sub {
231 1     1 0 2 my $self = shift;
232 1 50       8 if ( not defined $self->{'as_print_sub'} ) {
233 1         3 my $sub;
234 1     1   609 eval '$sub = sub {' . Templ::Parser::Print->new()->parse($self) . '}';
  1         4  
  1         123  
  1         16  
235 1 50       15 $@ && croak $@;
236 1         78 $self->{'as_print_sub'} = $sub;
237             }
238 1         28 return $self->{'as_print_sub'};
239             }
240              
241             # Prints the output of this template with the passed params
242             sub run {
243 1     1 0 1726 my $self = shift;
244 1         8 $self->as_print_sub->(@_);
245             }
246              
247             sub clear {
248 4     4 0 34 my $self = shift;
249 4         7 delete $self->{$_} foreach grep { m/^as_/ } keys %{$self};
  0         0  
  4         154  
250             }
251              
252             sub dump {
253 0     0 0   my $self = shift;
254 0           local $Data::Dumper::Deparse = 1;
255 0           return Data::Dumper->Dump( [$self], ['template'] );
256             }
257              
258             1;