Pod::Compiler - compile POD into an object tree
This package, based on Pod::Parser, compiles a given POD document into an object tree (based on Tree::DAG_Node). It prints errors and warnings about the POD it reads. The result can be used to conveniently convert the POD into any other format.
The resulting objects have a variety of methods to ease the subsequent conversion.
This package is object-oriented, which means that you can quite easily build a derived package and override some methods in case the given behaviour does not exactly suit your needs.
The following functions can be imported and called from a script, e.g. like this:
use Pod::Compiler qw(pod_compile); my $root = pod_compile('myfile.pod');
Compile the given $file using some %options and return the root of the object tree representing the POD in $file. The return value is either undef if some fatal error occured or an object of type Pod::root. See below for methods applicable to this class and for the options.
The special option
-compiler => 'class' lets you specify an alternate (derived) compiler class rather than Pod::Compiler.
The following section describes the OO interface of Pod::Compiler.
Set up a new compiler object. Options (see below) can be passed as a hash, e.g.
$c = Pod::Compiler->new( -warnings => 0 ); # don't be silly
Pod::Compiler inherits from Pod::Parser. See Pod::Parser for additional methods.
Initalize, set defaults. The following options are set to the given defaults unless they have been defined at object creation:
-errors => 1
Print POD syntax errors (using messagehandler) if option value is true.
-warnings => 1
Print POD syntax warnings (using messagehandler) if option value is true.
-idlength => 20
Pod::Compiler creates a unique node id for each
X<>, consisting only of
\w characters. The option value specifies how many characters from the original node text are used for the node id by the built-in make_unique_node_id method. See below for more information.
-ignore => 'BCFS'
This option specifies which interior sequences (e.g.
B<...>) are ignored when nested in itself, e.g.
B<...B<...>...>. The inner
B is simply discarded if the corresponding letter appears in the option value string.
-unwrap => 'I'
This option specifies which interior sequences (e.g.
I<...>) are unwrapped when nested in itself, e.g.
I<...I<...>...> is turned into
I<...>...I<...>. While some destination formats may handle such nestings appropriately, other might have problems. This option solves it right away. By the way, from a typographical point of view, italics are often used for emphasis. In order to emphasize something within an emphasis, one reverts to the non-italic font.
name => ''
This is used to store the (logical) name of the POD, i.e. for example the module name as it appears in
use module;. It is used internally only to detect internal links pointing to the explicit page name. Example: You compile the file Compiler.pm which contains the package
Pod::Compiler. You set name to
Pod::Compiler (there is no safe automatic way to do so). Thus if the file includes a link like
L<Pod::Compiler/messagehandler> it is recognized as an internal link and it is checked whether it resolves. Of course you should have written the link as
-perlcode => 0
If set to true, the compiler will also return the Perl code blocks as objects Pod::perlcode, rather than only the POD embedded in the file. This is used e.g. by podlint.
Get or set the compile option (see above) given by $name. If $value is defined, the option is set to this value. The resulting (or unchanged) value is returned.
This method is called every time a warning or error occurs. $severity is one of 'ERROR' or 'WARNING', $message is a one-line string. The built-in method simply does
warn "$severity: $message\n";
name property, i.e. the canonical Pod name (e.g.
Pod::HTML). See above for more details.
Return the root element (instance of class Pod::root) representing the compiled POD document. See below for more info about its methods.
Turn given text string into a document unique node id. Can be overridden to adapt this to specific formatter needs. Basically this method takes a string and must return something (more or less dependent on the string) that is unique for this POD document. The built-in method maps all consecutive non-word characters and underlines to a single underline and truncates the result to -idlength (see options above). If the result already exists, a suffix
_n is appended, where
n is a number starting with 1. A different method could e.g. just return ascending numbers, but if you think of HTML output, a node id that resembles the text and has a fair chance to remain constant over subsequent compiles of the same document gives the opportunity to link to such anchors from external documents.
The Pod::Compiler module is designed to serve as a basis for complex POD converters, e.g. to HTML, FrameMaker or LaTeX that can handle multiple POD documents with a table of contents, an index and most imporant hyperlinks/crossreferences.
The following flow outlines how such a converter may work:
Interpreting command line arguments and options, the converter should gather all the POD files to be converted. Note that because of the structure of POD hyperlinks and restrictions in the anchor format of the individual destination formats you'll almost certainly will need a two-pass apporach where you process all documents at once. See Pod::Find for some useful helpers in locating POD documents. The documents are stored as Pod::doc in a Pod::doc::collection.
The next step would be a loop over all documents, calling Pod::Compiler on each document. This checks the syntax, prints errors and warnings and generates an object tree and information about the document's hyperlink anchors. The latter (a Pod::node::collection) is stored in the Pod::doc, the former is saved to a temporary file (see also File::Temp) with the help of Storable.
The second loop over all documents does the actual conversion. If you do not care very much about OO principles, you may extend the Pod::* packages by e.g. a
as_html method, so that you can say
(Pod::root)->as_html. Or you use the
walk_down method of Tree::DAG_Node to traverse the object tree and convert the individual objects in the callback.
The existing Pod::doc::collection is used to resolve the hyperlinks. Each node already has a node id assigned.
The result is saved to the destination files and the temporary files can be removed.
During or after the final conversion one can build a TOC and an index, derived from the
X<> respectively. Strategies for the index could be: Only the
X<> entries, single worded
=item, all hyperlink anchors that were hit during conversion, all
Marek Rouchal <email@example.com>
A big deal of this code has been recycled from a variety of existing Pod converters, e.g. by Tom Christiansen and Russ Allbery. A lot of ideas came from Nick Ing-Simmons' PodToHtml.