Разделение данных конфигурации и логики скрипта в скриптах Perl - PullRequest
9 голосов
/ 04 марта 2010

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

#!/usr/bin/perl

use strict;
use warnings;

# machine specific settings at the start of the script.
my $SETTING_1 = "foo";
my @SETTING_2 = ("123", "456");
my $SETTING_3 = "something";

# general part of script follows.
...

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

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

Мой вопрос: Какой модуль CPAN вы бы порекомендовали для решения этой проблемы? Почему?

Ответы [ 8 ]

7 голосов
/ 04 марта 2010

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

4 голосов
/ 04 марта 2010

Мой любимый Config :: Std . Мне нравится способ обработки значений конфигурации multi-line и multi-part .

Вы должны быть осторожны, когда переменная потенциально многозначна: если в файле конфигурации существует одно значение, оно сохранит значение в скаляре; если существует несколько значений, вы получите ссылку на массив.

Мне удобно иметь два файла конфигурации: один для значений, которые описывают операционную среду (где искать библиотеки и т. Д.), А другой для изменяемого пользователем поведения.

Мне также нравится писать обертку вокруг него. Например (обновлено, чтобы включить автоматически созданные средства доступа только для чтения):

#!/usr/bin/perl

package My::Config;
use strict; use warnings;

use Config::Std;
use FindBin qw($Bin);
use File::Spec::Functions qw( catfile );

sub new {
    my $class = shift;
    my ($config_file) = @_;

    $config_file = catfile($Bin, 'config.ini');
    read_config $config_file => my %config;

    my $object = bless \%config => $class;

    $object->gen_accessors(
        single => {
            install => [ qw( root ) ],
        },
        multi => {
            template => [ qw( dir ) ],
        },
    );

    return $object;
}

sub gen_accessors {
    my $config = shift;
    my %args = @_;

    my $class = ref $config;

    {
        no strict 'refs';
        for my $section ( keys %{ $args{single} } ) {
            my @vars = @{ $args{single}->{$section} };
            for my $var ( @vars ) {
                *{ "${class}::${section}_${var}" } = sub {
                    $config->{$section}{$var};
                };
            }
        }

        for my $section ( keys %{ $args{multi} } ) {
            my @vars = @{ $args{multi}->{$section} };
            for my $var ( @vars ) {
                *{ "${class}::${section}_${var}" } = sub {
                    my $val = $config->{$section}{$var};
                    return [ $val ] unless 'ARRAY' eq ref $val;
                    return $val;
                }
            }
        }
    }

    return;
}

package main;

use strict; use warnings;

my $config = My::Config->new;

use Data::Dumper;
print Dumper($config->install_root, $config->template_dir);
C:\Temp> cat config.ini
[install]
root = c:\opt

[template]
dir = C:\opt\app\tmpl
dir = C:\opt\common\tmpl

Выход:

C:\Temp> g.pl
$VAR1 = 'c:\\opt';
$VAR2 = [
          'C:\\opt\\app\\tmpl',
          'C:\\opt\\common\\tmpl'
        ];
2 голосов
/ 04 марта 2010

Библиотека Config: Properties удобна для чтения и записи файлов свойств ключ / значение.

2 голосов
/ 04 марта 2010

Я предпочитаю YAML и YAML :: XS для данных конфигурации. Это просто, доступно для чтения и имеет привязки практически для любого языка программирования. Другой популярный выбор - Config :: General .

1 голос
/ 05 марта 2010

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

Сначала напишите структуру данных Perl, содержащую вашу конфигурацию.

use YAML;

my $SETTINGS = {
    '1' => "foo",
    '2' => ["123", "456"],
    '3' => "something",
};

Затем передайте его в YAML :: DumpFile ();

YAML::DumpFile("~/.$appname.yaml", $SETTINGS);

Удалить структуру данных и заменить ее на

my $SETTINGS = YAML::LoadFile("~/.$appname.yaml");

А потом забудь об этом. Даже если вы не знаете или не хотите изучать синтаксис YAML, небольшие изменения в конфигурации могут быть сделаны вручную, а более важные можно выполнить в Perl, а затем повторно вывести в YAML.

1 голос
/ 05 марта 2010

Во избежание смеха вне класса, одним из решений является сохранение конфигурации в XML (или, для более приключенческого, JSON). Потребляемый человеком, совместимый вне Perl, не должен жить на локальном ПК (XML и JSON могут быть запрошены из «config URL») и нескольких стандартных модулей (XML :: Simple обычно достаточно для XML-файлы конфигурации) существуют в CPAN.

1 голос
/ 04 марта 2010

Обычный низкотехнологичный метод - просто сделать EXPR файл конфигурации. Вы смотрели на это?

0 голосов
/ 05 марта 2010

Не привязывайте себя к формату - используйте Config :: Any или, если хотите, немного больше, чем DWIM-коэффициент, Config :: JFDI (который включает в себя Config: :Любой). С их помощью вы приобретаете возможность поддержки INI, YAML, XML, конфигурации в стиле Apache и т. Д.

Config :: JFDI основывается на этом, пытаясь уловить часть волшебства загрузчика конфигурации Catalyst: объединение конфигурации локального экземпляра с конфигурацией всего приложения, поддержка переменных среды и ограниченная возможность макросов (__path_to(foo/bar)__ входит в удобно на удивление часто.)

...