File Coverage

blib/lib/Module/Bundled/Files.pm
Criterion Covered Total %
statement 61 61 100.0
branch 15 20 75.0
condition 4 6 66.6
subroutine 11 11 100.0
pod 6 6 100.0
total 97 104 93.2


line stmt bran cond sub pod time code
1             #!/usr/bin/perl -w
2             package Module::Bundled::Files;
3              
4 5     5   91007 use warnings;
  5         11  
  5         295  
5 5     5   27 use strict;
  5         8  
  5         147  
6              
7 5     5   1414 use File::Spec::Functions;
  5         1046  
  5         613  
8 5     5   4646 use Class::ISA;
  5         15227  
  5         281  
9              
10             =head1 NAME
11              
12             Module::Bundled::Files - Access files bundled with Module
13              
14             =head1 VERSION
15              
16             Version 0.03
17              
18             =cut
19              
20             our $VERSION = '0.03';
21              
22             =head1 SYNOPSIS
23              
24              
25             Access files installed with your module without needing to specify
26             an install location on the target filesystem.
27              
28             =head2 Setup
29              
30             In I:
31              
32             my $build = new Module::Build(...);
33             map{$build->add_build_element($_);}
34             qw{txt html tmpl};
35             # installs all .txt, .html and .tmpl files found in the lib/ tree
36            
37             Create files:
38              
39             Build.PL
40             lib/
41             My/
42             Module.pm
43             Module/
44             index.html
45             data.txt
46             form.tmpl
47            
48             =head2 Object-Oriented Interface
49              
50             use base qw{Module::Bundled::Files};
51            
52             if($self->mbf_exists('data.txt')){...}
53            
54             my $filename = $self->mbf_path('data.txt');
55             # $filename = '/usr/local/share/perl/5.8.7/My/Module/data.txt';
56             open my $fh, '<', $filename or die $@;
57            
58             my $fh = $self->mbf_open('data.txt');
59             while(<$fh>)
60             {
61             ...
62             }
63            
64             my $data = $self->mbf_read('data.txt');
65              
66             =head2 Non-Object-Oriented Interface
67              
68             use Module::Bundled::Files qw{:all};
69             my $object = new Other::Object;
70              
71             if(mf_exists($other,'otherfile.txt')){...}
72              
73             my $filename = mbf_path($object,'otherfile.txt');
74              
75             open my $fh, '<', $filename or die $@;
76            
77             my $fh = mbf_open($object,'otherfile.txt');
78             while(<$fh>)
79             {
80             ...
81             }
82            
83             my $data = mbf_read($object,'otherfile.txt');
84            
85             =cut
86              
87             =head1 DESCRIPTION
88              
89             This module provides an simple method of accessing files that need to be
90             bundled with a module.
91              
92             For example, a module My::Module, which needs to access a seperate file
93             I.
94              
95             In your development directory you would place your I in your
96             I directory.
97              
98             lib/
99             My/
100             Module.pm
101             Module/
102             data.txt
103              
104             Using I in your I file allows the
105             I file to be installed in the same relative location.
106              
107             The file(s) can then be accessed using the I functions provided by
108             this module.
109              
110             =head1 EXPORT
111              
112             The following functions can be exported if you will not be using the
113             Object-Oriented Interface.
114              
115             :all
116             mbf_validate
117             mbf_dir
118             mbf_exists
119             mbf_path
120             mbf_open
121             mbf_read
122              
123             =cut
124              
125 5     5   32 use base 'Exporter';
  5         7  
  5         3968  
