Pod-Index-0.14/0040755000076400007640000000000010324315142011710 5ustar ivanivanPod-Index-0.14/Changes0100644000076400007640000000225210324315121013176 0ustar ivanivanRevision history for Pod-Index 0.14 2005-10-15 - Improved portability, particularly for the tests. - Make sure tests can run from any directory. - Updated default filemap to look at @INC. 0.13 2005-10-12 - Sort index by keyword,podname,line instead of keyword,line. - Use File::Spec in tests instead of hardcoded slashes. 0.12 2005-08-14 - Case-insensitive search option. NOTE: as a consequence, indexes built with previous versions are not likely to work with this one. Also note that the keys for the hashref returned by Pod::Index::Builder->pod_index are now normalized to lowercase. - Added a 'keyword' property to Entry objects. - Eliminate duplicate search results. - Fixed some typos and documentation errors. 0.11 2005-08-01 - Added context to the POD entries. - Added subtopic support. - Changed file format: now instead of file:line, it uses podname\tline - The hashref returned by Pod::Index::Builder->pod_index now has Pod::Index::Entry as values. - Various bug and typo fixes. 0.10 2005-07-27 - First release Pod-Index-0.14/MANIFEST0100644000076400007640000000050110277757303013052 0ustar ivanivanChanges lib/Pod/Index.pm lib/Pod/Index/Builder.pm lib/Pod/Index/Entry.pm lib/Pod/Index/Extract.pm lib/Pod/Index/Search.pm Makefile.PL MANIFEST This list of files META.yml Module meta-data (added by MakeMaker) perldoc-k.cgi podindex README t/Builder.t t/nocase.t t/pod.t t/Search.t t/subtopics.t t/test.pod t/test.txt Pod-Index-0.14/lib/0040755000076400007640000000000010324315142012456 5ustar ivanivanPod-Index-0.14/lib/Pod/0040755000076400007640000000000010324315142013200 5ustar ivanivanPod-Index-0.14/lib/Pod/Index.pm0100644000076400007640000001146310324314517014614 0ustar ivanivanpackage Pod::Index; $VERSION = '0.14'; use strict; use warnings; 1; __END__ =head1 NAME Pod::Index - Index and search PODs using XE> entries. =head1 SYNOPSIS ### to create an index: use Pod::Index::Builder; my $p = Pod::Index::Builder->new; for my $file (@ARGV) { $p->parse_from_file($file); } $p->print_index("index.txt"); ### to search for a keyword in the index: use Pod::Index::Search; my $q = Pod::Index::Search->new( filename => 'index.txt', ); my @results = $q->search('getprotobyname'); for my $r (@results) { printf "%s\t%s\n", $r->podname, $r->line; print $r->pod; } =head1 DESCRIPTION The Pod-Index distribution includes various modules for indexing and searching POD that is appropriately marked with XE> POD codes. C, as a module, does nothing. Everything is done by L, L, and other helper modules. This document discusses some of the general issues with POD indexing; specifically, the recommended conventions for the use of XE> codes. =head1 BACKGROUND The little-known (or at least little-used) XE> formatting code is described in L: "X" -- an index entry This is ignored by most formatters, but some may use it for build- ing indexes. It always renders as empty-string. Example: "X" =head1 CONVENTIONS FOR THE USE OF XE> CODES =head2 Placement of the XE> entries First, a definition. By "scope", I mean the part of the document that is deemed relevant to an index entry, and that may be extracted and shown in isolation by a processing or display tool. For example, perldoc -f considers the scope of a function to end at the beginning of the next =item, or at the end of the enclosing =over. The XE> entries should be added at the end of a command or textblock paragraph (verbatim paragraphs are excluded). The scope of the index entry starts at the beginning of the paragraph to which it was attached; the end of the scope depends on the command type: 1) if the XE> is at the end of a textblock, the scope is that paragraph and zero or more verbatim paragraphs immediately following it. 2) if the XE> is at the end of a command paragraph, it depends on the type of command: =over =item =head1, head2, etc. The scope ends right before the next heading with equal or higher level. That is, a =head1 ends at the next =head1, and a =head2 ends at the next =head2 or =head1. =item =item The scope ends right before the next =item, or the =back that terminates the containing list. Note: "empty" items are not counted for terminating scopes, to allow for cases where multiple =items head a block of text. For example, =item function X X =item otherfunction C and C do the same thing, even if they have different names... =item lemonade Here the scope of the XEfunction> and XEotherfunction> entries starts with "=item function", and ends right before "=item lemonade". =back 3) other command paragraphs, such as =back, =over, =begin, =end, and =for should not be used for attaching XE> entries. =head2 Content of the XE> entry. =over =item * It should contain plain text without further formatting codes (with the possible exception of EE>). =item * It should be in lowercase, unless caps are required due to case-sensitivity or correctness. =item * Non-word characters are allowed, so one can list things like operators and special variables. =item * Use of synonyms is encouraged, to make things easier to find. =item * To be consistent, words should be normalized to the singular whenever possible. For example, use XEoperator> instead of XEoperators>. =item * The use of a comma in an index entry has a special meaning: it separates levels of hierarchy (or namespaces), as a way of classifying entries in more specific ways. For example, "XEoperator, logical>", or "XEoperator, logical, xor>". This information may be used by processing programs to arrange the entries, or for listing results when a user searches for a namespace that contains several entries. =item * There's no limitation as to the number of times that a given entry can appear in a document or collection of documents. That is, it is not an error to have XEwhatever> appear twice in the same file. =back =head1 VERSION 0.14 =head1 SEE ALSO L, L, L, L =head1 AUTHOR Ivan Tubert-Brohman Eitub@cpan.orgE =head1 COPYRIGHT Copyright (c) 2005 Ivan Tubert-Brohman. All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut Pod-Index-0.14/lib/Pod/Index/0040755000076400007640000000000010324315142014247 5ustar ivanivanPod-Index-0.14/lib/Pod/Index/Builder.pm0100644000076400007640000001162410324314521016174 0ustar ivanivanpackage Pod::Index::Builder; use 5.008; $VERSION = '0.14'; use strict; use warnings; use base qw(Pod::Parser); use Pod::Index::Entry; use File::Spec; ####### Pod::Parser overriden methods sub begin_input { my ($self) = @_; $self->{pi_breadcrumbs} = []; } sub verbatim { #my ($self, $text, $line_num, $pod_para) = @_; # do nothing } sub textblock { my ($self, $text, $line_num, $pod_para) = @_; $self->{pi_pos} = [$pod_para->file_line, [ @{$self->{pi_breadcrumbs}} ] ]; $self->interpolate($text, $line_num); return; } sub command { my ($self, $cmd, $text, $line_num, $pod_para) = @_; my $breadcrumbs = $self->{pi_breadcrumbs}; if ($cmd =~ /head(\d)/) { my $level = $1; splice @$breadcrumbs, $level-1 if @$breadcrumbs >= $level; $self->{pi_pos} = [$pod_para->file_line, [ @$breadcrumbs ] ]; my $s = $self->interpolate($text, $line_num); $self->{pi_breadcrumbs}[$level - 1] = $s; } else { $self->{pi_pos} = [$pod_para->file_line, [ @$breadcrumbs ] ]; $self->interpolate($text, $line_num); } return; } sub interior_sequence { my ($self, $seq_command, $seq_argument, $seq_obj) = @_ ; if ($seq_command eq 'X') { $self->add_entry($seq_argument); return ''; } return $seq_argument; } ###### new methods sub pod_index { shift->{pi_pod_index} } sub add_entry { my ($self, $keyword) = @_; my ($filename, $line, $breadcrumbs) = @{$self->{pi_pos}}; my $podname = $self->path2package($filename); my $context = $breadcrumbs->[-1]; $context = '' unless defined $context; $context =~ s/\n.*//s; my $entry = Pod::Index::Entry->new( keyword => $keyword, filename => $filename, podname => $podname, line => $line, context => $context, ); push @{$self->{pi_pod_index}{lc $keyword}}, $entry; } sub path2package { my ($self, $pathname) = @_; my $relname = File::Spec->abs2rel($pathname, $self->{pi_base}); my ($volume, $dirstring, $file) = File::Spec->splitpath($relname); my @dirs = File::Spec->splitdir($dirstring); pop @dirs if ($dirs[-1] eq ''); # in case there was a trailing slash $file =~ s/\.\w+$//; my $package = join('::',@dirs,$file); return $package; } sub print_index { my ($self, $f) = @_; # figure out filehandle my $fh; if ($f and !ref $f) { open $fh, ">", $f or die "couldn't open $f: $!\n"; } elsif ($f) { $fh = $f; } else { $fh ||= *STDOUT; } # print out the index my $idx = $self->pod_index; for my $key ( sort { $a cmp $b or $idx->{$a}{keyword} cmp $idx->{$b}{keyword} } keys %$idx ) { for my $entry ( sort { $a->{podname} cmp $b->{podname} or $a->{line} <=> $b->{line} } @{$idx->{$key}} ) { print $fh join("\t", @$entry{qw(keyword podname line context)}), "\n"; } } } 1; __END__ =head1 NAME Pod::Index::Builder - Build a pod index =head1 SYNOPSIS use Pod::Index::Builder; my $p = Pod::Index::Builder->new( pi_base => $base_path, ); for my $file (@ARGV) { $p->parse_from_file($file); } $p->print_index; =head1 DESCRIPTION This is a subclass of L that reads POD and outputs nothing. However, it saves the position of every XE> entry it sees. The index can be retrieved as a hashref, or printed in a format that is understandable by L. =head1 METHODS =over =item new The constructor, inherited from L. The only optional argument that X cares about is C. If given, it is used as a base when converting pathnames to package names. For example, if C = "lib", the filename F will turn into C, instead of the undesirable C. =item pod_index Retrieves the index as a hashref. The hash keys are the keywords contained in the XE> tags, I; the values are array references of L objects. =item print_index $parser->print_index($fh); $parser->print_index($filename); $parser->print_index(); Prints the index to the given output filename or filehandle (or STDOUT by default). The format is tab-delimited, with the following columns: 1) keyword 2) podname 3) line number 4) context (title of section containing this entry) The index is sorted by keyword in a case-insensitive way. =back =head1 VERSION 0.14 =head1 SEE ALSO L, L, L, L, L =head1 AUTHOR Ivan Tubert-Brohman Eitub@cpan.orgE =head1 COPYRIGHT Copyright (c) 2005 Ivan Tubert-Brohman. All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut Pod-Index-0.14/lib/Pod/Index/Entry.pm0100644000076400007640000000547710324314524015723 0ustar ivanivanpackage Pod::Index::Entry; use 5.008; $VERSION = '0.14'; use strict; use warnings; use Pod::Index::Extract; sub new { my ($class, %args) = @_; my $self = bless { %args, }, $class; return $self; } sub podname { shift->{podname} } sub line { shift->{line} } sub filename { shift->{filename} } sub context { shift->{context} } sub keyword { shift->{keyword} } sub pod { my ($self) = @_; return $self->{pod} if defined $self->{pod}; my $filename = $self->filename; open my $in, "<", $filename or die "couldn't open $filename $!\n"; open my $out, ">", \(my $pod) or die "couldn't open output fh: $!\n"; my $parser = Pod::Index::Extract->new( ppi_entry => $self, ); <$in> for (1 .. $self->{line} - 1); # skip lines $parser->parse_from_filehandle($in, $out); return $self->{pod} = $pod; } 1; =head1 NAME Pod::Index::Entry - Represents Pod search result =head1 SYNOPSIS use Pod::Index::Entry; my $entry = Pod::Index::Entry->new( keyword => 'constructors', podname => 'perlobj', line => 42, filename => '/usr/lib/perl5/5.8.7/pod/perlobj.pod', context => 'Using POD', ); # trivial accessors my $podname = $entry->podname; my $filename = $entry->filename; my $line = $entry->line; my $context = $entry->context; my $keyword = $entry->keyword; # extract the POD for this entry my $pod = $entry->pod; =head1 DESCRIPTION This class represents a POD index entry. An entry is defined by the podname/filename, line number, and context. The entry object also has the ability to extract the POD "scope" from the filename. =head1 METHODS =over =item new my $q = Pod::Index::Entry->new(%args); Create a new search object. Possible arguments are: =over =item podname The name of the pod, such as X. =item filename The filename for the pod, such as F. =item line The line number where the scope of this entry begins. =item context The title of the section that contains this entry. =back =item podname =item filename =item line =item context These are just simple accessors that return the value of these properties, as given to the constructor. =item pod Extracts the POD for the scope of the entry from $self->filename, beginning at $self->line. For a definition of I, see L. The POD extraction is delegated to the L module. =back =head1 VERSION 0.14 =head1 SEE ALSO L, L, L =head1 AUTHOR Ivan Tubert-Brohman Eitub@cpan.orgE =head1 COPYRIGHT Copyright (c) 2005 Ivan Tubert-Brohman. All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut Pod-Index-0.14/lib/Pod/Index/Search.pm0100644000076400007640000001207710324314526016023 0ustar ivanivanpackage Pod::Index::Search; use 5.008; $VERSION = '0.14'; use strict; use warnings; use Search::Dict (); use Pod::Index::Entry; use Carp qw(croak); use File::Spec::Functions; sub new { my ($class, %args) = @_; my $self = bless { %args, }, $class; if ($self->{filename}) { open my $fh, "<", $self->{filename} or die "couldn't open $self->{filename}: $!\n"; $self->{fh} = $fh; } unless ($self->{fh}) { require perlindex; $self->{fh} = *perlindex::DATA; } $self->{start} = tell $self->{fh}; $self->{filemap} ||= sub { my ($podname) = @_; my @path_elems = split /::/, $podname; for my $inc (@INC) { my $file = catfile($inc, @path_elems); return "$file.pod" if -e "$file.pod"; return "$file.pm" if -e "$file.pm"; } return undef; }; return $self; } sub subtopics { my ($self, $keyword, %args) = @_; croak "need a keyword " unless defined $keyword; my $fh = $self->{fh}; $self->look($keyword); my $i = $self->{nocase} ? 'i' : ''; my $re_filter = qr/^\Q$keyword\E/i; my $re_select = $args{deep} ? qr/^((?$i)\Q$keyword\E,.*)/ : qr/^((?$i)\Q$keyword\E,[^,]*)/; local $_; my @ret; my %seen; while (<$fh>) { my ($topic) = split /\t/; last unless $topic =~ $re_filter; if ($topic =~ $re_select and not $seen{$1}++) { push @ret, $1; } } return @ret; } # hack to make 'look' skip everything before __DATA__: # everything before start always compares negatively sub look { my ($self, $keyword) = @_; my $fh = $self->{fh}; my $start = $self->{start}; # the search is case-insensitive (fold => 1), but the results are filtered # later if the user wanted it case-sensitive Search::Dict::look($fh, $keyword, { comp => sub { tell($fh) <= $start ? -1 : $_[0] cmp $_[1]; }, fold => 1, }); } sub search { my ($self, $keyword) = @_; croak "need a keyword " unless defined $keyword; my $fh = $self->{fh}; $self->look($keyword); local $_; my @ret; my $keyword_lc = lc $keyword; my %seen; while (<$fh>) { chomp; my ($entry, $podname, $line, $context) = split /\t/; last unless lc $entry eq $keyword_lc; next if !$self->{nocase} and $entry ne $keyword; next if $seen{"$podname\t$line"}++; push @ret, Pod::Index::Entry->new( keyword => $entry, podname => $podname, line => $line, filename => $self->{filemap}($podname), context => $context, ); } return @ret; } 1; __END__ =head1 NAME Pod::Index::Search - Search for keywords in an indexed pod =head1 SYNOPSIS use Pod::Index::Search; my $q = Pod::Index::Search->new; my @results = $q->search('getprotobyname'); for my $r (@results) { printf "%s\t%s\n", $r->podname, $r->line; print $r->pod; } my @subtopics = $q->subtopics('operator'); =head1 DESCRIPTION This module searches an index created by L. Search results are returned as L objects. It is also possible to search for subtopics for a keyword. For example, a search for "operator" might return things like operator, conditional operator, filetest operator, logical operator, precedence operator, relational The subtopics returned are simple strings. =head1 METHODS =over =item new my $q = Pod::Index::Search->new(%args); Create a new search object. Possible arguments are: =over =item C The filehandle of the index to use. If omitted, C is used. =item C The filename of the index to use. Note that you can specify either C or filename, but not both. =item C A subroutine reference that takes a podname and returns a filename. A simple example might be: sub { my $podname = shift; return "/usr/lib/perl5/5.8.7/pod/$podname.pod"; } The podname is in colon-delimited Perl package syntax. The default C returns the first file in @INC that seems to have the proper documentation (either a .pod or .pm file). =item C If true, the search will be case-insensitive. =back =item search($keyword) Do the actual search in the index. Returns a list of search results, as L objects. =item subtopics($keyword, %options) my @topics = $q->subtopics('operator'); my @topics = $q->subtopics('operator', deep => 1); Lists the subtopics for a given keyword. If C is given, it includes all subtopics; otherwise, only the first level of subtopics is included. =back =head1 VERSION 0.14 =head1 SEE ALSO L, L =head1 AUTHOR Ivan Tubert-Brohman Eitub@cpan.orgE =head1 COPYRIGHT Copyright (c) 2005 Ivan Tubert-Brohman. All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut Pod-Index-0.14/lib/Pod/Index/Extract.pm0100644000076400007640000000750210324314532016222 0ustar ivanivanpackage Pod::Index::Extract; use 5.008; $VERSION = '0.14'; use strict; use warnings; use base qw(Pod::Parser); sub begin_input { my ($self) = @_; $self->cutting(0); # force parser to notice that it's in POD mode } sub verbatim { my ($self, $text, $line_num, $pod_para) = @_; # verbatim should't have the X<> attached return $self->ppi_done unless $self->{ppi_anchor_type}; my $out_fh = $self->output_handle; print $out_fh $text; $self->{ppi_textblock_count}++; } sub textblock { my ($self, $text, $line_num, $pod_para) = @_; # should sanity check that the X<> is really here... #print "<<<$text>>>\n"; my $out_fh = $self->output_handle; unless ($self->{ppi_anchor_type}) { $self->{ppi_anchor_type} = 'textblock'; $self->ppi_start; } # only print the first paragraph if in textblock mode return $self->ppi_done if $self->{ppi_anchor_type} eq 'textblock' and $self->{ppi_textblock_count}; print $out_fh $text; $self->{ppi_textblock_count}++; } sub command { my ($self, $cmd, $text, $line_num, $pod_para) = @_; # should sanity check that the X<> is really here... my $out_fh = $self->output_handle; unless ($self->{ppi_anchor_type}) { $self->{ppi_anchor_type} = 'command'; $self->{ppi_command} = $cmd; $self->ppi_start; if ($cmd eq 'item') { print $out_fh "=over\n\n"; } } return $self->ppi_done unless $self->{ppi_anchor_type} eq 'command'; my $ppi_cmd = $self->{ppi_command}; return $self->ppi_done unless $ppi_cmd =~ /^(?:head|item)/; # XXX # check if we are out of scope if ($self->{ppi_textblock_count}) { if ($ppi_cmd =~ /^head(\d)/) { my $initial_level = $1; if ($cmd =~ /^head(\d)/) { my $current_level = $1; return $self->ppi_done if $current_level <= $initial_level; } } elsif ($ppi_cmd =~ /^item/) { if ($cmd =~ /item|back/ and !$self->{ppi_depth}) { return $self->ppi_done; } elsif ($cmd eq 'over') { $self->{ppi_depth}++; } elsif ($cmd eq 'back') { $self->{ppi_depth}--; } } else { die "shouldn't be here "; } } print $out_fh $pod_para->raw_text; } sub ppi_start { my ($self) = @_; } sub ppi_done { my ($self) = @_; my $out_fh = $self->output_handle; if ($self->{ppi_command} and $self->{ppi_command} eq 'item') { print $out_fh "=back\n\n"; } my $fh = $self->input_handle; seek $fh, 0, 2; # EOF } 1; __END__ =head1 NAME Pod::Index::Extract - Extracts a "pod scope" =head1 SYNOPSIS use Pod::Index::Extract; my $parser = Pod::Index::Extract->new; # [...] get $fh_in to the desired position $parser->parse_from_filehandle($fh_in, $fh_out); =head1 DESCRIPTION This module is a subclass of L. It outputs POD without any transformation; however, it only outputs the POD that is "in scope" as defined in L. To use this module, you first need to position a filehandle at the beginning of the desired scope, and then call C with that filehandle for input. It will just print the POD until it reaches the end of the scope, after which it will jump to the end of the file. If the scope starts with an C<=item>, it will wrap it with an C<=over> and a C<=back>, so it can be used as valid POD in isolation. =head1 VERSION 0.14 =head1 SEE ALSO L, L, L =head1 AUTHOR Ivan Tubert-Brohman Eitub@cpan.orgE =head1 COPYRIGHT Copyright (c) 2005 Ivan Tubert-Brohman. All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut Pod-Index-0.14/perldoc-k.cgi0100755000076400007640000000374210312133664014266 0ustar ivanivan#!/home/ivan/bin/perl use strict; use warnings; no warnings qw(uninitialized); use CGI (); use Template; use lib qw(pod-indexing-snapshot/lib pod-indexing-snapshot/); use Pod::Perldoc; my $cgi = CGI->new; print $cgi->header; my $keyword = $cgi->param('keyword'); my $nocase = $cgi->param('nocase'); my $pod; my $err; my $out; if (defined $keyword) { open my $fh_out, ">", \$out or die; open my $fh_err, ">", \$err or die; my $old_stdout = *STDOUT; *STDOUT = $fh_out; *STDERR = $fh_err; push @ARGV, qw(-MPod::Perldoc::ToHTML -T -k), $keyword; push @ARGV, '-i' if $nocase; eval { Pod::Perldoc->run() }; $err .= $@; ($pod) = $out =~ /(.*)<\/body>/s; *STDOUT = $old_stdout; } my $tt = Template->new; $tt->process(\*DATA, { pod => $pod, err => $err, keyword => $keyword, nocase => $nocase, script_name => $0, }) or die; __DATA__ perldoc -k demo

