File Coverage

blib/lib/Text/MicroMason/TemplatePath.pm
Criterion Covered Total %
statement 26 29 89.6
branch 8 12 66.6
condition n/a
subroutine 6 6 100.0
pod 1 3 33.3
total 41 50 82.0


line stmt bran cond sub pod time code
1             package Text::MicroMason::TemplatePath;
2              
3 2     2   855 use strict;
  2         4  
  2         55  
4 2     2   19 use File::Spec;
  2         4  
  2         46  
5 2     2   10 use base 'Text::MicroMason::TemplateDir';
  2         4  
  2         805  
6              
7             ######################################################################
8              
9             sub resolve_path {
10 16     16 0 29 my ($self, $src_data) = @_;
11              
12             # Absolute file path: use that filename.
13 16 50       99 return $src_data if File::Spec->file_name_is_absolute($src_data);
14              
15             # Relative filename: use a path search
16              
17             # Our path for this file will be the current directory, if there is
18             # one, followed by the configured path.
19 16         29 my @path = @{$self->{template_path}};
  16         39  
20 16         32 my $current = $self->{source_file};
21 16 100       36 unshift @path, $current if $current;
22              
23             # Check path for an existing template file.
24 16         28 foreach my $dir (@path) {
25 25         221 my $fn = File::Spec->canonpath(File::Spec->catfile($dir, $src_data));
26 25 100       379 next unless -e $fn;
27 16         88 return $fn;
28             }
29              
30             # We couldn't find a matching template, croak.
31 0         0 $self->croak_msg("Text::MicroMason::TemplatePath: template '$src_data' not found in path.\n");
32             }
33              
34             # $contents = $mason->read_file( $filename );
35             sub read_file {
36 12     12 1 23 my ( $self, $file ) = @_;
37              
38 12 50       28 if ( my $root = $self->{strict_root} ) {
39 0         0 my $path = File::Spec->canonpath( $file );
40             # warn "Checking for '$root' in '$path'\n";
41 0 0       0 ( $path =~ /\A\Q$root\E(\/|(?<=\/))(?!\.\.)/ )
42             or $self->croak_msg("Text::MicroMason::TemplatePath: Template not in required base path '$root'");
43             }
44              
45 12         24 return $self->NEXT('read_file', $file );
46             }
47              
48             sub cache_key {
49 6     6 0 10 my $self = shift;
50 6         14 my ($src_type, $src_data, %options) = @_;
51              
52 6 100       19 return $self->NEXT('cache_key', @_) unless $src_type eq 'file';
53 4         16 return $self->resolve_path($src_data);
54             }
55              
56             ######################################################################
57              
58             1;
59              
60             ######################################################################
61              
62             =head1 NAME
63              
64             Text::MicroMason::TemplatePath - Template Path Searching
65              
66              
67             =head1 SYNOPSIS
68              
69             Instead of using this class directly, pass its name to be mixed in:
70              
71             use Text::MicroMason;
72             my $mason = Text::MicroMason->new( -TemplatePath, template_path => [ '/foo', '/bar' ] );
73              
74             Use the standard compile and execute methods to parse and evaluate templates:
75              
76             print $mason->compile( file=>$filepath )->( 'name'=>'Dave' );
77             print $mason->execute( file=>$filepath, 'name'=>'Dave' );
78              
79             Templates stored in files are searched for in the specified template_path:
80              
81             print $mason->execute( file=>"includes/greeting.msn", 'name'=>'Charles');
82              
83             When including other files into a template you can use relative paths:
84              
85             <& ../includes/greeting.msn, name => 'Alice' &>
86              
87             When a file is included in the template, the including template's
88             current directory is added to the beginning of the template search path.
89              
90              
91             =head1 DESCRIPTION
92              
93             This module works similarly to the related TemplateDir mix-in. However,
94             instead of specifying a single root which must contain all templates,
95             TemplatePath allows you to specify an arrayref of directories which will
96             be searched in order whenever a template filename must be resolved.
97              
98             Using a TemplatePath object, absolute filenames are used as-is. If a
99             relative template filenames or file paths is used, every directory in
100             the specified template_path is checked for the existence of the
101             template, and the first existing template file is used.
102              
103             If a template includes another template using <& ... &>, then the
104             including template's location is added to the beginning of the template
105             search path list, for the resolution of the included template's
106             filename. This allows the included template to be specified relative to
107             the including template, but also lets the template search fall back to
108             the configured template search path if necessary.
109              
110              
111             =head2 Supported Attributes
112              
113             =over 4
114              
115             =item template_path
116              
117             An array ref containing a list of directories in which to search for
118             relative template filenames.
119              
120             =item strict_root
121              
122             Optional directory beyond which not to read files. Unlike TemplateDir,
123             this must be a specific file path. Causes read_file to croak if any
124             filename outside of the root is provided. You should make sure that all
125             paths specified in template_path are inside the specified strict_root.
126             (Note that this is not a chroot jail and only affects attempts to load a
127             file as a template; for greater security see the chroot() builtin and
128             L.)
129              
130             =back
131              
132             =head2 Private Methods
133              
134             =over 4
135              
136             =item read_file
137              
138             Intercepts file access to check for strict_root.
139              
140             =back
141              
142             =head2 EXCEPTIONS
143              
144             The following additional exceptions are generated by
145             Text::MicroMason::TemplatePath when appropriate:
146              
147             =over 4
148              
149             =item *
150              
151             Text::MicroMason::TemplatePath: template '%s' not found in path.
152              
153             This indicates that the specified template name does not exist in any of
154             the directories in the configured path.
155              
156             =item *
157              
158             Text::MicroMason::TemplatePath: Template not in required base path '%s'
159              
160             The template found in the configured template path was not within the
161             configured strict_root directory. This may be caused by requesting an
162             absolute template filename not within strict_root, or by specifying a
163             strict_root which does not match the configured template path.
164              
165             =back
166              
167             =head1 SEE ALSO
168              
169             For an overview of this templating framework, see L.
170              
171             This is a mixin class intended for use with L.
172              
173             For distribution, installation, support, copyright and license
174             information, see L.
175              
176             =cut
177