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