Front page | perl.perl5.porters |
Postings from September 2000
New Tools for Old
Thread Previous
|
Thread Next
From:
Tom Christiansen
Date:
September 5, 2000 08:34
Subject:
New Tools for Old
Message ID:
25767.968168041@chthon
I've been working on the perldoc rewrite, as documented in the new
Camel's intro chapter. If you've read it, that description provides
just the vaguest sketch of the real story. Here is a more fleshed
out form of that so you see more what's happening.
Things are starting to come together nicely, and I think I'll be
able to give you stuff to play with and test out soon enough. Here's
my general working description. This all pretty much works save
for messy edges I intend to smooth out in the near future.
This all fits together, but you may need to read the whole thing
if you want to see the underlying componentry. That is, how low-level
the access that you can get actually is.
Note that these are all the same
perlman (normal mode)
podgrep (same, but non Perl-installation aware mode)
perldoc (for legacy operation; may have a few differing
CLI flags, but these are deprecated.)
But see below. In reality, perlman is just something of a front-end
for a bunch of little semi-related programs and/or function calls.
Passing a full path to perlman is the same as calling podgrep,
although with podgrep the pager is not autocalled.
===================== NORMAL USAGE =================
$ perlman
Prints out a short usage message.
$ perlsub
$ perlman perlsub
Shows you the perlsub manpage, formatted and paged. (The program
will use its own name as the name of the manpage to display if
that name is not from a set of expected installation names.)
If the pre-converted version is available in Config's $man1dir,
the system man program will be invoked upon it; this confers
all the speed and caching (and security?) of your native man
system, because in fact it really uses your system, without
having to know too much about it. This in practice speeds up
simple displays dramaticaly.
If there is no converted version but if you appear to be on a
manly system, the page will be manually sent through pod2man
and nroff and your pager. If you are unmanly, you get it run
through pod2text and thence to your pager once again.
If you want to do things the slow way, you can ignore the nroff
translations using the "-t" flag, which means "pod2text" only.
These are all the same:
$ perlsub -t
$ perlman -t perlsub
$ pod2text `podpath perlsub` | $PAGER
$ pod2text /usr/local/lib/perl5/5.6.0/pod/perlsub.pod | $PAGER
==================== SEARCH MODES =======================
[ section, paragraph, line; should this be a --mode=line style
option? ]
Search modes are one of the following:
no flag => section search
-p flag => paragraph search
-a flag => line search
-C flag => code search (verbatim/indented podagraphs)
-L flag => outline search (pod directives)
These are all the same:
$ perlsub local
$ perlman perlsub local
$ podgrep `podpath perlsub` local | $PAGER
$ podgrep /usr/local/lib/perl5/5.6.0/pod/perlsub.pod local | $PAGER
This runs section-search mode against the raw perlsub podpage,
where we're looking for any pod sections whose *headers* match
the pattern "local". By default, this text is sent through
pod2text and, if stdout isatty, your pager.
What's a section? A section is defined to be an =foo pod
directive plus any undirected text following that up until
another pod directive of the same or higher level. For example,
a =head1 would include subordinate =head2s and =items, but be
terminated by another =head1. An =item is lower than any =headN,
and is terminated by any =headN, or any =item that did not occur
immediately following the matched one without intervening text;
this latter rule allows a paragraph with multiple, consecutive
=item tags to be matched, such as you find in perlfunc and
perlvar. That way you can say things like
$ perlfunc split
$ perlvar OFS
$ perldiag 'assigned to typeglob'
To get each of those =item entries.
$ perldata -p typeglob
This runs paragraph-search mode, displaying any paragraph that
matches "typeglob". Pod directive paragraphs matching the
pattern are not immediately catted out. The paragraphs are by
default tagged with the paragraph number from the pod source,
and, if multiple files are possible (see Metapages below), the
manpage name itself. These paragraphs are sent through your
pager (and pod2text?). Because paragraphs break across line
boundaries, in paragraph mode, all whitespace chunks are converted
into \s+ and the (?ms) flags are added to control ^, $, and .
$ perlmod -a typeglob
The -a flag runs in line-search mode, showing all lines matching
the pattern "typeglob". Lines are tagged with the number from
their source, and, with multiple files, the name of the file.
Your pager will be used for output, but not pod2text, as this
is line-based.
$ perldata -C code
$ perldata -Ca code
The -C flag runs in code-search mode, either on paragraphs (by
default, or with -p) or lines (with -a). Only verbatim pod
paragraphs are listed, usually code. By default, -p is assumed
if -C is used and -a is not.
$ perlxs -L Keyword
$ perlman -L perlxs Keyword
The -L flag (same as the ol(1) program below) will search only in
the outline. It's essentially the same as
$ ol perlxs | grep Keyword
===================== CONJUNCTIVE SEARCHES ======================
If you ask for more than one search string, these are by default
ANDed together. The -o flag makes them ORed together. For example:
$ perldata -pi typeglob variable
Prints only those paragraphs that case-insensitively contain both
"typeglob" AND "variable". With the -o flag, you get those
with either of them.
$ perldata -opi typeglob variable
GREP OPTIONS:
Definitely:
-i case-insensitive using (?i)
-w whole words only using \bPAT\b, presuming P and T are
word-chars.
-l list filenames matching, but not matches
Maybe: (but these tend to conflict)
-e EXPR for patterns beginning with -?
-c just show count of matches
-o always show filename (conflicts with -o above)
-h hide filenames
-n show recnos (but this is the default!)
-x exact matches only, so nothing else on line; eg,
perlsub -x BUGS to find just the BUGS section,
not any section with "BUGS" in the name.
For example
$ perldata -ai typeglob
This searches perldata for any lines (the -a flag) that match
"typeglob" case-insensitively (the -i flag).
=============== MULTIPLE PAGES AND METAPAGES ============
You can search multiple pages at once explicitly using a comma
separated pagelist:
$ perlman -i perlsub,perldata variables
That does a case-insensitive section-search against those
two manpages.
or by a "metapage" specification. For example, the "perlfaq" metapage
is really all the stanard perlfaq? manpages.
$ perlfaq -w round
is the same as
$ perlman -w perlfaq1,perlfaq2,perlfaq3,perlfaq4,perlfaq5,perlfaq6,perlfaq7,perlfaq8,perlfaq9 round
But much easier to type.
Some metapages also set or clear specific flags, usually change the
default search mode (which is section search) into something else.
Metapage Meaning
perlhelp All standard Perl manpages, with -a (line mode).
perlfaq All perlfaq? manpages.
perltoc All standard manpages, with -L (outline mode).
stdmods All CORE module manpages, with -a flag.
modpods All module manpages, with -a flag.
sitemods All non-CORE (site) module manpages, with -a flag.
These can be used with non-searches also. If no search is provided
with a metabase, the -l is assumed to list out what files they are
consulting, as in:
$ sitepods
(Lists all the modules in your sitelib directories)
The module-related metapages all have to run a find (well, its perl equivalent)
on the relevant directories. There is no central database, nor is it all
in one place.
+--------------------------------------------------------------------------+
| =============== HOOKS FROM perlman INTO OTHER PROGRAMS ================= |
+--------------------------------------------------------------------------+
+-------------------------+
| podgrep - grep the pods |
+-------------------------+
This is a regular search (pod-section search as described below
be default, but with the other search modes enabled by flags.)
$ podgrep `podpath manpage` pattern
$ podgrep /full/path pattern
$ perlman manpage pattern
$ manpage pattern
+----------------------------------+
| docpath - show paths to docpages |
+----------------------------------+
The "docpath" program can be invoked as "perlman -l" if no search
is given. The "podpath" program, which doesn't include manpages,
is the same as "perlman -lt", where the -t flag makes it only think
about pod2textual bits.
On manpages:
$ docpath perlfunc
$ perlfunc -l
$ perlman -l perlfunc
/usr/local/man/man1/perlfunc.1
/usr/local/lib/perl5/5.6.0/pod/perlfunc.pod
$ podpath perlfunc
$ perlfunc -lt
$ perlman -lt perlfunc
/usr/local/lib/perl5/5.6.0/pod/perlfunc.pod
On modules:
$ docpath LWP
$ perlman -l LWP
/usr/local/man/man3/LWP.3
/usr/local/lib/perl5/site_perl/5.6.0/LWP.pm
/usr/local/lib/perl5/site_perl/5.00554/LWP.pm
On programs:
$ docpath perlbug
$ perlman -l perlbug
/usr/local/man/man1/perlbug.1
/usr/local/bin/perlbug
/usr/bin/perlbug
Alternative invocations work as follows (this is really all the
same program). These are also all available as functions from the
PM::Tools::podpath module. If called as functions, then all paths
are returned in list context, but just the first found in scalar
context, which short-circuits the first. The program versions show
all paths; see pmpath(1) below for more details.
The docpath program means pod2manpath + podpath (that is, paths
to the manpages plus the podpages)
The podpath program means stdpodpath + pmpodpath + progpodpath
(that is, just podpages)
use PM::Tools qw/podpath/; # imports podpath only
use PM::Tools::podpath; # imports podpath only
use PM::Tools::podpath /:ALL/; # imports all podpath tools
stdpodpath("perlfunc") => /usr/local/perl/lib/pod/perlfunc.pod
pmpodpath("CGI") => /usr/local/perl/lib/CGI.pm
pmpodpath("POSIX") => /usr/local/lib/perl5/5.6.0/OpenBSD.i386-openbsd/POSIX.pod
progpodpath("perlbug") => /usr/local/perl/bin/perlbug
pod2manpath("perlfunc") => /usr/local/man/man1/perlfunc.1
pod2manpath("CGI") => /usr/local/perl/man/man3/CGI.3
+------------------------------------+
| pmpath - find path to perl modules |
+------------------------------------+
If you just want the path to the module, not its documentation,
use "pmpath". The podpath functions/programs will prefer a ".pod"
over a ".pm", and they will open up programs to search for pods.
This only cares about modules.
As the pmpath(1) program
$ pmpath POSIX
/usr/local/lib/perl5/5.6.0/OpenBSD.i386-openbsd/POSIX.pm
$ pmpath IO::Socket
/usr/local/lib/perl5/5.6.0/OpenBSD.i386-openbsd/IO/Socket.pm
$ pmpath LWP
/usr/local/lib/perl5/site_perl/5.6.0/LWP.pm
/usr/local/lib/perl5/site_perl/5.00554/LWP.pm
$ pmpath CGI LWP
CGI: /usr/local/lib/perl5/5.6.0/CGI.pm
LWP: /usr/local/lib/perl5/site_perl/5.6.0/LWP.pm /usr/local/lib/perl5/site_perl/5.00554/LWP.
pm
$ pmpath -I/some/dir MyMod
/some/Dir/MyMod.pm
Or, as a module; first load module:
use PM::Tools qw(pmpath);
use PM::Tools::pmpath; # this form imports pmpath
Then in scalar context:
my $path = pmpath("CGI");
Or in list context:
my @paths = pmpath("LWP");
+--------------------------------+
| catpod - cat out just the pods |
+--------------------------------+
This program produces just the unformatted pods, but not the
non-pod which will be filtered out, from a file. If an absolute
path is given, that will be the literal filename. Otherwise,
a podpath() search will be run to find the real path.
Thus,
$ catpod CGI
is really
$ catpod `podpath CGI`
is really
$ catpod /usr/local/lib/perl5/5.6.0/CGI.pm
And, since this is the "perlman -u" unformatted flag, the same as:
$ perlman -u CGI
+--------------------------+
| ol - display pod outline |
+--------------------------+
(Should this be called olpod or podol instead?)
These are all (presumably) equivalent:
$ ol /usr/local/lib/perl5/5.6.0/pod/perlsub.pod
$ ol `podpath perlsub`
$ ol perlsub
$ perlsub -O
$ perlman -O perlsub
The "ol" program prints the pod outline for the given file.
If the file is not absolute, podpath() will be used to find
it, as shown above.
$ ol -2 perlsub
You may specify a max level to display, so -1 would be only
=head1, -2 would be no lower than =head2, etc. =items are
considered to be of the ninth level.
The ol program can also be invoked as "perlman -L" or
eg "perlman -L2":
$ perlsub -L
$ perlman -L perlsub
$ perlsub -L2
$ perlman -L2 perlsub
Note that if you provide a search in conjunction with -L, you are
in "outline search" mode described above.
+------------------------------------------+
| pmcat - cat out complete module contents |
+------------------------------------------+
The pmcat locates the path to the named module and cats out the
complete contents (through your pager, probably, though). This is
different from catpod in that it doesn't select only pod, or in
fact, prefer pod if both .pod and .pm versions are available, as
with POSIX. The -U flag (for *really* unformatted) to perlman does
the same thing.
$ pmcat CGI
$ pmcat `pmpath CGI`
$ $PAGER /usr/local/lib/perl5/5.6.0/CGI.pm
$ perlman -U /usr/local/lib/perl5/5.6.0/CGI.pm
+-------------------------+
| other podpath funcprogs |
+-------------------------+
The PM::Tools::podpath module also supports the following
simple functions, which may be called as programs, too.
$ podlibdir
/usr/local/lib/perl5/5.6.0/pod
$ mandirs
/usr/local/man/man1
/usr/local/man/man3
$ pmanpath
/usr/local/man
========================================================
What about apropos and whatis (that is, perlman -k or perlman -f)?
Those are either easy or hard. If there's a whatis database in the
perl mandirs, then you just call native man. If not, it's rough,
and you really would need to run pretty slowly to do a manual apropos
on the pods. I suppose that "perlman -k foo" could be "perlhelp
-x NAME foo" or some such if you don't have a podful makewhatis to
build and install a podtree-specific database. But if you did,
then you should think hard about what else the database should hold.
Thread Previous
|
Thread Next