1 #############################################################################
2 # Pod/Find.pm -- finds files containing POD documentation
4 # Author: Marek Rouchal <marek@saftsack.fs.uni-bayreuth.de>
6 # Copyright (C) 1999-2000 by Marek Rouchal (and borrowing code
7 # from Nick Ing-Simmon's PodToHtml). All rights reserved.
8 # This file is part of "PodParser". Pod::Find is free software;
9 # you can redistribute it and/or modify it under the same terms
11 #############################################################################
15 use vars qw($VERSION);
16 $VERSION = 0.12; ## Current version of this package
17 require 5.005; ## requires this Perl version or later
19 #############################################################################
23 Pod::Find - find POD documents in directory trees
27 use Pod::Find qw(pod_find simplify_name);
28 my %pods = pod_find({ -verbose => 1, -inc => 1 });
30 print "found library POD `$pods{$_}' in $_\n";
33 print "podname=",simplify_name('a/b/c/mymodule.pod'),"\n";
37 B<Pod::Find> provides a function B<pod_find> that searches for POD
38 documents in a given set of files and directories. It returns a hash
39 with the file names as keys and the POD name as value. The POD name
40 is derived from the file name and its position in the directory tree.
42 E.g. when searching in F<$HOME/perl5lib>, the file
43 F<$HOME/perl5lib/MyModule.pm> would get the POD name I<MyModule>,
44 whereas F<$HOME/perl5lib/Myclass/Subclass.pm> would be
45 I<Myclass::Subclass>. The name information can be used for POD
48 Only text files containing at least one valid POD command are found.
50 A warning is printed if more than one POD file with the same POD name
51 is found, e.g. F<CPAN.pm> in different directories. This usually
52 indicates duplicate occurrences of modules in the I<@INC> search path.
54 The function B<simplify_name> is equivalent to B<basename>, but also
55 strips Perl-like extensions (.pm, .pl, .pod) and extensions like
56 F<.bat>, F<.cmd> on Win32 and OS/2, respectively.
58 Note that neither B<pod_find> nor B<simplify_name> are exported by
59 default so be sure to specify them in the B<use> statement if you need
62 use Pod::Find qw(pod_find simplify_name);
66 The first argument for B<pod_find> may be a hash reference with options.
67 The rest are either directories that are searched recursively or files.
68 The POD names of files are the plain basenames with any Perl-like extension
69 (.pm, .pl, .pod) stripped.
75 Print progress information while scanning.
79 Apply Perl-specific heuristics to find the correct PODs. This includes
80 stripping Perl-like extensions, omitting subdirectories that are numeric
81 but do I<not> match the current Perl interpreter's version id, suppressing
82 F<site_perl> as a module hierarchy name etc.
86 Search for PODs in the current Perl interpreter's installation
87 B<scriptdir>. This is taken from the local L<Config|Config> module.
91 Search for PODs in the current Perl interpreter's I<@INC> paths. This
92 automatically considers paths specified in the C<PERL5LIB> environment.
98 Marek Rouchal E<lt>marek@saftsack.fs.uni-bayreuth.deE<gt>,
99 heavily borrowing code from Nick Ing-Simmons' PodToHtml.
103 L<Pod::Parser>, L<Pod::Checker>
114 use vars qw(@ISA @EXPORT_OK $VERSION);
116 @EXPORT_OK = qw(&pod_find &simplify_name);
118 # package global variables
121 # return a hash of the POD files found
122 # first argument may be a hashref (options),
123 # rest is a list of directories to search recursively
131 $opts{-verbose} ||= 0;
138 push(@search, $Config::Config{scriptdir});
143 push(@search, grep($_ ne '.',@INC));
149 # this code simplifies the POD name for Perl modules:
150 # * remove "site_perl"
151 # * remove e.g. "i586-linux" (from 'archname')
152 # * remove e.g. 5.00503
153 # * remove pod/ if followed by *.pod (e.g. in pod/perlfunc.pod)
155 qq!^(?i:site_perl/|\Q$Config::Config{archname}\E/|\\d+\\.\\d+([_.]?\\d+)?/|pod/(?=.*?\\.pod\\z))*!;
164 foreach my $try (@search) {
165 unless(File::Spec->file_name_is_absolute($try)) {
167 $try = File::Spec->catfile($pwd,$try);
170 $try = File::Spec->canonpath($try);
173 if($name = _check_and_extract_name($try, $opts{-verbose})) {
174 _check_for_duplicates($try, $name, \%names, \%pods);
178 my $root_rx = qq!^\Q$try\E/!;
179 File::Find::find( sub {
180 my $item = $File::Find::name;
182 if($dirs_visited{$item}) {
183 warn "Directory '$item' already seen, skipping.\n"
185 $File::Find::prune = 1;
189 $dirs_visited{$item} = 1;
191 if($opts{-perl} && /^(\d+\.[\d_]+)\z/s && eval "$1" != $]) {
192 $File::Find::prune = 1;
193 warn "Perl $] version mismatch on $_, skipping.\n"
198 if($name = _check_and_extract_name($item, $opts{-verbose}, $root_rx)) {
199 _check_for_duplicates($item, $name, \%names, \%pods);
201 }, $try); # end of File::Find::find
207 sub _check_for_duplicates {
208 my ($file, $name, $names_ref, $pods_ref) = @_;
209 if($$names_ref{$name}) {
210 warn "Duplicate POD found (shadowing?): $name ($file)\n";
211 warn " Already seen in ",
212 join(' ', grep($$pods_ref{$_} eq $name, keys %$pods_ref)),"\n";
215 $$names_ref{$name} = 1;
217 $$pods_ref{$file} = $name;
220 sub _check_and_extract_name {
221 my ($file, $verbose, $root_rx) = @_;
223 # check extension or executable flag
224 # this involves testing the .bat extension on Win32!
225 unless($file =~ /\.(pod|pm|plx?)\z/i || (-f $file && -x _ && -T _)) {
229 # check for one line of POD
230 unless(open(POD,"<$file")) {
231 warn "Error: $file is unreadable: $!\n";
237 unless($pod =~ /\n=(head\d|pod|over|item)\b/) {
238 warn "No POD in $file, skipping.\n"
244 # strip non-significant path components
245 # _TODO_ what happens on e.g. Win32?
247 if(defined $root_rx) {
248 $name =~ s!$root_rx!!s;
249 $name =~ s!$SIMPLIFY_RX!!os if(defined $SIMPLIFY_RX);
255 $name =~ s!/+!::!g; #/
259 # basic simplification of the POD name:
260 # basename & strip extension
263 # remove all path components
271 # strip Perl's own extensions
272 $_[0] =~ s/\.(pod|pm|plx?)\z//i;
273 # strip meaningless extensions on Win32 and OS/2
274 $_[0] =~ s/\.(bat|exe|cmd)\z//i if($^O =~ /win|os2/i);