perldoc -k demo

Keyword to search:

[% IF keyword %]

Searched for `[% keyword | html %]'

[% END %] [% IF err %]
[% err %]
[% END %] [% IF pod %]
[% pod %]
[% END %] Pod-Index-0.14/t/0040755000076400007640000000000010324315142012153 5ustar ivanivanPod-Index-0.14/t/pod.t0100644000076400007640000000030210271755552013130 0ustar ivanivanuse strict; use Test::More; eval "use Test::Pod 1.00"; plan skip_all => "Test::Pod 1.00 required for testing POD" if $@; my @poddirs = qw( lib ); all_pod_files_ok( all_pod_files( @poddirs ) ); Pod-Index-0.14/t/Builder.t0100644000076400007640000000126410324312035013724 0ustar ivanivanuse strict; use warnings; use Test::More; use File::Spec::Functions; my ($volume, $dirstring, $file) = File::Spec->splitpath($0); my @dirs = File::Spec->splitdir($dirstring); pop @dirs while (@dirs and $dirs[-1] =~ /^(t|)$/); #plan 'no_plan'; plan tests => 3; use_ok("Pod::Index::Builder"); my $p = Pod::Index::Builder->new(pi_base => catdir(@dirs)); isa_ok($p, "Pod::Index::Builder"); $p->parse_from_file(catfile(@dirs, 't','test.pod')); open my $fh, ">", \(my $got) or die; $p->print_index($fh); open my $fh_exp, "<", catfile(@dirs, 't', 'test.txt') or die; my $expected = do { local $/; <$fh_exp> }; is($got, $expected, "index ok"); #use Data::Dumper; print Dumper $p->pod_index; Pod-Index-0.14/t/test.pod0100644000076400007640000000167310277753635013666 0ustar ivanivan=head1 NAME Pod::Index::example - this is a sample indexed file =head1 SYNOPSIS X blah blah blah =head1 DESCRIPTION This is the description. Let's describe some stuff. This is a random paragraph. X This is another paragraph, followed by a verbatim block or two: X this is an example this is another example =over =item hydrogen X X X X =item deuterium =item tritium These are the isotopes of element 1. Let's add some nested items: =over =item H20 water =item D2O heavy water =back =item helium X X X X X Helium is used for filling balloons. =back =head2 HEAD2 X X This is to see if the head2 block is selected correctly. for example, this paragraph should be included. =head1 SEE ALSO X X X Stuff =cut Pod-Index-0.14/t/nocase.t0100644000076400007640000000252010324313547013613 0ustar ivanivanuse strict; use warnings; use Test::More; # preamble to make it work portably regardless of where the test is run use File::Spec::Functions; my ($volume, $dirstring, $file) = File::Spec->splitpath($0); my @DIRS = File::Spec->splitdir($dirstring); pop @DIRS while (@DIRS and $DIRS[-1] =~ /^(t|)$/); unshift @INC, catdir(@DIRS); #plan 'no_plan'; plan tests => 9; use_ok('Pod::Index::Search'); my ($q, @results); ####### CASE-SENSITIVE ########## $q = Pod::Index::Search->new( filename => catfile(@DIRS, 't', 'test.txt'), ); @results = $q->search('tritium'); is( scalar @results, 1, 'tritium (case)'); @results = $q->search('Tritium'); is( scalar @results, 1, 'Tritium (case)'); @results = $q->subtopics('tritium'); is( scalar @results, 1, 'tritium subtopics (case)'); @results = $q->subtopics('Tritium'); is( scalar @results, 1, 'Tritium subtopics (case)'); ####### CASE-INSENSITIVE ########## $q = Pod::Index::Search->new( filename => catfile(@DIRS, 't', 'test.txt'), nocase => 1, ); @results = $q->search('tritium'); is( scalar @results, 2, 'tritium (nocase)'); @results = $q->search('Tritium'); is( scalar @results, 2, 'Tritium (nocase)'); @results = $q->subtopics('tritium'); is( scalar @results, 2, 'tritium subtopics (nocase)'); @results = $q->subtopics('Tritium'); is( scalar @results, 2, 'Tritium subtopics (nocase)'); Pod-Index-0.14/t/subtopics.t0100644000076400007640000000151510324313405014352 0ustar ivanivanuse strict; use warnings; use Test::More; # preamble to make it work portably regardless of where the test is run use File::Spec::Functions; my ($volume, $dirstring, $file) = File::Spec->splitpath($0); my @DIRS = File::Spec->splitdir($dirstring); pop @DIRS while (@DIRS and $DIRS[-1] =~ /^(t|)$/); unshift @INC, catdir(@DIRS); #plan 'no_plan'; plan tests => 4; use_ok('Pod::Index::Search'); my $q = Pod::Index::Search->new( filename => catfile(@DIRS, 't', 'test.txt'), ); isa_ok($q, 'Pod::Index::Search'); my @subtopics = $q->subtopics('balloon'); is_deeply( \@subtopics, ['balloon, floating', 'balloon, gas-filled', 'balloon, light'], 'topics' ); @subtopics = $q->subtopics('balloon', deep => 1); is_deeply( \@subtopics, ['balloon, floating', 'balloon, gas-filled, helium', 'balloon, light'], 'topics' ); Pod-Index-0.14/t/test.txt0100644000076400007640000000102610277755234013710 0ustar ivanivanballoon t::test 61 DESCRIPTION balloon, floating t::test 50 DESCRIPTION balloon, gas-filled, helium t::test 50 DESCRIPTION balloon, light t::test 50 DESCRIPTION deuterium t::test 26 DESCRIPTION head2 t::test 61 DESCRIPTION helium t::test 50 DESCRIPTION hydrogen t::test 26 DESCRIPTION protium t::test 26 DESCRIPTION random t::test 14 DESCRIPTION random t::test 50 DESCRIPTION synopsis t::test 5 tritium t::test 26 DESCRIPTION Tritium t::test 71 tritium, clocks t::test 71 Tritium, leaks t::test 71 verbatim t::test 17 DESCRIPTION Pod-Index-0.14/t/Search.t0100644000076400007640000000500410324313333013541 0ustar ivanivanuse strict; use warnings; use Test::More; # preamble to make it work portably regardless of where the test is run use File::Spec::Functions; my ($volume, $dirstring, $file) = File::Spec->splitpath($0); my @DIRS = File::Spec->splitdir($dirstring); pop @DIRS while (@DIRS and $DIRS[-1] =~ /^(t|)$/); unshift @INC, catdir(@DIRS); #plan 'no_plan'; plan tests => 27; use_ok('Pod::Index::Search'); my $q = Pod::Index::Search->new( filename => catfile(@DIRS, qw(t test.txt)), ); isa_ok($q, 'Pod::Index::Search'); my @results = $q->search('random'); is (scalar @results, 2, 'got 2 results for random'); push @results, $q->search('deuterium'); push @results, $q->search('head2'); push @results, $q->search('verbatim'); push @results, $q->search('synopsis'); my @expected = expected(); for my $res (@results) { isa_ok($res, 'Pod::Index::Entry'); my $exp = shift @expected; is($res->line, $exp->{line}, "line=$exp->{line}"); is($res->filename, $exp->{podname}, "podname=$exp->{podname}"); is($res->pod, $exp->{pod}, "pod ok"); } ################## EXPECTED ################ sub expected { my $podfile = catfile(@DIRS, 't', 'test.pod'); return ( ############################### { line => 14, podname => $podfile, pod => < POD ############################### { line => 50, podname => $podfile, pod => < X X X X Helium is used for filling balloons. =back POD ############################### { line => 26, podname => $podfile, pod => < X X X =item deuterium =item tritium These are the isotopes of element 1. Let's add some nested items: =over =item H20 water =item D2O heavy water =back =back POD ############################### { line => 61, podname => $podfile, pod => < X This is to see if the head2 block is selected correctly. for example, this paragraph should be included. POD ############################### { line => 17, podname => $podfile, pod => < this is an example this is another example POD ############################### { line => 5, podname => $podfile, pod => < blah blah blah POD ); } Pod-Index-0.14/podindex0100755000076400007640000000442110273717705013464 0ustar ivanivan#!/usr/bin/perl use strict; use warnings; use Pod::Index; use Pod::Index::Builder; use Getopt::Long; my ($package, $help, $version); my $ret = GetOptions( 'package=s' => \$package, 'version' => \$version, 'help' => \$help, ); if ($version) { print "Pod::Index version ", Pod::Index->VERSION, "\n"; exit; } elsif (!$ret or $help or !@ARGV) { print usage(); exit; } my $p = Pod::Index::Builder->new; my @files = @ARGV; if ($^O eq 'MSWin32') { # do our own globbing under Windows @files = map glob, @files; } for my $file (@files) { $p->parse_from_file($file); } if ($package) { print "package $package;\n1;\n__DATA__\n"; } $p->print_index; sub usage { <... Reads pod(s) and prints an index to stdout. Options: --package=PACKAGE precede the index by a perl package declaration --help this help --version print version number USAGE } __END__ =head1 NAME podindex - build index from pods =head1 SYNOPSYS podindex [options] ... Reads pod(s) and prints an index to stdout. Options: --package=PACKAGE precede the index by a perl package declaration --help this help --version print version number =head1 DESCRIPTION This is a simple wrapper script around L. It parses the POD files given as arguments, finds all XE> entries, generates an index and prints it to standard output. =head1 OPTIONS =over =item package If given, it will place the index in the __DATA__ section of a perl package. For example, podindex --package=perlindex perlop.pod outputs something like this: package perlindex; 1; __DATA__ ! perlsyn 116 DESCRIPTION ! perlop 207 Symbolic Unary Operators != perlop 436 Equality Operators !~ perlop 242 DESCRIPTION This is used so that an index can be placed in @INC and found easily (See L). =back =head1 SEE ALSO L, L, L =head1 AUTHOR Ivan Tubert-Brohman Eitub@cpan.orgE =head1 COPYRIGHT Copyright (c) 2005 Ivan Tubert-Brohman. All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut Pod-Index-0.14/META.yml0100644000076400007640000000057010324315142013160 0ustar ivanivan# http://module-build.sourceforge.net/META-spec.html #XXXXXXX This is a prototype!!! It will change in the future!!! XXXXX# name: Pod-Index version: 0.14 version_from: lib/Pod/Index.pm installdirs: site requires: Pod::Parser: 1 Search::Dict: 0 distribution_type: module generated_by: ExtUtils::MakeMaker version 6.17 Pod-Index-0.14/README0100644000076400007640000000103410324314432012564 0ustar ivanivanPod::Index version 0.14 ======================= The Pod-Index distributions includes various modules for indexing and searching POD that is marked appropriately with X<> POD codes. INSTALLATION perl Makefile.PL make make test make install DEPENDENCIES perl-5.8.0+ Search::Dict => 0, Pod::Parser => 1, COPYRIGHT AND LICENSE Copyright (C) 2005 Ivan Tubert-Brohman This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. Pod-Index-0.14/Makefile.PL0100644000076400007640000000045410271763633013677 0ustar ivanivanuse 5.008; use ExtUtils::MakeMaker; WriteMakefile( 'NAME' => 'Pod::Index', 'VERSION_FROM' => 'lib/Pod/Index.pm', 'EXE_FILES' => [qw( podindex )], 'PREREQ_PM' => { Search::Dict => 0, Pod::Parser => 1, #Test::Pod => 1.20, # for testing }, );