Home / Alt manpages / perlpodspec(1)

  • perlpodspec(1)
  • User command
  • linux

Write Pod That Parsers Can Read Without Guesswork

You will finish with a small Perl documentation file that podchecker accepts, plus a repeatable way to check the parts that a formatter cannot infer safely. Pod is usually forgiving enough to render while still being structurally ambiguous. The habits here make the source predictable for HTML, terminal and other formatters.

Prerequisites: Perl and the perl-doc package. This guide was checked with Perl v5.38.2 and perl-doc 5.38.2-3.2ubuntu0.6 on Ubuntu. Allow about 15 minutes. You do not need root for the examples.

Checkpoint: create a Pod block

  1. Make a scratch file in /tmp, and put the documentation at the start of a Pod block.

    cat > /tmp/widget.pod <<'POD'
    =pod
    
    =head1 NAME
    
    widget - inspect a widget file
    
    =head1 SYNOPSIS
    
        widget [OPTIONS] FILE
    
    =head1 DESCRIPTION
    
    The widget command reads FILE and reports its basic properties.
    
    =cut
    POD
  2. Check the file before adding more content.

    podchecker /tmp/widget.pod

    A successful check reports that the file has no Pod errors or warnings. A Pod block begins with a line whose first character is = followed by a letter. It ends at =cut, or at end of file. A file containing only Pod is valid; Pod can also be embedded in a Perl source file.

Checkpoint: keep paragraph types distinct

Pod decides what a paragraph is from its first line. A line beginning with a recognised command creates a command paragraph. A line beginning with a space or tab creates a verbatim paragraph, where whitespace matters. Anything else is an ordinary paragraph. Blank lines separate paragraphs; spaces and tabs on an otherwise empty line count as blank too.

That first-character rule is an easy place to lose time. Do not indent =head1, =item or =cut. Do indent literal command examples, because indentation is what makes them verbatim:

=head1 EXAMPLE

    printf "hello\n";

This is ordinary paragraph text.

The indented line is documentation text, not a command to be executed. Keep a blank line around it so later edits do not accidentally merge it with the surrounding prose.

Checkpoint: use commands with their intended shape

Use =head1 through =head6 for headings, =over and =back for a list or indented region, and =item for its entries. A bare =over has the same practical default indent as =over 4; a supplied value must be a positive number such as 3 or 3.5.

=head1 OPTIONS

=over 4

=item B<--verbose>

Print additional details.

=item B<--output> I<FILE>

Write the report to FILE.

=back

Choose one list shape and keep it consistent inside a region: bullet items such as =item *, numbered items starting at 1 and continuing without gaps, or descriptive item text. A region without any =item is an indented block. Do not put headings inside an =over ... =back region.

Commands are not interchangeable. =back takes no trailing text. =end must name the currently open =begin region, in the same nesting order. An unknown command should be treated as an error, so a typo such as =headd1 is not harmless prose.

Checkpoint: make formatting codes unambiguous

Formatting codes start with a capital letter. Use I<text> for emphasis, B<text> for bold text, C<code> for code, F<filename> for filenames, and L<...> for links. Escape a literal angle bracket with an E<...> character escape, or use the multiple-angle form when code contains comparison operators.

=head1 EXAMPLE

Call C<open> with a three-argument form:

    open my $fh, '<', $path or die $!;

The expression C<$a E<lt>=E<gt> $b> means that $a is compared with $b.

For longer code, multiple angle brackets keep the closing markers visible:

C<<
    open my $fh, '<', $path or die $!;
>>

Do not nest L<...> links. For a page and section, write a form such as L<perlfunc/"open">; for an external address, use L<https://example.invalid/>. A section-only link uses L</"OPTIONS">. The link text can be supplied before a vertical bar, as in L<the open documentation|perlfunc/"open">.

Checkpoint: separate target-specific data

Use =begin FORMAT ... =end FORMAT when content is intended for a particular processor, such as HTML. Inside a region whose name does not start with a colon, non-command paragraphs are data and are not parsed for ordinary Pod formatting codes. A colon changes that: =begin :FORMAT keeps the contents subject to normal paragraph processing.

=begin html

<em>Only an HTML formatter should use this.</em>

=end html

Regions must nest properly. If you open =begin outer, then =begin inner, close =end inner before =end outer. Do not use a target-specific region as a way to hide a malformed command.

Verify the finished document

  1. Add the list and link examples to /tmp/widget.pod, then run the checker again.

    podchecker /tmp/widget.pod
  2. Ask the installed formatter to produce HTML in a separate temporary directory.

    pod2html --outfile=/tmp/widget.html --htmlroot=/tmp --htmldir=/tmp /tmp/widget.pod
    test -s /tmp/widget.html && echo "HTML created"
    rm -f /tmp/widget.html /tmp/widget.pod

    These commands change only temporary files. The final rm is safe here because the paths are explicit scratch outputs. If you need to inspect the HTML, omit that final command and remove the two files later.

Common traps

  • A command is ignored or rejected: check its first character, spelling and whether it is one of the recognised commands. A command inside a non-colon =begin region is still a command, even though ordinary paragraphs there are data.

  • Code layout changes: check whether the paragraph starts with a space or tab. Verbatim whitespace is significant, although a processor may expand tabs.

  • A list renders oddly: check that every =over has a matching =back, that item styles do not change halfway through, and that numbered items are sequential.

  • A link points somewhere surprising: make the page, section, text and URL explicit. Older section-only forms such as L<"OPTIONS"> are ambiguous and deprecated; prefer L</"OPTIONS">.

Done means

  • The document has a clearly bounded Pod block and a blank line between paragraphs.
  • Commands are unindented, code examples are intentionally verbatim, and lists close correctly.
  • Formatting codes and links use escaped or multiple-angle syntax where needed.
  • Target-specific data is isolated in correctly nested =begin and =end regions.
  • podchecker /tmp/widget.pod passes, and pod2html creates non-empty output.