Как я могу уменьшить дублирование в константах?
-
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
);
}
Делая это таким образом, я могу легко расширять или переопределять вещи. Р>
При этом теряется значение постоянного сворачивания, поэтому вам нужно подумать о том, насколько это важно для вас.