5

我有一个小的 perl 模块,并且正在使用 Getopt::Long,我想我不妨使用 Pod::Usage 来获得一个漂亮的帮助显示。

经过一番摆弄,我让它工作得相当好,只有一个小例外。我无法设置输出的宽度。

我的终端有 191 个字符宽。使用 perldoc Module.pm,它将文档正确格式化为该宽度。使用 pod2usage(),它使用 76 个字符的默认宽度。

我不知道如何将宽度选项传递给格式化程序。该文档显示了如何使用 BEGIN 块设置不同的格式化程序(例如 Pod::Text::Termcap),并且我使用 Term::ReadKey 来拉宽度(已验证),但我无法让格式化程序看见。

有什么提示吗?

这是我要测试的完整模块,以及一个用于加载它的小测试脚本。要明白我的意思,打开一个具有合理宽度的终端(132 或更大,所以很明显),并将“./test.pl --man”的输出与“perldoc MUD::Config”的输出进行比较.

我可以不用 perldoc 添加的手册页样式页眉和页脚,但我希望它尊重(并使用)终端宽度。

测试.pl

#!/usr/bin/perl -w

use strict;
use warnings;

use MUD::Config;
#use MUD::Logging;

my $config = new MUD::Config @ARGV;
#my $logger = new MUD::Logging $config;

#$bootlog->info("Logging initialized");
#$bootlog->info("Program exiting");

和 MUD/Config.pm

#!/usr/bin/perl -w

package MUD::Config;

=pod

=head1 NAME

MUD::Config --  Configuration options for PocketMUD

=head1 SYNOPSIS

./PocketMUD [OPTIONS]

=head1 OPTIONS

=over 8

=item B<--dbname>

Specifiy the name of the database used by PocketMUD S<(default B<pocketmud>)>.

=item B<--dbhost>

Specify the IP address used to connect to the database S<(default B<localhost>)>.

=item B<--dbport>

Specify the port number used to connect to the database S<(default B<5432>)>.

=item B<--dbuser>

Specify the username used to connect to the database S<(default B<quixadhal>)>.

=item B<--dbpass>

Specify the password used to connect to the database S<(default B<password>)>.

=item B<--dsn>

The DSN is the full connection string used to connect to the database.  It includes the
values listed above, as well as several other options specific to the database used.

S<(default B<DBI:Pg:dbname=$db_name;host=$db_host;port=$db_port;sslmode=prefer;options=--autocommit=on>)>

=item B<--logfile>

Specify the text file used for debugging/logging output S<(default B</home/quixadhal/PocketMUD/debug-server.log>)>.

=item B<--port>

Specify the port used for player connections S<(default B<4444>)>.

=item B<--help>

Display usage information for PocketmUD.

=item B<--man>

Display full documentation of configuration module details.

=back

=head1 DESCRIPTION

PocketMUD is a perl re-implementation of SocketMUD.

It is meant to be a barebones MUD server, written in perl,
which can be easily modified and extended.

=head1 METHODS

=cut

use strict;
use warnings;
use Getopt::Long qw( GetOptionsFromArray );
use Config::IniFiles;
use Data::Dumper;

BEGIN {
    use Term::ReadKey;

    my ($width, $height, $pixel_width, $pixel_height) = GetTerminalSize();
    #print "WIDTH: $width\n";
    $Pod::Usage::Formatter = 'Pod::Text::Termcap';
    $Pod::Usage::width = $width;
}

use Pod::Usage;
use Pod::Find qw(pod_where);

Getopt::Long::Configure('prefix_pattern=(?:--|-)?');    # Make dashes optional for arguments

=pod

B<new( @ARGV )> (constructor)

Create a new configuration class.  You should only need ONE instance of this
class, under normal circumstances.

Parameters passed in are usually the command line's B<@ARGV> array.  Options that
can be specified are listed in the B<OPTIONS> section, above.

Returns: configuration data object.

=cut


sub new {
    my $class = shift;
    my @args = @_;
    my ($db_name, $db_host, $db_port, $db_user, $db_pass, $DSN);
    my ($logfile, $port);
    my $HOME = $ENV{HOME} || ".";

    # Order matters... First we check the global config file, then the local one...
    foreach my $cfgfile ( "/etc/pocketmud.ini", "$HOME/.pocketmud.ini", "./pocketmud.ini" ) {
        next if !-e $cfgfile;
        my $cfg = Config::IniFiles->new( -file  => "$cfgfile", -handle_trailing_comment => 1, -nocase => 1, -fallback => 'GENERAL', -default => 'GENERAL' );
        $db_name = $cfg->val('database', 'name')        if $cfg->exists('database', 'name');
        $db_host = $cfg->val('database', 'host')        if $cfg->exists('database', 'host');
        $db_port = $cfg->val('database', 'port')        if $cfg->exists('database', 'port');
        $db_user = $cfg->val('database', 'user')        if $cfg->exists('database', 'user');
        $db_pass = $cfg->val('database', 'password')    if $cfg->exists('database', 'password');
        $DSN = $cfg->val('database', 'dsn')             if $cfg->exists('database', 'dsn');
        $logfile = $cfg->val('general', 'logfile')      if $cfg->exists('general', 'logfile');
        $port = $cfg->val('general', 'port')            if $cfg->exists('general', 'port');
    }

    # Then we check arguments from the constructor
    GetOptionsFromArray( \@args ,
        'dbname:s'      => \$db_name,
        'dbhost:s'      => \$db_host,
        'dbport:i'      => \$db_port,
        'dbuser:s'      => \$db_user,
        'dbpass:s'      => \$db_pass,
        'dsn:s'         => \$DSN,
        'logfile:s'     => \$logfile,
        'port:i'        => \$port,
        'help|?'        => sub { pod2usage( -input => pod_where( {-inc => 1}, __PACKAGE__), -exitval => 1 ); },
        'man'           => sub { pod2usage( -input => pod_where( {-inc => 1}, __PACKAGE__), -exitval => 2, -verbose => 2 ); },
    );

    # Finally, we fall back to hard-coded defaults
    $db_name = 'pocketmud'  if !defined $db_name and !defined $DSN;
    $db_host = 'localhost'  if !defined $db_host and !defined $DSN;
    $db_port = 5432         if !defined $db_port and !defined $DSN;
    $db_user = 'quixadhal'  if !defined $db_user;
    $db_pass = 'password'   if !defined $db_pass;
    $logfile = '/home/quixadhal/PocketMUD/debug-server.log' if !defined $logfile;
    $port    = 4444         if !defined $port;

    $DSN = "DBI:Pg:dbname=$db_name;host=$db_host;port=$db_port;sslmode=prefer;options=--autocommit=on" if !defined $DSN and defined $db_name and defined $db_host and defined $db_port;

    die "Either a valid DSN or a valid database name, host, and port MUST exist in configuration data" if !defined $DSN;
    die "A valid database username MUST exist in configuration data" if !defined $db_user;
    die "A valid database password MUST exist in configuration data" if !defined $db_pass;
    die "A valid logfile MUST be defined in configuration data" if !defined $logfile;
    die "A valid port MUST be defined in configuration data" if !defined $port;


    my $self = {
        DB_NAME => $db_name,
        DB_HOST => $db_host,
        DB_PORT => $db_port,
        DB_USER => $db_user,
        DB_PASS => $db_pass,
        DSN     => $DSN,
        LOGFILE => $logfile,
        PORT    => $port,
    };

    bless $self, $class;
    print Dumper($self);
    return $self;
}

sub dsn {
    my $self = shift;
    if ( @_ ) {
        $self->{DSN} = shift;
    }
    return $self->{DSN};
}

sub db_user {
    my $self = shift;
    if ( @_ ) {
        $self->{DB_USER} = shift;
    }
    return $self->{DB_USER};
}

sub db_pass {
    my $self = shift;
    if ( @_ ) {
        $self->{DB_PASS} = shift;
    }
    return $self->{DB_PASS};
}

sub logfile {
    my $self = shift;
    if ( @_ ) {
        $self->{LOGFILE} = shift;
    }
    return $self->{LOGFILE};
}

sub port {
    my $self = shift;
    if ( @_ ) {
        $self->{PORT} = shift;
    }
    return $self->{PORT};
}

1;
4

2 回答 2

3

伙计,我真的在寻找这个挑战......

我偷看了代码,Pod::Usage看看发生了什么。Pod::Usage直接使用该perldoc命令,因此看起来两者都以相同perldocpod2usage方式打印。事实上,在我的系统上,两者都perldoc默认pod2usage或多或少为 80 列。我不知道为什么它在您的系统上有所不同。

有一个例外:

如果您设置-noperldoc参数,它将Pod::Text用于格式化,并且在您创建新对象时Pod::Text有一个选项。-width => $widthPod::Text

我想我可能能够将一个未记录 -width的参数pod2usage传递给它,它会被传递给$parser被创建的对象。这个对象是一个Pod::Usage对象,但Pod::Usage它是 的子类Pod::Text

没有骰子。

这些选项作为单独USAGE_OPT选项的一部分传递,因此$opt_width设置不正确。没有功能接口Pod::Text,因此宽度与特定$parser对象相关联,而不是与包相关联。您不能设置$Pod::Text::width和覆盖默认76值。默认情况下,这是在程序中硬编码的。

有一种方法可以使用Pod::Text,找到一种方法来获取终端宽度,将其传递给您的Pod::Text对象,然后使用该对象调用parse_from_file源文件上的 to 方法。

如果终端是 130 个字符宽,那么您可以看到 130 个字符宽的 POD 输出,这将是很多工作。

于 2013-10-14T01:07:24.183 回答
2

毫不奇怪,针对这个问题的评论对执行 perldoc 时应显示多少列表达了不同的意见,因为 perldoc 的“ToMan”库定义了几种根据您的环境确定行长的方法。

具体来说,它将使用 MANWIDTH 环境变量,或者执行 'stty -a',或者最终默认为 73 个字符 - 按此顺序。

哦,等等,确定行长的策略?这只是针对 Linux 的某些排列。其他平台直接遵循 nroff 来确定应该使用多少列。

那些其他平台可能具有通过 nroff 正确确定行长的实现(如 Quixadhal 建议的那样),或者它们可能在某处隐藏了硬编码值(如 David W. 建议的那样)。

不幸的是,这个特定问题似乎没有一个万能的答案——至少根据我自己比较 FreeBSD 和 Linux 的经验。

一个可能有用的技巧:您可以通过 perldoc 将参数直接传递给 nroff。因此,如果您的 pod2usage 恰好是别名 perldoc(有时会,有时不会?),那么您可以尝试将参数传递给 nroff ,这可能会迫使它为您工作:

pod2usage -n 'nroff -rLL=120n' sample.pm

这仅在 pod2usage 调用 perldoc 时才有效,但是在某些情况下,它是一个完全独立的实现,不接受 -n 参数。

于 2015-03-19T01:13:02.443 回答