Как я могу уменьшить дублирование в константах?

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

  •  04-07-2019
  •  | 
  •  

Вопрос

У меня есть этот Perl-скрипт со многими определенными константами конфигурационных файлов. Например:

use constant  {
LOG_DIR                             => "/var/log/",
LOG_FILENAME                        => "/var/log/file1.log",
LOG4PERL_CONF_FILE                  => "/etc/app1/log4perl.conf",
CONF_FILE1                          => "/etc/app1/config1.xml",
CONF_FILE2                          => "/etc/app1/config2.xml",
CONF_FILE3                          => "/etc/app1/config3.xml",
CONF_FILE4                          => "/etc/app1/config4.xml",
CONF_FILE5                          => "/etc/app1/config5.xml",
};

Я хочу уменьшить дублирование файла / etc / app1 " и " / var / log " , но использование переменных не работает. Также использование ранее определенных констант не работает в том же «использовать константный блок». Например:

use constant {
LOG_DIR                             => "/var/log/",
FILE_FILENAME                       => LOG_DIR . "file1.log" 
};

не работает.

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

Как правильно это сделать?

Спасибо.

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

Решение

Я бы, наверное, написал это так:

use Readonly;

Readonly my $LOG_DIR            => "/var/log";
Readonly my $LOG_FILENAME       => "$LOG_DIR/file1.log";
Readonly my $ETC                => '/etc/app1';
Readonly my $LOG4PERL_CONF_FILE => "$ETC/log4perl.con";

# hash because we don't have an index '0'
Readonly my %CONF_FILES => map { 

Я бы, наверное, написал это так:

<*>

Тем не менее, это все еще много кода, но он удаляет дублирование, и это выигрыш.

Почему ваши лог-файлы являются числовыми? Если они начинаются с 0, массив является лучшим выбором, чем хеш. Если они названы, они более наглядны.

=> "$ETC/config

Я бы, наверное, написал это так:

<*>

Тем не менее, это все еще много кода, но он удаляет дублирование, и это выигрыш.

Почему ваши лог-файлы являются числовыми? Если они начинаются с 0, массив является лучшим выбором, чем хеш. Если они названы, они более наглядны.

.xml" } 1 .. 5;

Тем не менее, это все еще много кода, но он удаляет дублирование, и это выигрыш.

Почему ваши лог-файлы являются числовыми? Если они начинаются с 0, массив является лучшим выбором, чем хеш. Если они названы, они более наглядны.

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

  

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

Это правда?

use constant BASE_PATH => "/etc/app1";

use constant  {
    LOG4PERL_CONF_FILE                  => BASE_PATH . "/log4perl.conf",
    CONF_FILE1                          => BASE_PATH . "/config1.xml",
    CONF_FILE2                          => BASE_PATH . "/config2.xml",
    CONF_FILE3                          => BASE_PATH . "/config3.xml",
    CONF_FILE4                          => BASE_PATH . "/config4.xml",
    CONF_FILE5                          => BASE_PATH . "/config5.xml",
};

Я не вижу много проблем с этим. Вы указали базовый путь только в одной точке, тем самым соблюдая принцип СУХОЙ. Если вы назначите BASE_PATH с переменной среды:

use constant BASE_PATH => $ENV{MY_BASE_PATH} || "/etc/app1";

... тогда у вас есть дешевый способ перенастроить свою константу без необходимости редактировать код. Что тут не нравится в этом?

Если вы действительно хотите сократить количество повторяющихся " BASE_PATH. & Quot; конкатенация, вы можете добавить немного машин для самостоятельной установки констант и их устранения:

use strict;
use warnings;

use constant BASE_PATH => $ENV{MY_PATH} || '/etc/apps';

BEGIN {
    my %conf = (
        FILE1 => "/config1.xml",
        FILE2 => "/config2.xml",
    );

    for my $constant (keys %conf) {
        no strict 'refs';
        *{__PACKAGE__ . "::CONF_$constant"}
            = sub () {BASE_PATH . "$conf{$constant}"};
    }
}

print "Config is ", CONF_FILE1, ".\n";

Но на данный момент я думаю, что баланс переместился с правильного на неприятный :) Для начала, вы больше не можете использовать grep для CONF_FILE1 и посмотреть, где он определен.

use constant +{
    map { sprintf <*>, '/var/log' } (
        LOG_DIR            => "%s/",
        LOG_FILENAME       => "%s/file1.log",
    ),
    map { sprintf <*>, '/etc/app1' } (
        LOG4PERL_CONF_FILE => "%s/log4perl.conf",
        CONF_FILE1         => "%s/config1.xml",
        CONF_FILE2         => "%s/config2.xml",
        CONF_FILE3         => "%s/config3.xml",
        CONF_FILE4         => "%s/config4.xml",
        CONF_FILE5         => "%s/config5.xml",
    ),
};

К сожалению, это не сработает. Причина этого в том, что вы используете функции («константы») до того, как они определены. Вы оцениваете их перед вызовом constant-> gt; import .

Использование переменных не работает, потому что операторы use оцениваются во время компиляции. Присвоение переменных выполняется только во время выполнения, поэтому они еще не определены.

Единственное решение, которое я могу дать, - разделить его на несколько операторов use constant . В этом случае подойдут два оператора (один для LOG_DIR и CONF_DIR , другой для остальных).

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

 sub base_log_dir { '...' }

 sub get_log_file
      {
      my( $self, $number ) = @_;

      my $log_file = catfile( 
        $self->base_log_dir, 
        sprintf "foo%03d", $number
        );
      }

Делая это таким образом, я могу легко расширять или переопределять вещи.

При этом теряется значение постоянного сворачивания, поэтому вам нужно подумать о том, насколько это важно для вас.

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