1 #############################################################################
2 # Pod/Find.pm -- finds files containing POD documentation
4 # Author: Marek Rouchal <marek@saftsack.fs.uni-bayreuth.de>
6 # borrowing code from Nick Ing-Simmon's PodToHtml
7 # This file is part of "PodParser". Pod::Find is free software;
8 # you can redistribute it and/or modify it under the same terms
10 #############################################################################
14 use vars qw($VERSION);
15 $VERSION = 0.10; ## Current version of this package
16 require 5.005; ## requires this Perl version or later
18 #############################################################################
22 Pod::Find - find POD documents in directory trees
26 use Pod::Find qw(pod_find simplify_name);
27 my %pods = pod_find({ -verbose => 1, -inc => 1 });
29 print "found library POD `$pods{$_}' in $_\n";
32 print "podname=",simplify_name('a/b/c/mymodule.pod'),"\n";
36 B<Pod::Find> provides a function B<pod_find> that searches for POD
37 documents in a given set of files and directories. It returns a hash
38 with the file names as keys and the POD name as value. The POD name
39 is derived from the file name and its position in the directory tree.
41 E.g. when searching in F<$HOME/perl5lib>, the file
42 F<$HOME/perl5lib/MyModule.pm> would get the POD name I<MyModule>,
43 whereas F<$HOME/perl5lib/Myclass/Subclass.pm> would be
44 I<Myclass::Subclass>. The name information can be used for POD
47 Only text files containing at least one valid POD command are found.
49 A warning is printed if more than one POD file with the same POD name
50 is found, e.g. F<CPAN.pm> in different directories. This usually
51 indicates duplicate occurences of modules in the I<@INC> search path.
53 The function B<simplify_name> is equivalent to B<basename>, but also
54 strips Perl-like extensions (.pm, .pl, .pod).
56 Note that neither B<pod_find> nor B<simplify_name> are exported by
57 default so be sure to specify them in the B<use> statement if you need them:
59 use Pod::Find qw(pod_find simplify_name);
63 The first argument for B<pod_find> may be a hash reference with options.
64 The rest are either directories that are searched recursively or files.
65 The POD names of files are the plain basenames with any Perl-like extension
66 (.pm, .pl, .pod) stripped.
72 Print progress information while scanning.
76 Apply Perl-specific heuristics to find the correct PODs. This includes
77 stripping Perl-like extensions, omitting subdirectories that are numeric
78 but do I<not> match the current Perl interpreter's version id, suppressing
79 F<site_perl> as a module hierarchy name etc.
83 Search for PODs in the current Perl interpreter's installation
84 B<scriptdir>. This is taken from the local L<Config|Config> module.
88 Search for PODs in the current Perl interpreter's I<@INC> paths.
94 Marek Rouchal E<lt>marek@saftsack.fs.uni-bayreuth.deE<gt>,
95 heavily borrowing code from Nick Ing-Simmons' PodToHtml.
99 L<Pod::Parser>, L<Pod::Checker>
109 use vars qw(@ISA @EXPORT_OK $VERSION);
111 @EXPORT_OK = qw(&pod_find &simplify_name);
113 # package global variables
116 # return a hash of the
124 $opts{-verbose} ||= 0;
131 push(@search, $Config::Config{scriptdir});
136 push(@search, grep($_ ne '.',@INC));
142 # this code simplifies the POD name for Perl modules:
143 # * remove "site_perl"
144 # * remove e.g. "i586-linux"
145 # * remove e.g. 5.00503
146 # * remove pod/ if followed by *.pod (e.g. in pod/perlfunc.pod)
148 qr!^(?i:site_perl/|$Config::Config{archname}/|\d+\.\d+([_.]?\d+)?/|pod/(?=.*?\.pod$))*!o;
156 foreach my $try (@search) {
157 unless($try =~ m:^/:) {
159 $try = join('/',$pwd,$try);
161 $try =~ s:/\.?(?=/|$)::; # simplify path
164 if($name = _check_and_extract_name($try, $opts{-verbose})) {
165 _check_for_duplicates($try, $name, \%names, \%pods);
169 my $root_rx = qr!^\Q$try\E/!;
170 File::Find::find( sub {
171 my $item = $File::Find::name;
173 if($dirs_visited{$item}) {
174 warn "Directory '$item' already seen, skipping.\n"
176 $File::Find::prune = 1;
180 $dirs_visited{$item} = 1;
182 if($opts{-perl} && /^(\d+\.[\d_]+)$/ && eval "$1" != $]) {
183 $File::Find::prune = 1;
184 warn "Perl $] version mismatch on $_, skipping.\n"
189 if($name = _check_and_extract_name($item, $opts{-verbose}, $root_rx)) {
190 _check_for_duplicates($item, $name, \%names, \%pods);
192 }, $try); # end of File::Find::find
198 sub _check_for_duplicates {
199 my ($file, $name, $names_ref, $pods_ref) = @_;
200 if($$names_ref{$name}) {
201 warn "Duplicate POD found (shadowing?): $name ($file)\n";
202 warn " Already seen in ",
203 join(' ', grep($$pods_ref{$_} eq $name, keys %$pods_ref)),"\n";
206 $$names_ref{$name} = 1;
208 $$pods_ref{$file} = $name;
211 sub _check_and_extract_name {
212 my ($file, $verbose, $root_rx) = @_;
214 # check extension or executable
215 unless($file =~ /\.(pod|pm|pl)$/i || (-f $file && -x _ && -T _)) {
219 # check for one line of POD
220 unless(open(POD,"<$file")) {
221 warn "Error: $file is unreadable: $!\n";
227 unless($pod =~ /\n=(head\d|pod|over|item)\b/) {
228 warn "No POD in $file, skipping.\n"
234 # strip non-significant path components
235 # _TODO_ what happens on e.g. Win32?
237 if(defined $root_rx) {
238 $name =~ s!$root_rx!!;
239 $name =~ s!$SIMPLIFY_RX!!o if(defined $SIMPLIFY_RX);
244 $name =~ s/\.(pod|pm|pl)$//i;
249 # basic simplification of the POD name:
250 # basename & strip extension
254 $str =~ s:\.p([lm]|od)$::i;