perlmanpage

Perl's pod2usage function is incorrectly handling formatting codes


First off, I am using Ubuntu 20.04 with Perl v5.30.0; however, I run into this same issue when using macOS High Sierra with Perl v5.32.1, so it is not limited to one platform.

I began using Perl's Pod::Usage module to document my code by calling pod2usage. I was glad to have something that handles formatting of manual pages, but I was dismayed when I noticed that format codes, such as B<text> and I<text> do not render properly in the output manual page. Below is a screenshot from my terminal window.

Actual output.

As I say in the description section, I expect there to be bold text, followed by normal text, followed italicized text. The first two groups appear in the same typeface, while the italicized section appears between asterisks to simulate the different typeface. The source code of my script is below.

#!/usr/bin/env perl

use strict;
use warnings;
# NOTE: un-commenting the following line produces the "Undefined
#       subroutine" error described below in the post. Otherwise this
#       code executes, though it does not produce the desired output.
# BEGIN { $Pod::Usage::Formatter = "Pod::Perldoc::ToMan"; }

use Getopt::Long qw(GetOptions);
use Pod::Usage qw(pod2usage);

my $man  = 0;
my $help = 0;

GetOptions("help|h" => \$help, "man" => \$man) || pod2usage(2);
pod2usage(1) if ($help);
pod2usage(-verbose => 2) if ($man);

__END__

=pod

=head1 NAME

Sample POD.

=head1 SYNOPSIS

This is a simple test to see if Perl is correctly formatting POD.

=head1 DESCRIPTION

B<This text should be bold>, this text should be normal,
I<and this text should be italicized>.

=cut

I have tried changing the POD formatter using the following lines of code, which I took directly from the Pod::Usage page, but with no success.

BEGIN { $Pod::Usage::Formatter = 'Pod::Text::Termcap'; }
use Pod::Usage qw(pod2usage);

Going down several rabbit holes, I invoked perldoc from the command line to read the POD, and I changed the formatter to Pod::Perldoc::ToMan, first with -oman and then via the -M flag; I learned those from reading the perldoc manpage. This produced the expected result—though the italicized text appeared as underlined, but I'll take it.

perldoc -t -oman test.pl
perldoc -t -MPod::Perldoc::ToMan test.pl

Expected output.

Thinking that may solve the problem in my script, I changed the formatter from "Pod::Text::Termcap" to "Pod::Perldoc::ToMan", but that created the following unexpected error.

Undefined subroutine &main::pod2usage called at test.pl line 16.

I want the output of pod2usage to look like that shown in the second screenshot—even if I cannot get the italics to render properly. How can I do this, and is it a matter of changing the POD formatter?

EDIT: this is the code as it appears in my file, copied directly from output with xclip.

#!/usr/bin/env perl

use strict;
use warnings;

BEGIN { $Pod::Usage::Formatter = "Pod::Perldoc::ToMan"; }

use Getopt::Long qw(GetOptions);
use Pod::Usage qw(pod2usage);

my $man  = 0;
my $help = 0;

GetOptions("help|h" => \$help, "man" => \$man) || pod2usage(2);
pod2usage(1) if ($help);
pod2usage(-verbose => 2) if ($man);

__END__

=pod

=head1 NAME

Sample POD.

=head1 SYNOPSIS

This is a simple test to see if Perl is correctly formatting POD.

=head1 DESCRIPTION

B<This text should be bold>, this text should be normal,
I<and this text should be italicized>.

=cut

Running the script without flags produces a zero exit status with no errors. Executing with the following flags, however, results in the Undefined subroutine error mentioned above. Once again, this output was collected directly from the terminal using xclip.

$ perl test.pl -help
Undefined subroutine &main::pod2usage called at test.pl line 15.
$ perl test.pl -man
Undefined subroutine &main::pod2usage called at test.pl line 16.

Solution

  • First of all, Pod::Text::Termcap works fine.

    Italics!

    "Usage" is bold, and I added I<foo> which is underlined.


    Secondly, you're using a perldoc plugin instead of a pod formatter. You should be using Pod::Man instead of Pod::Perldoc::ToMan.

    (Pod::Man results in the same error as Pod::Perldoc::ToMan. I'll provide an explanation and a workaround below.)

    Of course, that produces a man page, which is completely unreadable unless you invoke nroff using something like one of the following:

    man <( perl a.pl --help )     # Requires bash
    
    perl a.pl --help | nroff -man
    

    The text is entirely missing, though.

    "Empty" man page

    So this is a no go. Stick with Pod::Text::Termcap.


    But as for your question, there is a bug in Pod::Usage.

    Most modules that export symbols use Exporter. This is what Pod::Usage uses to export pod2usage.

    There are two ways to use Exporter:

    1. Inherit from it.

      use Exporter;
      our @EXPORT = qw( pod2usage );
      our @ISA = qw( Exporter );
      
    2. Import import from it.

      use Exporter qw( import );
      our @EXPORT = qw( pod2usage );
      

    This is what Pod::Usage does:

    use Exporter;
    our @EXPORT = qw( pod2usage );
    our @ISA = $Pod::Usage::Formatter;
    

    This works if the formatter inherits from Exporter (such as Pod::Text), but it fails if the formatter doesn't. This is the case for Pod::Man.

    There is workaround, however.

    BEGIN { $Pod::Usage::Formatter = 'Pod::Man'; }
    package Pod::Usage { use Exporter qw( import ); }
    use Pod::Usage qw( pod2usage );
    

    I have filed a ticket.


    Finally, you probably noticed I used --help above. You're probably asking --man, which you have use perldoc instead of Pod::Usage's formatter. So playing with Pod::Usage's formatter will have absolutely no effect on --man. -perldocopt should get you where you want to go, though.