126             our @EXPORT_OK = qw{mbf_validate mbf_dir mbf_exists mbf_path mbf_open mbf_read};
127             our %EXPORT_TAGS = (all => [@EXPORT_OK]);
128              
129             =head1 FUNCTIONS
130              
131             =head2 mbf_validate(FILENAME)
132              
133             Returns true if the filename does not contain illegal sequences (i.e. '..')
134              
135             Dies if filename is invalid.
136              
137             =cut
138              
139             sub mbf_validate($;$)
140             {
141 32     32 1 13332 my $filename = shift;
142 32 100 100     6812 $filename = shift if ref($filename) && $filename->isa('Module::Bundled::Files');
143 32 100       142 die "Illegal reference to parent directory in filename '$filename'"
144             if $filename =~ /\.\./;
145 28         50 return 1;
146             }
147              
148             =head2 mbf_dir([MODULE])
149              
150             Returns the path of the directory where all files would be installed.
151              
152             The non-OO interface requires an object reference or module name as
153             the only parameter.
154              
155             =cut
156              
157             sub mbf_dir(;$)
158             {
159 42     42 1 1613 my $module = shift;
160 42 100       113 $module = ref($module) if ref($module);
161             # Convert My::Module into My/Module.pm
162             # %INC uses '/' for delimiters, even on Windows
163 42         137 my $shortpath = join('/',split(/::/,$module)).'.pm';
164 42 50       89 die "Short path not generated for $module" unless $shortpath;
165             # Find the complete path for the module
166 42         72 my $fullpath = $INC{$shortpath};
167 42 50       83 die "Full path not found in \%INC for '$shortpath'" unless $fullpath;
168             # convert the '/' delimiters in %INC to those used by the OS
169 42         228 $fullpath = catfile(split(m|/|,$fullpath));
170             # Strip the .pm to get the directory name
171 42         166 $fullpath =~ s|\.pm$||;
172 42         99 return $fullpath;
173             }
174              
175             =head2 mbf_exists([MODULE,] FILENAME)
176              
177             Returns true of the named file has been bundled with the module.
178              
179             The non-OO interface requires an object reference or module name as
180             the first parameter.
181              
182             =cut
183              
184             sub mbf_exists($;$)
185             {
186 24     24 1 3653 my $module = shift;
187 24         34 my $filename = shift;
188 24         50 mbf_validate($module,$filename);
189 24         46 my $dir = mbf_dir($module);
190 24         89 my $fullpath = catfile($dir,$filename);
191 24 100       564 return stat($fullpath) ? 1 : 0;
192             }
193              
194             =head2 mbf_path([MODULE,] FILENAME)
195              
196             Returns the full path to the named file. Dies if the file does not exist.
197              
198             Will look for file in inherited classes (by reading @ISA) if the file is
199             not found for the derived class. @ISA navigation is the same as per Perl
200             searching for methods. See L for more details.
201              
202             The non-OO interface requires an object reference or module name as
203             the first parameter.
204              
205             =cut
206              
207             sub mbf_path($;$)
208             {
209 14     14 1 1592 my $module = shift;
210 14         23 my $filename = shift;
211 14 100       28 unless( mbf_exists($module,$filename) )
212             {
213 2         6 my $found = 0;
214 2   33     43 my $module_name = ref($module) || $module;
215 2         12 foreach my $module_isa (Class::ISA::super_path($module_name))
216             {
217 2 50       127 if( mbf_exists($module_isa,$filename) )
218             {
219 2         4 $module = $module_isa;
220 2         487 $found++;
221 2         4 last;
222             }
223             }
224 2 50       7 die "File not found: '$filename' for module '$module_name'"
225             unless $found;
226             }
227 14         31 my $dir = mbf_dir($module);
228 14         51 my $fullpath = catfile($dir,$filename);
229 14         40 return $fullpath;
230             }
231              
232             =head2 mbf_open([MODULE,] FILENAME)
233              
234             Returns an open file handle for the named file. Dies if the file does not exist.
235              
236             The non-OO interface requires an object reference or module name as
237             the first parameter.
238              
239             =cut
240              
241             sub mbf_open($;$)
242             {
243 10     10 1 2861 my $module = shift;
244 10         17 my $filename = shift;
245 10         28 my $fullpath = mbf_path($module,$filename);
246 10 50       1109 open my $fh, '<', $fullpath
247             or die "Could not open file '$filename': ".$@;
248 10         35 return $fh;
249             }
250              
251             =head2 mbf_read([MODULE,] FILENAME)
252              
253             Returns the content of the named file. Dies if the file does not exist.
254              
255             The non-OO interface requires an object reference or module name as
256             the first parameter.
257              
258             =cut
259              
260             sub mbf_read($;$)
261             {
262 6     6 1 4869 my $module = shift;
263 6         13 my $filename = shift;
264 6         18 my $fh = mbf_open($module,$filename);
265 6         15 my $content = '';
266 6         9 local $_;
267 6         106 while(<$fh>){$content.=$_;}
  18         85  
268 6         87 return $content;
269             }
270              
271             =head1 AUTHOR
272              
273             Paul Campbell, C<< >>
274              
275             =head1 BUGS
276              
277             Please report any bugs or feature requests to
278             C, or through the web interface at
279             L.
280             I will be notified, and then you will automatically be notified of progress on
281             your bug as I make changes.
282              
283             #=head1 ACKNOWLEDGEMENTS
284              
285             =head1 COPYRIGHT & LICENSE
286              
287             Copyright 2005 Paul Campbell, all rights reserved.
288              
289             This program is free software; you can redistribute it and/or modify it
290             under the same terms as Perl itself.
291              
292             =cut
293              
294             1; # End of Module::Bundled::Files