File Coverage

lib/Templer/Plugin/FileGlob.pm
Criterion Covered Total %
statement 55 64 85.9
branch 9 18 50.0
condition 3 6 50.0
subroutine 6 6 100.0
pod 1 2 50.0
total 74 96 77.0


line stmt bran cond sub pod time code
1              
2             =head1 NAME
3            
4             Templer::Plugin::FileGlob - A plugin to expand file globs.
5            
6             =cut
7              
8             =head1 SYNOPSIS
9            
10             The following is a good example use of this plugin
11            
12             title: Images of cats
13             images: file_glob( img/candid*.jpg )
14             ----
15             <li>
16             <!-- tmpl_loop name='images' -->
17             <li><img src="<!-- tmpl_var name='file' -->" width="<!-- tmpl_var name='width' -->" height="<!-- tmpl_var name='height' -->" alt="Animal &amp; Pet Photography, Edinburgh" /></li>
18             <!-- /tmpl_loop -->
19             </ul>
20            
21             =cut
22              
23             =head1 DESCRIPTION
24            
25             This plugin operates on file-patterns and populates loops refering
26             to the specified pattern.
27            
28             The intended use-case is inline-gallery generation, but more uses
29             would surely be discovered.
30            
31             For each loop created there will be the variables:
32            
33             =over 8
34            
35             =item file
36            
37             The name of the file.
38            
39             =item height
40            
41             The height of the image, if the file is an image and L<Image::Size> is available.
42            
43             =item width
44            
45             The width of the image, if the file is an image and L<Image::Size> is available.
46            
47             =item content
48            
49             The content of the file if the file is not an image and not a templer input file.
50            
51             =item dirname
52            
53             The directory part of the file name.
54            
55             =item basename
56            
57             The basename of the file (without extension).
58            
59             =item extension
60            
61             The extension (everything after the last period) of the file name.
62            
63             =back
64            
65             If matching files are templer input files then all templer variables are also
66             populated.
67            
68             =cut
69              
70             =head1 LICENSE
71            
72             This module is free software; you can redistribute it and/or modify it
73             under the terms of either:
74            
75             a) the GNU General Public License as published by the Free Software
76             Foundation; either version 2, or (at your option) any later version,
77             or
78            
79             b) the Perl "Artistic License".
80            
81             =cut
82              
83             =head1 AUTHOR
84            
85             Steve Kemp <steve@steve.org.uk>
86            
87             =cut
88              
89             =head1 COPYRIGHT AND LICENSE
90            
91             Copyright (C) 2012-2015 Steve Kemp <steve@steve.org.uk>.
92            
93             This library is free software. You can modify and or distribute it under
94             the same terms as Perl itself.
95            
96             =cut
97              
98             =head1 METHODS
99            
100             =cut
101              
102              
103 11     11   4196 use strict;
  11         14  
  11         238  
104 11     11   31 use warnings;
  11         10  
  11         283  
105              
106              
107             package Templer::Plugin::FileGlob;
108              
109 11     11   38 use Cwd;
  11         10  
  11         515  
110 11     11   40 use File::Basename;
  11         11  
  11         6207  
