ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/File-INC/INC.pm
Revision: 1.3
Committed: Wed May 1 03:09:22 2013 UTC (13 years, 5 months ago) by root
Branch: MAIN
Changes since 1.2: +3 -0 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 root 1.3 local $/;
235     return scalar <$fh>;
236    
237 root 1.1 } elsif (defined $_[0][1]) { # fh
238     if (defined $_[0][2]) { # filter sub
239     my @data;
240     my $status;
241    
242     local $_;
243 root 1.2 while () {
244     $_ = <$_[0][1]>;
245 root 1.1 $status = $_[0][2]->($_[0][3]);
246     push @data, $_;
247     last if $status <= 0;
248     }
249    
250     return join "", @data;
251     }
252    
253     # plain file, slurp
254     local $/;
255     return scalar <$_[0][1]>;
256    
257     } elsif (defined $_[0][2]) {
258     # "filter" sub
259    
260     my @data;
261     my $status;
262    
263     local $_;
264     while () {
265     $_ = "";
266     $status = $_[0][2]->($_[0][3]);
267     push @data, $_;
268     last if $status <= 0;
269     }
270    
271     return join "", @data;
272    
273     } else {
274     die "internal error";
275     }
276     }
277    
278     =back
279    
280     =head1 LIMITATIONS
281    
282     As with many of the newer additions to perl, C<@INC> hooks have been
283 root 1.2 poorly designed (the interface is pretty chaotic and does not follow Perl
284     language rules, and the subroutine magically has to know whether the line
285     passed to it is the last line of the file) and documented (for example,
286     the filter cache is completely undocumented), and as a result, it's not
287     (to the best of my knowledge) possible implement this module in pure
288     Perl. I hope this implementation is good enough for real world C<@INC>
289     hooks.
290 root 1.1
291     Known deficiencies are that file handles are detected differently,
292     only a copy of the state argument is passed to the subroutine, and the
293     undocumented filter cache return value is ignored.
294    
295     =head1 AUTHOR AND CONTACT INFORMATION
296    
297     Marc Lehmann <schmorp@schmorp.de>
298     http://software.schmorp.de/pkg/File-INC
299    
300     =cut
301    
302     1
303