1
2require 5.005;
3package Pod::Simple::Search;
4use strict;
5
6use vars qw($VERSION $MAX_VERSION_WITHIN $SLEEPY);
7$VERSION = '3.20';   ## Current version of this package
8
9BEGIN { *DEBUG = sub () {0} unless defined &DEBUG; }   # set DEBUG level
10use Carp ();
11
12$SLEEPY = 1 if !defined $SLEEPY and $^O =~ /mswin|mac/i;
13  # flag to occasionally sleep for $SLEEPY - 1 seconds.
14
15$MAX_VERSION_WITHIN ||= 60;
16
17#############################################################################
18
19#use diagnostics;
20use File::Spec ();
21use File::Basename qw( basename );
22use Config ();
23use Cwd qw( cwd );
24
25#==========================================================================
26__PACKAGE__->_accessorize(  # Make my dumb accessor methods
27 'callback', 'progress', 'dir_prefix', 'inc', 'laborious', 'limit_glob',
28 'limit_re', 'shadows', 'verbose', 'name2path', 'path2name', 'recurse',
29);
30#==========================================================================
31
32sub new {
33  my $class = shift;
34  my $self = bless {}, ref($class) || $class;
35  $self->init;
36  return $self;
37}
38
39sub init {
40  my $self = shift;
41  $self->inc(1);
42  $self->recurse(1);
43  $self->verbose(DEBUG);
44  return $self;
45}
46
47#--------------------------------------------------------------------------
48
49sub survey {
50  my($self, @search_dirs) = @_;
51  $self = $self->new unless ref $self; # tolerate being a class method
52
53  $self->_expand_inc( \@search_dirs );
54
55
56  $self->{'_scan_count'} = 0;
57  $self->{'_dirs_visited'} = {};
58  $self->path2name( {} );
59  $self->name2path( {} );
60  $self->limit_re( $self->_limit_glob_to_limit_re ) if $self->{'limit_glob'};
61  my $cwd = cwd();
62  my $verbose  = $self->verbose;
63  local $_; # don't clobber the caller's $_ !
64
65  foreach my $try (@search_dirs) {
66    unless( File::Spec->file_name_is_absolute($try) ) {
67      # make path absolute
68      $try = File::Spec->catfile( $cwd ,$try);
69    }
70    # simplify path
71    $try =  File::Spec->canonpath($try);
72
73    my $start_in;
74    my $modname_prefix;
75    if($self->{'dir_prefix'}) {
76      $start_in = File::Spec->catdir(
77        $try,
78        grep length($_), split '[\\/:]+', $self->{'dir_prefix'}
79      );
80      $modname_prefix = [grep length($_), split m{[:/\\]}, $self->{'dir_prefix'}];
81      $verbose and print "Appending \"$self->{'dir_prefix'}\" to $try, ",
82        "giving $start_in (= @$modname_prefix)\n";
83    } else {
84      $start_in = $try;
85    }
86
87    if( $self->{'_dirs_visited'}{$start_in} ) {
88      $verbose and print "Directory '$start_in' already seen, skipping.\n";
89      next;
90    } else {
91      $self->{'_dirs_visited'}{$start_in} = 1;
92    }
93
94    unless(-e $start_in) {
95      $verbose and print "Skipping non-existent $start_in\n";
96      next;
97    }
98
99    my $closure = $self->_make_search_callback;
100
101    if(-d $start_in) {
102      # Normal case:
103      $verbose and print "Beginning excursion under $start_in\n";
104      $self->_recurse_dir( $start_in, $closure, $modname_prefix );
105      $verbose and print "Back from excursion under $start_in\n\n";
106
107    } elsif(-f _) {
108      # A excursion consisting of just one file!
109      $_ = basename($start_in);
110      $verbose and print "Pondering $start_in ($_)\n";
111      $closure->($start_in, $_, 0, []);
112
113    } else {
114      $verbose and print "Skipping mysterious $start_in\n";
115    }
116  }
117  $self->progress and $self->progress->done(
118   "Noted $$self{'_scan_count'} Pod files total");
119
120  return unless defined wantarray; # void
121  return $self->name2path unless wantarray; # scalar
122  return $self->name2path, $self->path2name; # list
123}
124
125
126#==========================================================================
127sub _make_search_callback {
128  my $self = $_[0];
129
130  # Put the options in variables, for easy access
131  my( $laborious, $verbose, $shadows, $limit_re, $callback, $progress,
132      $path2name, $name2path, $recurse) =
133    map scalar($self->$_()),
134     qw(laborious verbose shadows limit_re callback progress
135        path2name name2path recurse);
136
137  my($file, $shortname, $isdir, $modname_bits);
138  return sub {
139    ($file, $shortname, $isdir, $modname_bits) = @_;
140
141    if($isdir) { # this never gets called on the startdir itself, just subdirs
142
143      unless( $recurse ) {
144        $verbose and print "Not recursing into '$file' as per requested.\n";
145        return 'PRUNE';
146      }
147
148      if( $self->{'_dirs_visited'}{$file} ) {
149        $verbose and print "Directory '$file' already seen, skipping.\n";
150        return 'PRUNE';
151      }
152
153      print "Looking in dir $file\n" if $verbose;
154
155      unless ($laborious) { # $laborious overrides pruning
156        if( m/^(\d+\.[\d_]{3,})\z/s
157             and do { my $x = $1; $x =~ tr/_//d; $x != $] }
158           ) {
159          $verbose and print "Perl $] version mismatch on $_, skipping.\n";
160          return 'PRUNE';
161        }
162
163        if( m/^([A-Za-z][a-zA-Z0-9_]*)\z/s ) {
164          $verbose and print "$_ is a well-named module subdir.  Looking....\n";
165        } else {
166          $verbose and print "$_ is a fishy directory name.  Skipping.\n";
167          return 'PRUNE';
168        }
169      } # end unless $laborious
170
171      $self->{'_dirs_visited'}{$file} = 1;
172      return; # (not pruning);
173    }
174
175
176    # Make sure it's a file even worth even considering
177    if($laborious) {
178      unless(
179        m/\.(pod|pm|plx?)\z/i || -x _ and -T _
180         # Note that the cheapest operation (the RE) is run first.
181      ) {
182        $verbose > 1 and print " Brushing off uninteresting $file\n";
183        return;
184      }
185    } else {
186      unless( m/^[-_a-zA-Z0-9]+\.(?:pod|pm|plx?)\z/is ) {
187        $verbose > 1 and print " Brushing off oddly-named $file\n";
188        return;
189      }
190    }
191
192    $verbose and print "Considering item $file\n";
193    my $name = $self->_path2modname( $file, $shortname, $modname_bits );
194    $verbose > 0.01 and print " Nominating $file as $name\n";
195
196    if($limit_re and $name !~ m/$limit_re/i) {
197      $verbose and print "Shunning $name as not matching $limit_re\n";
198      return;
199    }
200
201    if( !$shadows and $name2path->{$name} ) {
202      $verbose and print "Not worth considering $file ",
203        "-- already saw $name as ",
204        join(' ', grep($path2name->{$_} eq $name, keys %$path2name)), "\n";
205      return;
206    }
207
208    # Put off until as late as possible the expense of
209    #  actually reading the file:
210    if( m/\.pod\z/is ) {
211      # just assume it has pod, okay?
212    } else {
213      $progress and $progress->reach($self->{'_scan_count'}, "Scanning $file");
214      return unless $self->contains_pod( $file );
215    }
216    ++ $self->{'_scan_count'};
217
218    # Or finally take note of it:
219    if( $name2path->{$name} ) {
220      $verbose and print
221       "Duplicate POD found (shadowing?): $name ($file)\n",
222       "    Already seen in ",
223       join(' ', grep($path2name->{$_} eq $name, keys %$path2name)), "\n";
224    } else {
225      $name2path->{$name} = $file; # Noting just the first occurrence
226    }
227    $verbose and print "  Noting $name = $file\n";
228    if( $callback ) {
229      local $_ = $_; # insulate from changes, just in case
230      $callback->($file, $name);
231    }
232    $path2name->{$file} = $name;
233    return;
234  }
235}
236
237#==========================================================================
238
239sub _path2modname {
240  my($self, $file, $shortname, $modname_bits) = @_;
241
242  # this code simplifies the POD name for Perl modules:
243  # * remove "site_perl"
244  # * remove e.g. "i586-linux" (from 'archname')
245  # * remove e.g. 5.00503
246  # * remove pod/ if followed by perl*.pod (e.g. in pod/perlfunc.pod)
247  # * dig into the file for case-preserved name if not already mixed case
248
249  my @m = @$modname_bits;
250  my $x;
251  my $verbose = $self->verbose;
252
253  # Shaving off leading naughty-bits
254  while(@m
255    and defined($x = lc( $m[0] ))
256    and(  $x eq 'site_perl'
257       or($x eq 'pod' and @m == 1 and $shortname =~ m{^perl.*\.pod$}s )
258       or $x =~ m{\\d+\\.z\\d+([_.]?\\d+)?}  # if looks like a vernum
259       or $x eq lc( $Config::Config{'archname'} )
260  )) { shift @m }
261
262  my $name = join '::', @m, $shortname;
263  $self->_simplify_base($name);
264
265  # On VMS, case-preserved document names can't be constructed from
266  # filenames, so try to extract them from the "=head1 NAME" tag in the
267  # file instead.
268  if ($^O eq 'VMS' && ($name eq lc($name) || $name eq uc($name))) {
269      open PODFILE, "<$file" or die "_path2modname: Can't open $file: $!";
270      my $in_pod = 0;
271      my $in_name = 0;
272      my $line;
273      while ($line = <PODFILE>) {
274        chomp $line;
275        $in_pod = 1 if ($line =~ m/^=\w/);
276        $in_pod = 0 if ($line =~ m/^=cut/);
277        next unless $in_pod;         # skip non-pod text
278        next if ($line =~ m/^\s*\z/);           # and blank lines
279        next if ($in_pod && ($line =~ m/^X</)); # and commands
280        if ($in_name) {
281          if ($line =~ m/(\w+::)?(\w+)/) {
282            # substitute case-preserved version of name
283            my $podname = $2;
284            my $prefix = $1 || '';
285            $verbose and print "Attempting case restore of '$name' from '$prefix$podname'\n";
286            unless ($name =~ s/$prefix$podname/$prefix$podname/i) {
287              $verbose and print "Attempting case restore of '$name' from '$podname'\n";
288              $name =~ s/$podname/$podname/i;
289            }
290            last;
291          }
292        }
293        $in_name = 1 if ($line =~ m/^=head1 NAME/);
294    }
295    close PODFILE;
296  }
297
298  return $name;
299}
300
301#==========================================================================
302
303sub _recurse_dir {
304  my($self, $startdir, $callback, $modname_bits) = @_;
305
306  my $maxdepth = $self->{'fs_recursion_maxdepth'} || 10;
307  my $verbose = $self->verbose;
308
309  my $here_string = File::Spec->curdir;
310  my $up_string   = File::Spec->updir;
311  $modname_bits ||= [];
312
313  my $recursor;
314  $recursor = sub {
315    my($dir_long, $dir_bare) = @_;
316    if( @$modname_bits >= 10 ) {
317      $verbose and print "Too deep! [@$modname_bits]\n";
318      return;
319    }
320
321    unless(-d $dir_long) {
322      $verbose > 2 and print "But it's not a dir! $dir_long\n";
323      return;
324    }
325    unless( opendir(INDIR, $dir_long) ) {
326      $verbose > 2 and print "Can't opendir $dir_long : $!\n";
327      closedir(INDIR);
328      return
329    }
330    my @items = sort readdir(INDIR);
331    closedir(INDIR);
332
333    push @$modname_bits, $dir_bare unless $dir_bare eq '';
334
335    my $i_full;
336    foreach my $i (@items) {
337      next if $i eq $here_string or $i eq $up_string or $i eq '';
338      $i_full = File::Spec->catfile( $dir_long, $i );
339
340      if(!-r $i_full) {
341        $verbose and print "Skipping unreadable $i_full\n";
342
343      } elsif(-f $i_full) {
344        $_ = $i;
345        $callback->(          $i_full, $i, 0, $modname_bits );
346
347      } elsif(-d _) {
348        $i =~ s/\.DIR\z//i if $^O eq 'VMS';
349        $_ = $i;
350        my $rv = $callback->( $i_full, $i, 1, $modname_bits ) || '';
351
352        if($rv eq 'PRUNE') {
353          $verbose > 1 and print "OK, pruning";
354        } else {
355          # Otherwise, recurse into it
356          $recursor->( File::Spec->catdir($dir_long, $i) , $i);
357        }
358      } else {
359        $verbose > 1 and print "Skipping oddity $i_full\n";
360      }
361    }
362    pop @$modname_bits;
363    return;
364  };;
365
366  local $_;
367  $recursor->($startdir, '');
368
369  undef $recursor;  # allow it to be GC'd
370
371  return;
372}
373
374
375#==========================================================================
376
377sub run {
378  # A function, useful in one-liners
379
380  my $self = __PACKAGE__->new;
381  $self->limit_glob($ARGV[0]) if @ARGV;
382  $self->callback( sub {
383    my($file, $name) = @_;
384    my $version = '';
385
386    # Yes, I know we won't catch the version in like a File/Thing.pm
387    #  if we see File/Thing.pod first.  That's just the way the
388    #  cookie crumbles.  -- SMB
389
390    if($file =~ m/\.pod$/i) {
391      # Don't bother looking for $VERSION in .pod files
392      DEBUG and print "Not looking for \$VERSION in .pod $file\n";
393    } elsif( !open(INPOD, $file) ) {
394      DEBUG and print "Couldn't open $file: $!\n";
395      close(INPOD);
396    } else {
397      # Sane case: file is readable
398      my $lines = 0;
399      while(<INPOD>) {
400        last if $lines++ > $MAX_VERSION_WITHIN; # some degree of sanity
401        if( s/^\s*\$VERSION\s*=\s*//s and m/\d/ ) {
402          DEBUG and print "Found version line (#$lines): $_";
403          s/\s*\#.*//s;
404          s/\;\s*$//s;
405          s/\s+$//s;
406          s/\t+/ /s; # nix tabs
407          # Optimize the most common cases:
408          $_ = "v$1"
409            if m{^v?["']?([0-9_]+(\.[0-9_]+)*)["']?$}s
410             # like in $VERSION = "3.14159";
411             or m{\$Revision:\s*([0-9_]+(?:\.[0-9_]+)*)\s*\$}s
412             # like in sprintf("%d.%02d", q$Revision: 4.13 $ =~ /(\d+)\.(\d+)/);
413          ;
414
415          # Like in sprintf("%d.%s", map {s/_//g; $_} q$Name: release-0_55-public $ =~ /-(\d+)_([\d_]+)/)
416          $_ = sprintf("v%d.%s",
417            map {s/_//g; $_}
418              $1 =~ m/-(\d+)_([\d_]+)/) # snare just the numeric part
419           if m{\$Name:\s*([^\$]+)\$}s
420          ;
421          $version = $_;
422          DEBUG and print "Noting $version as version\n";
423          last;
424        }
425      }
426      close(INPOD);
427    }
428    print "$name\t$version\t$file\n";
429    return;
430    # End of callback!
431  });
432
433  $self->survey;
434}
435
436#==========================================================================
437
438sub simplify_name {
439  my($self, $str) = @_;
440
441  # Remove all path components
442  #                             XXX Why not just use basename()? -- SMB
443
444  if ($^O eq 'MacOS') { $str =~ s{^.*:+}{}s }
445  else                { $str =~ s{^.*/+}{}s }
446
447  $self->_simplify_base($str);
448  return $str;
449}
450
451#==========================================================================
452
453sub _simplify_base {   # Internal method only
454
455  # strip Perl's own extensions
456  $_[1] =~ s/\.(pod|pm|plx?)\z//i;
457
458  # strip meaningless extensions on Win32 and OS/2
459  $_[1] =~ s/\.(bat|exe|cmd)\z//i if $^O =~ /mswin|os2/i;
460
461  # strip meaningless extensions on VMS
462  $_[1] =~ s/\.(com)\z//i if $^O eq 'VMS';
463
464  return;
465}
466
467#==========================================================================
468
469sub _expand_inc {
470  my($self, $search_dirs) = @_;
471
472  return unless $self->{'inc'};
473
474  if ($^O eq 'MacOS') {
475    push @$search_dirs,
476      grep $_ ne File::Spec->curdir, $self->_mac_whammy(@INC);
477  # Any other OSs need custom handling here?
478  } else {
479    push @$search_dirs, grep $_ ne File::Spec->curdir,  @INC;
480  }
481
482  $self->{'laborious'} = 0;   # Since inc said to use INC
483  return;
484}
485
486#==========================================================================
487
488sub _mac_whammy { # Tolerate '.', './some_dir' and '(../)+some_dir' on Mac OS
489  my @them;
490  (undef,@them) = @_;
491  for $_ (@them) {
492    if ( $_ eq '.' ) {
493      $_ = ':';
494    } elsif ( $_ =~ s|^((?:\.\./)+)|':' x (length($1)/3)|e ) {
495      $_ = ':'. $_;
496    } else {
497      $_ =~ s|^\./|:|;
498    }
499  }
500  return @them;
501}
502
503#==========================================================================
504
505sub _limit_glob_to_limit_re {
506  my $self = $_[0];
507  my $limit_glob = $self->{'limit_glob'} || return;
508
509  my $limit_re = '^' . quotemeta($limit_glob) . '$';
510  $limit_re =~ s/\\\?/./g;    # glob "?" => "."
511  $limit_re =~ s/\\\*/.*?/g;  # glob "*" => ".*?"
512  $limit_re =~ s/\.\*\?\$$//s; # final glob "*" => ".*?$" => ""
513
514  $self->{'verbose'} and print "Turning limit_glob $limit_glob into re $limit_re\n";
515
516  # A common optimization:
517  if(!exists($self->{'dir_prefix'})
518    and $limit_glob =~ m/^(?:\w+\:\:)+/s  # like "File::*" or "File::Thing*"
519    # Optimize for sane and common cases (but not things like "*::File")
520  ) {
521    $self->{'dir_prefix'} = join "::", $limit_glob =~ m/^(?:\w+::)+/sg;
522    $self->{'verbose'} and print " and setting dir_prefix to $self->{'dir_prefix'}\n";
523  }
524
525  return $limit_re;
526}
527
528#==========================================================================
529
530# contribution mostly from Tim Jenness <t.jenness@jach.hawaii.edu>
531
532sub find {
533  my($self, $pod, @search_dirs) = @_;
534  $self = $self->new unless ref $self; # tolerate being a class method
535
536  # Check usage
537  Carp::carp 'Usage: \$self->find($podname, ...)'
538   unless defined $pod and length $pod;
539
540  my $verbose = $self->verbose;
541
542  # Split on :: and then join the name together using File::Spec
543  my @parts = split /::/, $pod;
544  $verbose and print "Chomping {$pod} => {@parts}\n";
545
546  #@search_dirs = File::Spec->curdir unless @search_dirs;
547
548  if( $self->inc ) {
549    if( $^O eq 'MacOS' ) {
550      push @search_dirs, $self->_mac_whammy(@INC);
551    } else {
552      push @search_dirs,                    @INC;
553    }
554
555    # Add location of pod documentation for perl man pages (eg perlfunc)
556    # This is a pod directory in the private install tree
557    #my $perlpoddir = File::Spec->catdir($Config::Config{'installprivlib'},
558    #					'pod');
559    #push (@search_dirs, $perlpoddir)
560    #  if -d $perlpoddir;
561
562    # Add location of binaries such as pod2text:
563    push @search_dirs, $Config::Config{'scriptdir'};
564     # and if that's undef or q{} or nonexistent, we just ignore it later
565  }
566
567  my %seen_dir;
568 Dir:
569  foreach my $dir ( @search_dirs ) {
570    next unless defined $dir and length $dir;
571    next if $seen_dir{$dir};
572    $seen_dir{$dir} = 1;
573    unless(-d $dir) {
574      print "Directory $dir does not exist\n" if $verbose;
575      next Dir;
576    }
577
578    print "Looking in directory $dir\n" if $verbose;
579    my $fullname = File::Spec->catfile( $dir, @parts );
580    print "Filename is now $fullname\n" if $verbose;
581
582    foreach my $ext ('', '.pod', '.pm', '.pl') {   # possible extensions
583      my $fullext = $fullname . $ext;
584      if( -f $fullext  and  $self->contains_pod( $fullext ) ){
585        print "FOUND: $fullext\n" if $verbose;
586        return $fullext;
587      }
588    }
589    my $subdir = File::Spec->catdir($dir,'pod');
590    if(-d $subdir) {  # slip in the ./pod dir too
591      $verbose and print "Noticing $subdir and stopping there...\n";
592      $dir = $subdir;
593      redo Dir;
594    }
595  }
596
597  return undef;
598}
599
600#==========================================================================
601
602sub contains_pod {
603  my($self, $file) = @_;
604  my $verbose = $self->{'verbose'};
605
606  # check for one line of POD
607  $verbose > 1 and print " Scanning $file for pod...\n";
608  unless( open(MAYBEPOD,"<$file") ) {
609    print "Error: $file is unreadable: $!\n";
610    return undef;
611  }
612
613  sleep($SLEEPY - 1) if $SLEEPY;
614   # avoid totally hogging the processor on OSs with poor process control
615
616  local $_;
617  while( <MAYBEPOD> ) {
618    if(m/^=(head\d|pod|over|item)\b/s) {
619      close(MAYBEPOD) || die "Bizarre error closing $file: $!\nAborting";
620      chomp;
621      $verbose > 1 and print "  Found some pod ($_) in $file\n";
622      return 1;
623    }
624  }
625  close(MAYBEPOD) || die "Bizarre error closing $file: $!\nAborting";
626  $verbose > 1 and print "  No POD in $file, skipping.\n";
627  return 0;
628}
629
630#==========================================================================
631
632sub _accessorize {  # A simple-minded method-maker
633  shift;
634  no strict 'refs';
635  foreach my $attrname (@_) {
636    *{caller() . '::' . $attrname} = sub {
637      use strict;
638      $Carp::CarpLevel = 1,  Carp::croak(
639       "Accessor usage: \$obj->$attrname() or \$obj->$attrname(\$new_value)"
640      ) unless (@_ == 1 or @_ == 2) and ref $_[0];
641
642      # Read access:
643      return $_[0]->{$attrname} if @_ == 1;
644
645      # Write access:
646      $_[0]->{$attrname} = $_[1];
647      return $_[0]; # RETURNS MYSELF!
648    };
649  }
650  # Ya know, they say accessories make the ensemble!
651  return;
652}
653
654#==========================================================================
655sub _state_as_string {
656  my $self = $_[0];
657  return '' unless ref $self;
658  my @out = "{\n  # State of $self ...\n";
659  foreach my $k (sort keys %$self) {
660    push @out, "  ", _esc($k), " => ", _esc($self->{$k}), ",\n";
661  }
662  push @out, "}\n";
663  my $x = join '', @out;
664  $x =~ s/^/#/mg;
665  return $x;
666}
667
668sub _esc {
669  my $in = $_[0];
670  return 'undef' unless defined $in;
671  $in =~
672    s<([^\x20\x21\x23\x27-\x3F\x41-\x5B\x5D-\x7E])>
673     <'\\x'.(unpack("H2",$1))>eg;
674  return qq{"$in"};
675}
676
677#==========================================================================
678
679run() unless caller;  # run if "perl whatever/Search.pm"
680
6811;
682
683#==========================================================================
684
685__END__
686
687
688=head1 NAME
689
690Pod::Simple::Search - find POD documents in directory trees
691
692=head1 SYNOPSIS
693
694  use Pod::Simple::Search;
695  my $name2path = Pod::Simple::Search->new->limit_glob('LWP::*')->survey;
696  print "Looky see what I found: ",
697    join(' ', sort keys %$name2path), "\n";
698
699  print "LWPUA docs = ",
700    Pod::Simple::Search->new->find('LWP::UserAgent') || "?",
701    "\n";
702
703=head1 DESCRIPTION
704
705B<Pod::Simple::Search> is a class that you use for running searches
706for Pod files.  An object of this class has several attributes
707(mostly options for controlling search options), and some methods
708for searching based on those attributes.
709
710The way to use this class is to make a new object of this class,
711set any options, and then call one of the search options
712(probably C<survey> or C<find>).  The sections below discuss the
713syntaxes for doing all that.
714
715
716=head1 CONSTRUCTOR
717
718This class provides the one constructor, called C<new>.
719It takes no parameters:
720
721  use Pod::Simple::Search;
722  my $search = Pod::Simple::Search->new;
723
724=head1 ACCESSORS
725
726This class defines several methods for setting (and, occasionally,
727reading) the contents of an object. With two exceptions (discussed at
728the end of this section), these attributes are just for controlling the
729way searches are carried out.
730
731Note that each of these return C<$self> when you call them as
732C<< $self->I<whatever(value)> >>.  That's so that you can chain
733together set-attribute calls like this:
734
735  my $name2path =
736    Pod::Simple::Search->new
737    -> inc(0) -> verbose(1) -> callback(\&blab)
738    ->survey(@there);
739
740...which works exactly as if you'd done this:
741
742  my $search = Pod::Simple::Search->new;
743  $search->inc(0);
744  $search->verbose(1);
745  $search->callback(\&blab);
746  my $name2path = $search->survey(@there);
747
748=over
749
750=item $search->inc( I<true-or-false> );
751
752This attribute, if set to a true value, means that searches should
753implicitly add perl's I<@INC> paths. This
754automatically considers paths specified in the C<PERL5LIB> environment
755as this is prepended to I<@INC> by the Perl interpreter itself.
756This attribute's default value is B<TRUE>.  If you want to search
757only specific directories, set $self->inc(0) before calling
758$inc->survey or $inc->find.
759
760
761=item $search->verbose( I<nonnegative-number> );
762
763This attribute, if set to a nonzero positive value, will make searches output
764(via C<warn>) notes about what they're doing as they do it.
765This option may be useful for debugging a pod-related module.
766This attribute's default value is zero, meaning that no C<warn> messages
767are produced.  (Setting verbose to 1 turns on some messages, and setting
768it to 2 turns on even more messages, i.e., makes the following search(es)
769even more verbose than 1 would make them.)
770
771
772=item $search->limit_glob( I<some-glob-string> );
773
774This option means that you want to limit the results just to items whose
775podnames match the given glob/wildcard expression. For example, you
776might limit your search to just "LWP::*", to search only for modules
777starting with "LWP::*" (but not including the module "LWP" itself); or
778you might limit your search to "LW*" to see only modules whose (full)
779names begin with "LW"; or you might search for "*Find*" to search for
780all modules with "Find" somewhere in their full name. (You can also use
781"?" in a glob expression; so "DB?" will match "DBI" and "DBD".)
782
783
784=item $search->callback( I<\&some_routine> );
785
786This attribute means that every time this search sees a matching
787Pod file, it should call this callback routine.  The routine is called
788with two parameters: the current file's filespec, and its pod name.
789(For example: C<("/etc/perljunk/File/Crunk.pm", "File::Crunk")> would
790be in C<@_>.)
791
792The callback routine's return value is not used for anything.
793
794This attribute's default value is false, meaning that no callback
795is called.
796
797=item $search->laborious( I<true-or-false> );
798
799Unless you set this attribute to a true value, Pod::Search will
800apply Perl-specific heuristics to find the correct module PODs quickly.
801This attribute's default value is false.  You won't normally need
802to set this to true.
803
804Specifically: Turning on this option will disable the heuristics for
805seeing only files with Perl-like extensions, omitting subdirectories
806that are numeric but do I<not> match the current Perl interpreter's
807version ID, suppressing F<site_perl> as a module hierarchy name, etc.
808
809
810=item $search->shadows( I<true-or-false> );
811
812Unless you set this attribute to a true value, Pod::Simple::Search will
813consider only the first file of a given modulename as it looks thru the
814specified directories; that is, with this option off, if
815Pod::Simple::Search has seen a C<somepathdir/Foo/Bar.pm> already in this
816search, then it won't bother looking at a C<somelaterpathdir/Foo/Bar.pm>
817later on in that search, because that file is merely a "shadow". But if
818you turn on C<< $self->shadows(1) >>, then these "shadow" files are
819inspected too, and are noted in the pathname2podname return hash.
820
821This attribute's default value is false; and normally you won't
822need to turn it on.
823
824
825=item $search->limit_re( I<some-regxp> );
826
827Setting this attribute (to a value that's a regexp) means that you want
828to limit the results just to items whose podnames match the given
829regexp. Normally this option is not needed, and the more efficient
830C<limit_glob> attribute is used instead.
831
832
833=item $search->dir_prefix( I<some-string-value> );
834
835Setting this attribute to a string value means that the searches should
836begin in the specified subdirectory name (like "Pod" or "File::Find",
837also expressable as "File/Find"). For example, the search option
838C<< $search->limit_glob("File::Find::R*") >>
839is the same as the combination of the search options
840C<< $search->limit_re("^File::Find::R") -> dir_prefix("File::Find") >>.
841
842Normally you don't need to know about the C<dir_prefix> option, but I
843include it in case it might prove useful for someone somewhere.
844
845(Implementationally, searching with limit_glob ends up setting limit_re
846and usually dir_prefix.)
847
848
849=item $search->progress( I<some-progress-object> );
850
851If you set a value for this attribute, the value is expected
852to be an object (probably of a class that you define) that has a
853C<reach> method and a C<done> method.  This is meant for reporting
854progress during the search, if you don't want to use a simple
855callback.
856
857Normally you don't need to know about the C<progress> option, but I
858include it in case it might prove useful for someone somewhere.
859
860While a search is in progress, the progress object's C<reach> and
861C<done> methods are called like this:
862
863  # Every time a file is being scanned for pod:
864  $progress->reach($count, "Scanning $file");   ++$count;
865
866  # And then at the end of the search:
867  $progress->done("Noted $count Pod files total");
868
869Internally, we often set this to an object of class
870Pod::Simple::Progress.  That class is probably undocumented,
871but you may wish to look at its source.
872
873
874=item $name2path = $self->name2path;
875
876This attribute is not a search parameter, but is used to report the
877result of C<survey> method, as discussed in the next section.
878
879=item $path2name = $self->path2name;
880
881This attribute is not a search parameter, but is used to report the
882result of C<survey> method, as discussed in the next section.
883
884=back
885
886=head1 MAIN SEARCH METHODS
887
888Once you've actually set any options you want (if any), you can go
889ahead and use the following methods to search for Pod files
890in particular ways.
891
892
893=head2 C<< $search->survey( @directories ) >>
894
895The method C<survey> searches for POD documents in a given set of
896files and/or directories.  This runs the search according to the various
897options set by the accessors above.  (For example, if the C<inc> attribute
898is on, as it is by default, then the perl @INC directories are implicitly
899added to the list of directories (if any) that you specify.)
900
901The return value of C<survey> is two hashes:
902
903=over
904
905=item C<name2path>
906
907A hash that maps from each pod-name to the filespec (like
908"Stuff::Thing" => "/whatever/plib/Stuff/Thing.pm")
909
910=item C<path2name>
911
912A hash that maps from each Pod filespec to its pod-name (like
913"/whatever/plib/Stuff/Thing.pm" => "Stuff::Thing")
914
915=back
916
917Besides saving these hashes as the hashref attributes
918C<name2path> and C<path2name>, calling this function also returns
919these hashrefs.  In list context, the return value of
920C<< $search->survey >> is the list C<(\%name2path, \%path2name)>.
921In scalar context, the return value is C<\%name2path>.
922Or you can just call this in void context.
923
924Regardless of calling context, calling C<survey> saves
925its results in its C<name2path> and C<path2name> attributes.
926
927E.g., when searching in F<$HOME/perl5lib>, the file
928F<$HOME/perl5lib/MyModule.pm> would get the POD name I<MyModule>,
929whereas F<$HOME/perl5lib/Myclass/Subclass.pm> would be
930I<Myclass::Subclass>. The name information can be used for POD
931translators.
932
933Only text files containing at least one valid POD command are found.
934
935In verbose mode, a warning is printed if shadows are found (i.e., more
936than one POD file with the same POD name is found, e.g. F<CPAN.pm> in
937different directories).  This usually indicates duplicate occurrences of
938modules in the I<@INC> search path, which is occasionally inadvertent
939(but is often simply a case of a user's path dir having a more recent
940version than the system's general path dirs in general.)
941
942The options to this argument is a list of either directories that are
943searched recursively, or files.  (Usually you wouldn't specify files,
944but just dirs.)  Or you can just specify an empty-list, as in
945$name2path; with the
946C<inc> option on, as it is by default, teh
947
948The POD names of files are the plain basenames with any Perl-like
949extension (.pm, .pl, .pod) stripped, and path separators replaced by
950C<::>'s.
951
952Calling Pod::Simple::Search->search(...) is short for
953Pod::Simple::Search->new->search(...).  That is, a throwaway object
954with default attribute values is used.
955
956
957=head2 C<< $search->simplify_name( $str ) >>
958
959The method B<simplify_name> is equivalent to B<basename>, but also
960strips Perl-like extensions (.pm, .pl, .pod) and extensions like
961F<.bat>, F<.cmd> on Win32 and OS/2, or F<.com> on VMS, respectively.
962
963
964=head2 C<< $search->find( $pod ) >>
965
966=head2 C<< $search->find( $pod, @search_dirs ) >>
967
968Returns the location of a Pod file, given a Pod/module/script name
969(like "Foo::Bar" or "perlvar" or "perldoc"), and an idea of
970what files/directories to look in.
971It searches according to the various options set by the accessors above.
972(For example, if the C<inc> attribute is on, as it is by default, then
973the perl @INC directories are implicitly added to the list of
974directories (if any) that you specify.)
975
976This returns the full path of the first occurrence to the file.
977Package names (eg 'A::B') are automatically converted to directory
978names in the selected directory.  Additionally, '.pm', '.pl' and '.pod'
979are automatically appended to the search as required.
980(So, for example, under Unix, "A::B" is converted to "somedir/A/B.pm",
981"somedir/A/B.pod", or "somedir/A/B.pl", as appropriate.)
982
983If no such Pod file is found, this method returns undef.
984
985If any of the given search directories contains a F<pod/> subdirectory,
986then it is searched.  (That's how we manage to find F<perlfunc>,
987for example, which is usually in F<pod/perlfunc> in most Perl dists.)
988
989The C<verbose> and C<inc> attributes influence the behavior of this
990search; notably, C<inc>, if true, adds @INC I<and also
991$Config::Config{'scriptdir'}> to the list of directories to search.
992
993It is common to simply say C<< $filename = Pod::Simple::Search-> new
994->find("perlvar") >> so that just the @INC (well, and scriptdir)
995directories are searched.  (This happens because the C<inc>
996attribute is true by default.)
997
998Calling Pod::Simple::Search->find(...) is short for
999Pod::Simple::Search->new->find(...).  That is, a throwaway object
1000with default attribute values is used.
1001
1002
1003=head2 C<< $self->contains_pod( $file ) >>
1004
1005Returns true if the supplied filename (not POD module) contains some Pod
1006documentation.
1007=head1 SUPPORT
1008
1009Questions or discussion about POD and Pod::Simple should be sent to the
1010pod-people@perl.org mail list. Send an empty email to
1011pod-people-subscribe@perl.org to subscribe.
1012
1013This module is managed in an open GitHub repository,
1014L<http://github.com/theory/pod-simple/>. Feel free to fork and contribute, or
1015to clone L<git://github.com/theory/pod-simple.git> and send patches!
1016
1017Patches against Pod::Simple are welcome. Please send bug reports to
1018<bug-pod-simple@rt.cpan.org>.
1019
1020=head1 COPYRIGHT AND DISCLAIMERS
1021
1022Copyright (c) 2002 Sean M. Burke.
1023
1024This library is free software; you can redistribute it and/or modify it
1025under the same terms as Perl itself.
1026
1027This program is distributed in the hope that it will be useful, but
1028without any warranty; without even the implied warranty of
1029merchantability or fitness for a particular purpose.
1030
1031=head1 AUTHOR
1032
1033Pod::Simple was created by Sean M. Burke <sburke@cpan.org> with code borrowed
1034from Marek Rouchal's L<Pod::Find>, which in turn heavily borrowed code from
1035Nick Ing-Simmons' C<PodToHtml>.
1036
1037But don't bother him, he's retired.
1038
1039Pod::Simple is maintained by:
1040
1041=over
1042
1043=item * Allison Randal C<allison@perl.org>
1044
1045=item * Hans Dieter Pearcey C<hdp@cpan.org>
1046
1047=item * David E. Wheeler C<dwheeler@cpan.org>
1048
1049=back
1050
1051=cut
1052