111              
112              
113             =head2
114            
115             Constructor. No arguments are required/supported.
116            
117             =cut
118              
119             sub new
120             {
121 11     11 0 20     my ( $proto, %supplied ) = (@_);
122 11   33     56     my $class = ref($proto) || $proto;
123              
124 11         15     my $self = {};
125 11         15     bless( $self, $class );
126 11         75     return $self;
127             }
128              
129              
130              
131             =head2 expand_variables
132            
133             This is the method which is called by the L<Templer::Plugin::Factory>
134             to expand the variables contained in a L<Templer::Site::Page> object.
135            
136             Variables are written in the file in the form "key: value", and are
137             internally stored within the Page object as a hash.
138            
139             This method iterates over each key & value and updates any that
140             seem to refer to file-globs.
141            
142             =cut
143              
144             sub expand_variables
145             {
146 9     9 1 16     my ( $self, $site, $page, $data ) = (@_);
147              
148             #
149             # Get the page-variables in the template.
150             #
151 9         32     my %hash = %$data;
152              
153             #
154             # Look for a value of "file_glob" in each key.
155             #
156 9         26     foreach my $key ( keys %hash )
157                 {
158 66 100       115         if ( $hash{ $key } =~ /^file_glob\((.*)\)/ )
159                     {
160              
161             #
162             # Populate an array of hash-refs referring to files which match
163             # a particular glob.
164             #
165             # Could be used for many things, will be used for image-gallaries.
166             #
167              
168             #
169             # Get the pattern and strip leading/trailing quotes and whitespace.
170             #
171 1         2             my $pattern = $1;
172 1         2             $pattern =~ s/['"]//g;
173 1         5             $pattern =~ s/^\s+|\s+$//g;
174              
175             #
176             # Make sure we're relative to the directory containing
177             # the actual input-page.
178             #
179             # This way globs will match what the author expected.
180             #
181 1         3             my $dirName = $page->source();
182 1 50       4             if ( $dirName =~ /^(.*)\/(.*)$/ )
183                         {
184 1         2                 $dirName = $1;
185                         }
186 1         1919             my $pwd = Cwd::cwd();
187 1         20             chdir( $dirName . "/" );
188              
189             #
190             # The value we'll set the variable to.
191             #
192 1         2             my $ref;
193              
194             #
195             # The suffix of files that are Templer input-files.
196             #
197 1         11             my $suffix = $site->{ suffix };
198              
199              
200             #
201             # Run the glob.
202             #
203 1         90             foreach my $file ( glob($pattern) )
204                         {
205              
206             #
207             # The page dependency also includes the matching filename now.
208             #
209 5 50       15                 if ( $file =~ m{^/} )
210                             {
211 0         0                     $page->add_dependency($file);
212                             }
213                             else
214                             {
215 5         26                     $page->add_dependency( $dirName . "/" . $file );
216                             }
217              
218             #
219             # Data reference - moved here so we can add height/width if the
220             # glob refers to an image, and if we have Image::Size installed.
221             #
222 5         12                 my %meta = ( file => $file );
223              
224             #
225             # Populate filename parts.
226             #
227 5         77                 my ( $basename, $dirname, $extension ) = fileparse($file);
228 5         20                 ( $meta{ 'dirname' } = $dirname ) =~ s{/$}{};
229 5         19                 ( $meta{ 'basename' } = $basename ) =~ s{(.*)\.([^.]*)$}{$1};
230 5         9                 $meta{ 'extension' } = $2;
231              
232             #
233             # If the file is an image AND we have Image::Size
234             # then populate the height/width too.
235             #
236 5 50 66     49                 if ( $file =~ /\.(jpe?g|png|gif)$/i )
    100          
237                             {
238 0         0                     my $module = "use Image::Size;";
239             ## no critic (Eval)
240 0         0                     eval($module);
241             ## use critic
242 0 0       0                     if ( !$@ )
243                                 {
244 0 0       0                         if ( -e $file )
245                                     {
246 0         0                             ( $meta{ 'width' }, $meta{ 'height' } ) =
247                                           imgsize($file);
248                                     }
249                                     else
250                                     {
251 0         0                             print
252                                           "WARNING: Attempting to invoke Image::Size on a file that doesn't exist: $file\n";
253                                     }
254                                 }
255                             }
256                             elsif ( ($suffix) && ( $file =~ /$suffix$/i ) )
257                             {
258              
259             #
260             # If the file is a Templer input file
261             # then populate templer variables
262             #
263 1         4                     my $pageClass = ref $page;
264 1         9                     my $globPage = $pageClass->new( file => $file );
265 1         3                     while ( my ( $k, $v ) = each %{ $globPage } )
  5         13  
266                                 {
267 4         6                         $meta{ $k } = $v;
268                                 }
269                             }
270                             else
271                             {
272              
273             #
274             # If it isn't an image we'll make the content available
275             #
276 4 50       117                     if ( open( my $handle, "<:utf8", $file ) )
277                                 {
278 4         12                         binmode( $handle, ":utf8" );
279 4         32                         while ( my $line = <$handle> )
280                                     {
281 4         18                             $meta{ 'content' } .= $line;
282                                     }
283 4         20                         close($handle);
284                                 }
285                             }
286              
287 5         20                 push( @$ref, \%meta );
288                         }
289              
290             #
291             # If we found at least one file then we'll update
292             # the variable value to refer to the populated structure.
293             #
294 1 50       3             if ($ref)
295                         {
296 1         2                 $hash{ $key } = $ref;
297                         }
298                         else
299                         {
300 0         0                 print
301                               "WARNING: pattern '$pattern' matched zero files for page " .
302                               $page->source() . "\n";
303 0         0                 delete $hash{ $key };
304                         }
305              
306             #
307             # Restore the PWD.
308             #
309 1         11             chdir($pwd);
310                     }
311                 }
312              
313 9         24     return ( \%hash );
314             }
315              
316              
317             #
318             # Register the plugin.
319             #
320             Templer::Plugin::Factory->new()->register_plugin("Templer::Plugin::FileGlob");
321