~ubuntu-branches/ubuntu/jaunty/horae/jaunty

« back to all changes in this revision

Viewing changes to 0CPAN/Pod-Simple-3.03/lib/Pod/Simple/Search.pm

  • Committer: Bazaar Package Importer
  • Author(s): Carlo Segre
  • Date: 2008-02-23 23:13:02 UTC
  • mfrom: (2.1.2 hardy)
  • Revision ID: james.westby@ubuntu.com-20080223231302-mnyyxs3icvrus4ke
Tags: 066-3
Apply patch to athena_parts/misc.pl for compatibility with 
perl-tk 804.28.

Show diffs side-by-side

added added

removed removed

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