The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Pod::Term - Yet another POD Parser for terminal (ie command line) output

SYNOPSIS

    use Pod::Term;

    my $pt = Pod::Term->new;

    $pt->globals({
        max_cols => 72,
        base_color => 'yellow'
    });

    Pod::Term->set_props({
        head1 => {
            indent => 2,
            after_indent => 4,
            bottom_spacing => 2,
            color => 'green'
        },
        'item-number' => {
            indent => 2,
            color => 'bright_cyan',
            prepend => {
                text => '@number -',
                color => 'blue'
            }
        }
    });

    $pt->parse_file( '/path/to/pod/file' );

DESCRIPTION

Despite the plethora of Pod parsing modules on CPAN I couldn't seem to coax any into meeting my presentation requirements for pod printed at the terminal. I never anticipated getting diverted onto writing a full-blown POD parser, but that is what ended up happening. My advice to anyone considering writing a POD parser - don't go there. Quantum mechanics is much less troublesome.

This is yet another POD parser. It inherits from POD::Simple and so all Pod::Simple methods should be available (but Pod::Simple seems pretty complex under the hood and possibly in need of some maintenance. I am wondering if the advice to 'use Pod::Simple for all things Pod' is really the best? e.g. I was not able to get the output_string method to work at all).

Like Pod::Text::Color, Pod::Term uses Term::ANSIColor to set ANSI color values to POD elements. However I was not able to get Pod::Text::Color to cleanly wrap colored text. It seems that Pod::Text::Color attempts to wrap the text after putting in the color characters, by trying to ignore those characters - I am not sure if it is the reason. I also couldn't seem to control the spacing, indents etc.

Pod::Term wraps text before inserting color values, and should produce a nice clean wrap. It also offers a decent level of control over formatting, by allowing you to assign simple directives (indent, top_spacing etc.) to individual page elements (head1, over etc.) POD has never looked so good!

METHODS

Basically Pod::Term formats according to whatever it finds in the prop_map attribute. If you want to know what's in there by default, you can do something like:

    use Data::Dumper;
    use Pod::Term;

    my $pt = Pod::Term->new;
    print "prop_map contains: ".Dumper( $pt->prop_map )."\n";

You should find prop_map is a hashref which looks something like:

    {
        head1 => {
            display => 'block',
            stacking => 'revert',
            indent => 0,
            after_indent => 2,
            color => 'on_blue',
            bottom_spacing => 2
        },

        head2 => {
            display => 'block',
            stacking => 'revert',
            indent => 0,
            after_indent => 2,
            color => 'blue',
            bottom_spacing => 2
        }

        # ...
    
    }

with one entry per POD element type, (using the element names that are generated by Pod::Simple.) So to adjust formatting, you can either directly replace the hashref in prop_map:

    $pt->prop_map({
        
        # new property map hashref 

    });

or use one of the property adjuster methods set_prop and set_props. As the names suggest, the former sets just one property in the map, while the second can set many:

    $pt->set_prop( 'head1', 'indent', 2);

    $pt->set_props({
        head2 => {
            bottom_spacing => 2,
            color => 'bright_magenta'
        },
        Para => {
            top_spacing => 5,
            color => 'white'
        }
    });

Once you have specified your format options, you are ready to parse.

A quick method summary:

prop_map

get/set the map of element properties (ie the hash of formatting options). This will use a set of default values if not explicitly set.

    my $current_prop_map = $pt->prop_map;       # get

    $pt->prop_map( $new_prop_map );             # set
set_prop

Set the value of an individual property in the map

    $pt->set_prop($element_name, $prop_name, $new_value );

    $pt->set_prop('head2', 'bottom_spacing', 3);
set_props

Set the values of several properties in the properties map at the same time. Pod::Text uses Hash::Merge to insert the new values.

    $pt->set_props({
        Document => {
            indent => 2,
            bottom_spacing => 2
        },            
        head1 => {
            indent => 4,
            color => 'red'
        }
    });
globals

globals is a hashref containing formatting which affects the whole document. Again it is a good idea to dump this to see the defaults and what is available for modification:

    use Data::Dumper;
    use Pod::Term;

    my $pt = Pod::Term->new;
    print "globals: ".Dumper( $pt->globals )."\n";

At the time of writing, it contains just 2 variables:

    {
        max_cols => 76,
        base_color => white
    }

but should I update the module but forget to update this documentation, then Data::Dumper is your friend.

