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

StackOverflow https://stackoverflow.com/questions/356337

  •  21-08-2019
  •  | 
  •  

Вопрос

У меня есть Perl-скрипт, который устанавливает переменные вверху для каталогов и файлов, которые он будет использовать.Это также требует, чтобы в качестве аргументов командной строки было задано несколько переменных.Пример:

use Getopt::Long;

my ($mount_point, $sub_dir, $database_name, $database_schema);
# Populate variables from the command line:
GetOptions(
    'mount_point=s'       => \$mount_point,
    'sub_dir=s'           => \$sub_dir,
    'database_name=s'     => \$database_name,
    'database_schema=s'   => \$database_schema
);
# ...  validation of required arguments here

################################################################################
# Directory variables
################################################################################
my $input_directory    = "/${mount_point}/${sub_dir}/input";
my $output_directory   = "/${mount_point}/${sub_dir}/output";
my $log_directory      = "/${mount_point}/${sub_dir}/log";
my $database_directory = "/db/${database_name}";
my $database_scripts   = "${database_directory}/scripts";

################################################################################
# File variables
################################################################################
my $input_file       = "${input_dir}/input_file.dat";
my $output_file      = "${output_dir}/output_file.dat";
# ... etc

Это прекрасно работает в моих средах разработки, тестирования и производства.Однако я пытался упростить переопределение определенных переменных (не заходя в отладчик) для разработки и тестирования.(Например, если я хочу установить мой input_file = "/tmp/my_input_file.dat").Моя мысль состояла в том, чтобы использовать функцию GetOptions для обработки этого, что-то вроде этого:

GetOptions(
    'input_directory=s'      => \$input_directory,
    'output_directory=s'     => \$output_directory,
    'database_directory=s'   => \$database_directory,
    'log_directory=s'        => \$log_directory,
    'database_scripts=s'     => \$database_scripts,
    'input_file=s'           => \$input_file,
    'output_file=s'          => \$output_file
);

GetOptions можно вызвать только один раз (насколько я знаю).Первые 4 аргумента в моем первом фрагменте обязательны, последние 7 непосредственно выше являются необязательными.Я думаю, идеальной ситуацией было бы установить значения по умолчанию, как в моем первом фрагменте кода, а затем каким-то образом переопределить любые из них, которые были установлены, если аргументы были переданы в командной строке.Я думал о том, чтобы сохранить все мои параметры в хэше, а затем использовать этот хэш при настройке каждой переменной со значением по умолчанию, если в хэше не существует записи, но это, похоже, добавляет много дополнительной логики.Есть ли способ вызвать GetOptions в двух разных местах скрипта?

Не уверен, имеет ли это какой-то смысл.

Спасибо!

Это было полезно?

Решение

Вот еще один подход.Он использует массивы имен и хэш для хранения параметров.Это делает все параметры действительно необязательными, но проверяет требуемые, если вы не включаете "--debug" в командной строке.Независимо от того, используете ли вы "--debug", вы можете переопределить любой из остальных.

Вы могли бы выполнить более явные логические проверки, если это, конечно, важно для вас.Я включил "--debug" в качестве примера того, как опустить базовые параметры, такие как "mount_point", если вы все равно собираетесь переопределить переменные "input_file" и "output_file".

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

use Getopt::Long;

my @required_opts = qw(
    mount_point
    sub_dir
    database_name
    database_schema
);

my @internal_opts = qw(
    input_directory
    output_directory
    log_directory
    database_directory
    database_scripts
    input_file
    output_file
);

my @opt_spec = ("debug", map { "$_:s" } @required_opts, @internal_opts);

# Populate variables from the command line:
GetOptions( \(my %opts), @opt_spec );

# check required options unless 
my @errors = grep { ! exists $opts{$_} } @required_options;
if ( @errors && ! $opts{debug} ) {
    die "$0: missing required option(s): @errors\n";
}

################################################################################
# Directory variables
###############################################################################
my $opts{input_directory}    ||= "/$opts{mount_point}/$opts{sub_dir}/input";
my $opts{output_directory}   ||= "/$opts{mount_point}/$opts{sub_dir}/output";
my $opts{log_directory}      ||= "/$opts{mount_point}/$opts{sub_dir}/log";
my $opts{database_directory} ||= "/db/$opts{database_name}";
my $opts{database_scripts}   ||= "$opts{database_directory}/scripts";

################################################################################
# File variables
################################################################################
my $opts{input_file}    ||= "$opts{input_directory}/input_file.dat";
my $opts{output_file}   ||= "$opts{output_directory}/output_file.dat";
# ... etc

Другие советы

Похоже, вам нужно изменить свою программу, чтобы она использовала файлы конфигурации, а не жестко запрограммированную конфигурацию.Я посвятил целую главу Освоение Perl к этому.Вы не хотите изменять исходный код для тестирования программы.

В CPAN есть много модулей Perl, которые упрощают добавление файлов конфигурации.Выберите тот, который лучше всего подходит для ваших входных данных.

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

Я думаю, что то, что я бы сделал, это установил input_directory и др. до "undef", а затем поместите их в getopts, а затем проверьте, все ли они по-прежнему undef, и если да, назначьте их, как показано.Если ваши пользователи достаточно технически развиты, чтобы понять, "если я указываю относительный путь, он относится к $mount_point/$sub_dir", затем я бы провел дополнительный синтаксический анализ в поисках начальной буквы "/".

GetOptions может быть вызван с использованием массива в качестве входных данных.Прочтите Документация.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top