Как я могу включить режим отладки через переключатель командной строки для моей программы Perl?

Я изучаю Perl в "головой вперед" способ. Я - абсолютно новичок на этом языке:

Я пытаюсь иметь переключатель debug_mode от CLI, который может использоваться, чтобы управлять, как мой сценарий работает, путем включения и выключения определенных подпрограмм "".

И ниже то, что я имею до сих пор:

#!/usr/bin/perl -s -w

# purpose : make subroutine execution optional,
# which is depending on a CLI switch flag

use strict;
use warnings;

use constant DEBUG_VERBOSE             => "v";
use constant DEBUG_SUPPRESS_ERROR_MSGS   => "s";
use constant DEBUG_IGNORE_VALIDATION     => "i";
use constant DEBUG_SETPPING_COMPUTATION  => "c";

our ($debug_mode);

mainMethod();

sub mainMethod # ()
{
    if(!$debug_mode)
    {
        print "debug_mode is OFF\n";
    }
    elsif($debug_mode)
    {
        print "debug_mode is ON\n";
    }
    else
    {
        print "OMG!\n";
        exit -1;
    }

    checkArgv();
    printErrorMsg("Error_Code_123", "Parsing Error at...");
    verbose();
}

sub checkArgv #()
{
    print ("Number of ARGV : ".(1 + $#ARGV)."\n");
}

sub printErrorMsg # ($error_code, $error_msg, ..)
{
    if(defined($debug_mode) && !($debug_mode =~ DEBUG_SUPPRESS_ERROR_MSGS))
    {
        print "You can only see me if -debug_mode is NOT set".
          " to DEBUG_SUPPRESS_ERROR_MSGS\n";
        die("terminated prematurely...\n") and exit -1;
    }
}

sub verbose # ()
{
    if(defined($debug_mode) && ($debug_mode =~ DEBUG_VERBOSE))
    {
        print "Blah blah blah...\n";
    }
}

Насколько я могу сказать, по крайней мере, это работает...:

  1. переключатель-debug_mode не вмешивается в нормальный ARGV
  2. следующая работа командных строк:
    • ./optional.pl
    • ./optional.pl-debug_mode
    • ./optional.pl-debug_mode=v
    • ./optional.pl-debug_mode=s

Однако я озадачен, когда несколько debug_modes "смешаны", такие как:

  1. ./optional.pl-debug_mode=sv
  2. ./optional.pl-debug_mode=vs

Я не понимаю, почему вышеупомянутые строки кода "волшебно работают".

Я вижу оба из "DEBUG_VERBOS", и "DEBUG_SUPPRESS_ERROR_MSGS" относятся к сценарию, который прекрасен в этом случае.

Однако, если существуют некоторые "конфликтующие" режимы отладки, я не уверен, как установить "приоритет debug_modes"?

Кроме того, я не уверен, достаточно хорош ли мой подход к Perlists, и я надеюсь, что получаю ноги в правильном направлении.

Одна самая большая проблема состоит в том, что я теперь поместил если операторы в большинстве моих подпрограмм для управления их поведением под различными режимами. Это хорошо? Существует ли более изящный путь?

Я знаю, что должен быть модуль отладки от CPAN или в другом месте, но я хочу реальное минимальное решение, которое не зависит ни от какого другого модуля, чем "значение по умолчанию".

И я не могу иметь никакого контроля на среде, где этот сценарий будет выполняться...

5
задан brian d foy 22 May 2010 в 15:36
поделиться

4 ответа

Для обработки параметров командной строки см. Getopt :: Long . Вы получаете всевозможные удобные варианты синтаксического анализа аргументов.

Существует очень много модулей, обрабатывающих ведение журнала. Log4Perl - очень популярный модуль регистрации.

Если вы действительно хотите ограничить себя, избегая CPAN (что является плохой идеей), вы можете довольно легко собрать модуль регистрации.

Вот маленький, который я для тебя взломал. Нужны тесты, настоящая документация и так далее. Я также использовал некоторые продвинутые методы, такие как собственный метод import () . Есть также некоторые подводные камни, связанные с тем, что я использую одну переменную для хранения настроек DEBUG для всего приложения. Но это работает. Я использовал аналогичный модуль в одном проекте, и он мне очень понравился.

package QLOG;

use strict;
use warnings;
use Carp qw(croak);

our %DEBUG_OPTIONS;
our %VALID_DEBUG_OPTIONS;
our %DEBUG_CONFLICTS;

sub import {

    my $pkg = shift;
    my $target = caller();

    my %opts = @_;


    # Configure options

    croak "Must supply an array ref of valid modes"
       unless exists $opts{options};

    @VALID_DEBUG_OPTIONS{ @{$opts{options}} } = ();

    # Configure conflicts

    if( exists $opts{conflicts} ) {
        @DEBUG_CONFLICTS{ keys %{$opts{conflicts}} } 
            = values %{$opts{conflicts}}
    }

    # Export DEBUG method

    {   no strict 'refs';
        *{$target.'::DEBUG'} = \&DEBUG;
    }

    return;
}

sub DEBUG {
    my $mode = shift;

    croak "DEBUG mode undefined"
        unless defined $mode;

    return unless
        ( $mode eq 'ANY' and %DEBUG_OPTIONS )
        or exists $DEBUG_OPTIONS{$mode};

    warn "$_\n" for @_;

    return 1;
}


sub set_options {

    for my $opt ( @_ ) {
        die "Illegal option '$opt'"
           unless exists $VALID_DEBUG_OPTIONS{$opt};

        $DEBUG_OPTIONS{$opt}++;
    }

    return;
}

sub check_option_conflicts {

    for my $opt ( keys %DEBUG_OPTIONS ) {

        if (exists $DEBUG_CONFLICTS{$opt}) {

            for ( @{$DEBUG_CONFLICTS{$opt}} ) {

                die "Debug option $opt conflicts with $_" 
                    if exists $DEBUG_OPTIONS{$_} 
            }
        }
    }

    return;
}


1;

А затем используйте это следующим образом:

#!/usr/bin/perl 

use strict;
use warnings;


use Getopt::Long;

use QLOG
    options => [qw(
        VERBOSE
        SUPPRESS_ERROR_MSGS
        IGNORE_VALIDATION
        SETPPING_COMPUTATION
    )], 
    conflicts => {
        VERBOSE => [qw(
            SUPPRESS_ERROR_MSGS
            SETPPING_COMPUTATION
        )],
    };




process_args();

DEBUG VERBOSE => 'Command line data parsed.';

main();

### ---------------

sub main {

    DEBUG VERBOSE => 'BEGIN main()';

    if( DEBUG 'ANY' ) {
        print "debug_mode is ON\n";
    }
    else {
        print "debug_mode is OFF\n";
    }

    warn "Error which could be surpressed\n"
        unless DEBUG 'SUPPRESS_ERROR_MSGS';
}


# Get arguments and process flags like 'v' and 'sc' into strings specified
# in QLOG configuration above.
# This processing makes the nice DEBUG VERBOSE => 'blah'; syntax work.
sub process_args {

    # Use Getopt::Long to parse @ARGV

    my @debug_options;
    GetOptions (
        'debug-options=s@' => \@debug_options,
        'help'             => \&usage,
    ) or usage();

    # Convert option flags to strings.
    my %option_lut = qw(
        v  VERBOSE  
        s  SUPPRESS_ERROR_MSGS
        i  IGNORE_VALIDATION 
        c  SETPPING_COMPUTATION 
    );

    my @options = map {          # This chained map 
        exists $option_lut{$_}   #    looks in the lut for a flag
        ? $option_lut{$_}        #       translates it if found
        : $_                     #       or passes on the original if not.
    } 
    map {                        # Here we split 'cv' into ('c','v')
       split //
    } @debug_options;

    # Really should use Try::Tiny here.
    eval {    
        # Send a list of strings to QLOG
        # QLOG will make sure they are allowed.
        QLOG::set_options( @options );

        QLOG::check_option_conflicts(); 

        1;          # Ensure true value returned if no exception occurs.
    } or usage($@);

    return;
}

sub usage {

    my $message = shift || '';
    $message = '' if $message eq 'help';

    print <<"END";
$message

Use this proggy right.

END

    exit;
}

Вы можете добавить метод, чтобы ваши отладочные сообщения подавлялись.

Что-то вроде:

sub SUPPRESSED_BY {
     my $mode = shift;

     return if exists $DEBUG_OPTIONS{$mode);

     return @_; 
}

Экспортируйте символ, а затем используйте его как:

DEBUG VERBOSE => SUPPRESSED_BY SUPPRESS_ERRORS => 'My message here';

Простота, с которой модуль регистрации может быть скомпонована вместе, привела к тому, что доступно большое количество таких модулей. Есть так много способов выполнить эту задачу и различные варианты требований при инструментировании кода, что их еще больше.Я даже написал несколько модулей регистрации для различных нужд.

Как бы то ни было, это должно дать вам серьезный шанс окунуться в воду, когда вы с головой погрузитесь в Perl.

Не стесняйтесь спросить меня: «Что за черт?» типа вопросы. Я понимаю, что много кидаю на тебя.

6
ответ дан 13 December 2019 в 19:22
поделиться

To ответьте на это:

Я не понимаю, почему приведенные выше строки кода «волшебным образом работают».

Причина в том, что вы проверяете значения переключателя отладки с помощью регулярного выражения, например:

if(defined($debug_mode) && !($debug_mode =~ DEBUG_SUPPRESS_ERROR_MSGS))

Итак, если у вас есть:

$debug_mode = "sv"

и в качестве напоминания:

use constant DEBUG_VERBOSE             => "v";
use constant DEBUG_SUPPRESS_ERROR_MSGS   => "s";

Тогда оба они будут оценка истина:

$debug_mode =~ DEBUG_SUPPRESS_ERROR_MSGS;
$debug_mode =~ DEBUG_VERBOSE;

Если вы хотите проверить ровно одно значение, вы можете попробовать:

if ($debug_mode eq DEBUG_SUPPRESS_ERROR_MSGS) {...}
if ($debug_mode eq DEBUG_VERBOSE) {...}

или еще

if ($debug_mode =~ /\bDEBUG_SUPPRESS_ERROR_MSGS\b/) {...}
if ($debug_mode =~ /\bDEBUG_VERBOSE/b\) {...}

, где \ b указывает регулярному выражению соответствовать границе слова. Конечно, если у вас есть $ debug_mode = "s v" , то регулярное выражение также будет оценивать значение true.

2
ответ дан 13 December 2019 в 19:22
поделиться

Судя по вашему ответу на Tore, я взломал этот образец.

#!/usr/bin/perl 

use strict;
use warnings;

use Getopt::Long;

my $count_letters;
my $eat_beans;
my $count_beans;
my $data_file;

GetOptions (
    'count-letters' => \$count_letters,
    'count-beans'   => \$count_beans,
    'eat-beans'     => \$eat_beans,
    'data-file=s'   => \$data_file,
    'help'          => \&usage,
) or usage();

# Build code ref arrays.

my @validate_file =
  ( $count_beans   ? \&count_beans   : () ),
  ( $count_letters ? \&count_letters : () ),
  ;

my @validate_line = 
  ( $eat_beans     ? \&eat_beans     : () ),
  ;


process_file( $data_file, \@validate_line, \@validate_file );


sub process_file {
    my $file           = shift;
    my $validate_lines = shift;
    my $validate_file  = shift;

    open my $fh, '<', $file or die "$file : $!";

    my @data;
    while( my $line = $fh->readline ) {

        # Validate each line with each line validator

        $_->($line) or die 'Invalid line' 
            for @$validate_lines;

        push @data, $line;
    }

    # Validate the whole file with the each file validator.
    $_->(\@data) or die 'Invalid file' 
        for @$validate_file;
}

# Put real subs here:

sub eat_beans     { 1 }

sub count_beans   { 1 }
sub count_letters { 1 }

Что касается тестирования, вы, вероятно, захотите поместить все свои подсистемы проверки в модуль и использовать обычные инструменты тестирования Perl (см. Test :: Simple и Test :: More, чтобы начать работу).

Мне нравится структурировать свои приложения с помощью тонкого синтаксического анализатора CLI, который настраивает базовый набор данных, который используется основной логикой приложения, живущей в модуле.

Это упрощает написание модульных тестов для проверки правильности кода.

2
ответ дан 13 December 2019 в 19:22
поделиться

Думаю, здесь вы столкнулись с двумя проблемами. Во-первых, для обработки более сложного синтаксического анализа командной строки используйте модули ядра Getopt :: Std или Getopt :: Long вместо ключа командной строки -s.

Вторая проблема (я думаю) заключается в том, что вы пытаетесь каким-то волшебным способом пропустить операторы отладки, когда включен режим отладки. Я не знаю ни одного стандартного модуля, который бы это делал, но это возможно с различными конструкциями:

eval {  ...code block... } if($debug);

Это не значит, что изменение логики вашей программы в зависимости от того, включен ли режим отладки, обязательно является хорошей идеей. Вы должны стремиться ограничить «режим отладки», чтобы изменить вывод вашей программы, а не логику, иначе вы потратите много часов, задаваясь вопросом, почему он работает в режиме отладки, а не в «рабочем режиме».

1
ответ дан 13 December 2019 в 19:22
поделиться
Другие вопросы по тегам:

Похожие вопросы: