ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/File-INC/INC.pm
Revision: 1.2
Committed: Wed May 1 03:08:29 2013 UTC (13 years, 4 months ago) by root
Branch: MAIN
Changes since 1.1: +9 -8 lines
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 root 1.1 =head1 NAME
2    
3     File::INC - find files via @INC
4    
5     =head1 SYNOPSIS
6    
7     use File::INC;
8    
9     =head1 DESCRIPTION
10    
11     Perl has two almost identical facilities to load "library"
12     files: C<require> and C<do> (C<use> is basically a compile-time
13     C<require>).
14    
15     These search C<@INC> for the file and compile it.
16    
17     Unfortunately, sometimes you want to locate data (or even source) files
18     using the same mechanism. The problem is that Perl I<laways> evaluates the
19     files as Perl code, which is not something you want for data files.
20    
21     This module implements the same (hopefully :) C<@INC> walk code as perl,
22     and gives you access to the resulting files, without evaluating them.
23    
24     =head2 ALTERNATIVES
25    
26     There are alternatives to this module, both of which I regularly employ,
27     but they come with their own drawbacks:
28    
29     =over 4
30    
31     =item Walking C<@INC> manually and treating it as an array of directories.
32    
33     Basically, this:
34    
35     sub find_rcfile($) {
36     my $path;
37    
38     for (@RC_PATH, "") {
39     $path = "$RC_BASE/$_/$_[0]";
40     return $path if -e $path;
41     }
42    
43     die "FATAL: can't find required file \"$_[0]\" in \"$RC_BASE\"\n";
44     }
45    
46     my $path = find_rcfile "My/Module/datafile.dat";
47    
48     This is simple, but fails for any entries in C<@INC> that are not
49     directories. Not handling these makes it fail in many environments, such
50     as in L<App::Staticperl> or L<PAR::Packer>.
51    
52     This module basically implements a full-featured version of this that
53     hopefully gets everything right.
54    
55     =item Embed datafiles using C<do>.
56    
57     You can embed datafiles by, say, uuencoding them and putting them into
58     a F<.pm> file (I think L<PAR::Packer>) does this. This is extremely
59     wasteful, but at least works around the C<@INC> problematic. A slightly
60     better way is to use C<do>. Take this file, put as F<My/Module/data.pl>
61     into the perl library:
62    
63     <<EOF
64     text data...
65     EOF
66    
67     Then you can load the "text data..." part using a simple C<do> call:
68    
69     my $data = do "My/Module/data.pl";
70    
71     You can handle arbirary binary data either by finding a suitable C<EOF>
72     marker that isn't part of it, or you could use utf8 encoding to the
73     rescue, by using a >255 character code as text delimiter:
74    
75     use utf8;
76     # use U+2026 as delimiter
77     q…arbitary binary data....…
78    
79     While this takes care of C<@INC>, perl still has to compile and execute
80     it every time (which might not be a significant problem), and it requires
81     the data to be formatted specifically for this occasion, so is hard for
82     accessing the sources of third-party modules.
83    
84     =back
85    
86     =head1 FUNCTIONS
87    
88     This module only provides one function, not exported, that creates
89     C<File::INC> objects.
90    
91     =over 4
92    
93     =cut
94    
95     package File::INC;
96    
97     use common::sense;
98    
99     use Carp ();
100    
101     our $VERSION = 0.2;
102    
103     =item $inc = File::INC::find $name
104    
105     The name is a file name of the same syntax as expected by C<do EXPR> or
106     C<require EXPR>, e.g. F<File/INC.pm> or F<My/Module/data.bin>. Unlike
107     C<require> et al., absolute paths are not supported.
108    
109     If the file is found, it returns a C<File::INC> object. Otherwise, it
110     returns C<undef>.
111    
112     To work around potential bugs in C<@INC> hooks, it is recommended to only
113     keep one C<File::INC> around at any single time.
114    
115     =cut
116    
117     sub find($) {
118     my $file = shift;
119    
120     for my $inc (@INC) {
121     if (ref $inc) {
122     my $func;
123    
124     if (CODE:: eq ref $inc) {
125     $func = $inc;
126     } elsif (ARRAY:: eq ref $inc) {
127     $func = $inc->[0];
128     } else {
129     $func = $inc->can ("INC");
130     }
131    
132     if ($func) {
133     my @r = $func->($inc, $file);;
134     my ($cache, $fh, $sub, $state);
135    
136     # undocumented and unsupported
137     if (!eval { fileno $r[0] } and CODE:: ne ref $r[0]) {
138     $cache = shift @r;
139     }
140    
141     if (defined eval { fileno $r[0] }) {
142     $fh = shift @r;
143     }
144    
145     if (CODE:: eq ref $r[0]) {
146     $sub = shift @r;
147     }
148    
149     $state = shift @r;
150    
151     if (defined $fh or defined $cache or defined $sub) {
152     defined $cache
153     and Carp::croak "File::INC: undocumented filter caches are not supported\n";
154    
155     return bless [undef, $fh, $sub, $state, $cache];
156     }
157     }
158    
159     } elsif (-e "$inc/$file") {
160     # what a relief, the simple case
161     return bless ["$inc/$file"];
162     }
163     }
164    
165     undef
166     }
167    
168     =back
169    
170     =head1 THE C<File::INC> CLASS
171    
172     Library files are represented by C<File::INC> objects. You can query it to
173     find more information about the file (such as whether it even is a file
174     :).
175    
176     =over 4
177    
178     =item $path = $inc->path
179    
180     If the file is actually a file on disk (the most common, but not
181     guaranteed, case), then this method returns the path to it. In other
182     cases, it returns C<undef>.
183    
184     =cut
185    
186     sub path {
187     $_[0][0]
188     }
189    
190     =item $path = $inc->force_path
191    
192     #todo
193    
194     =cut
195    
196     sub force_path {
197     die;
198     }
199    
200     =item $fh = $inc->fh
201    
202     =cut
203    
204     sub fh {
205     if (defined $_[0][0]) { # path?
206     open my $fh, "<", $_[0][0];
207     return $fh;
208     } elsif (defined $_[0][1] && !defined $_[0][2]) { # fh. and no filter?
209     return $_[0][1];
210     } else {
211     return undef;
212     }
213     }
214    
215     =item $fh = $inc->force_fh
216    
217     #todo
218    
219     =cut
220    
221     sub force_fh {
222     die;
223     }
224    
225     =item $data = $inc->data
226    
227     =cut
228    
229     sub data {
230     if ($_[0][0]) { # path
231     open my $fh, "<", $_[0][0]
232     or die "$_[0][0]: $!";
233    
234     } elsif (defined $_[0][1]) { # fh
235     if (defined $_[0][2]) { # filter sub
236     my @data;
237     my $status;
238    
239     local $_;
240 root 1.2 while () {
241     $_ = <$_[0][1]>;
242 root 1.1 $status = $_[0][2]->($_[0][3]);
243     push @data, $_;
244     last if $status <= 0;
245     }
246    
247     return join "", @data;
248     }
249    
250     # plain file, slurp
251     local $/;
252     return scalar <$_[0][1]>;
253    
254     } elsif (defined $_[0][2]) {
255     # "filter" sub
256    
257     my @data;
258     my $status;
259    
260     local $_;
261     while () {
262     $_ = "";
263     $status = $_[0][2]->($_[0][3]);
264     push @data, $_;
265     last if $status <= 0;
266     }
267    
268     return join "", @data;
269    
270     } else {
271     die "internal error";
272     }
273     }
274    
275     =back
276    
277     =head1 LIMITATIONS
278    
279     As with many of the newer additions to perl, C<@INC> hooks have been
280 root 1.2 poorly designed (the interface is pretty chaotic and does not follow Perl
281     language rules, and the subroutine magically has to know whether the line
282     passed to it is the last line of the file) and documented (for example,
283     the filter cache is completely undocumented), and as a result, it's not
284     (to the best of my knowledge) possible implement this module in pure
285     Perl. I hope this implementation is good enough for real world C<@INC>
286     hooks.
287 root 1.1
288     Known deficiencies are that file handles are detected differently,
289     only a copy of the state argument is passed to the subroutine, and the
290     undocumented filter cache return value is ignored.
291    
292     =head1 AUTHOR AND CONTACT INFORMATION
293    
294     Marc Lehmann <schmorp@schmorp.de>
295     http://software.schmorp.de/pkg/File-INC
296    
297     =cut
298    
299     1
300