Hopefully the 2 above global attributes are reasonably straightforward:

max_cols

max_cols is basically the number of columns to wrap to (except for 'Verbatim' sections - which are printed... verbatim, which means they can stray outside the wrapping margin if the POD author was being inconsiderate)

base_color

base_color is the color to start out with and revert back to if no color is specified. However, it's best to set colors explicitly where possible to avoid surprises.

PROPERTY MAP VALUES

I've called these "properties" rather than "attributes" because Pod::Simple uses "attributes" to mean something else. And "property map" is really a hashref which delegates properties to elements.

Some values I recommend you play with - and some I don't. Here are the ones that are fun to adjust:

properties which apply to "block" elements only

(see the display property for what is meant by a block element.)

indent

The number of spaces to add to the indent when the element is parsed. Note indents are cumulative (in general - see stacking). This indent happens before the element gets printed.

after_indent

The number of spaces to add to the indent immediately after the element is parsed. e.g. specifying after_indent = 2 on a head1 element means a paragraph occurring immediately after your head1 title will be indented 2 spaces relative to the head1.

top_spacing

How many lines to print immediately above the element

bottom_spacing

How many lines to print immediately below the element. Note that in many cases specifying 0 for this is not a good idea. You should probably make sure that either top_spacing or bottom_spacing are at least 1 for the elements which have text bodies, otherwise no linespace character will be printed between text blocks (and I'm afraid Pod::Term does not neatly run paragraphs together in this situation).

color

The color to set to the element. Pod::Term uses Term::ANSIColor for colors. See the man page for Term::ANSIColor for a list of available colors.

properties applying to both inline and block elements

prepend

prepend is really intended for list items. For example, you may want your bullets to start with a blue dash (-) etc. To do this, set your attribute thus:

    $pt->set_prop('item-bullet','prepend', {
        
        text => '*',
        color => '-'

    });

Note that the prepend attribute should be a hashref containing text at a minimum, and possibly color. In theory you can use prepend with any element - but in the case of 'over' elements in particular it will lead to unexpected effects. This is because parents of nested elements are rendered after the child - so you would get your prepended text occurring at the end of your list, which is probably not what you want.

Both prepend and append should not contain newline characters. Blocks are defined to be lumps of text without return characters, so trying to prepend or append then will cause confusion. To add newline characters to the beginning and end of blocks, use top_spacing and bottom_spacing

append

Like prepend, but occurs at the end of the element. See the documentation for prepend.

And now for the properties that you might want to leave alone. However it's important to understand what they do

display

This is a CSS style property, which can take 2 values with names borrowed from CSS, inline and block. If you are familiar with both CSS and POD then it should be quite easy to work out which POD elements should be defined as inline and which as block. Formatting codes such as B - which indicates bold text - obviously counts as an inline element, while head1, Para etc are block elements. The crucial difference being that block elements expect to have line spacing between them, whereas inline follows the text. Things like top and bottom spacing only really make sense for block style elements, so setting a bottom_spacing value on a B element will not have any effect

stacking

stacking controls how the left indent is calculated on block elements. Possible values are revert, nest and spot. POD suffers from an identity crisis, since for the most part it presents as a series of elements which don't nest, but then incorporates the over element which works as an envelope and can be nested to arbitrary depth, html style.

There are the head1, head2... elements - which are expected to occur as a single set, and not within other sections. For these, it's probably best if each head1 has the same indent, and each head2 has the same indent within the same head1. So these get stacking=revert, meaning the indent level will fall back to what it was last time the same element was encountered.

over and item elements typically get stacking=nest meaning a newly encountered over gets an increased indent (as long as the indent property is set for the relevant over element.)

spot is more complex, and should be used with caution. It is an uncomfortable combination of revert and nest, reverting only if the last stacked element is the same as itself. Otherwise it will nest. The idea with spot is to keep list items that may contain nested paragraphs in line with each other, rather than the next item after the paragraph indenting further.

Stacking may be confusing, and it may be best to make sure you can't get what you want by altering other settings before getting too experimental with it.

SEE ALSO

Pod::Simple, Pod::Text, Pod::Text::Color, Term::ANSIColor

AUTHOR

Tom Gracey tomgracey@gmail.com

COPYRIGHT AND LICENSE

Copyright (C) 2018 by Tom Gracey

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.20.1 or, at your option, any later version of Perl 5 you may have available.