Как использовать Perl в качестве языка для файла конфигурации? - PullRequest
1 голос
/ 17 марта 2019

У меня есть приложение, в котором я хотел бы разрешить пользователям указывать файлы конфигурации в Perl.

То, что я имею в виду, похоже на то, как PKGBUILD используется в Arch: это скрипт Bash, который просто source d из инструмента "makepkg". Содержит определения переменных и функций:

pkgbase=somepkg
pkgname=('somepkg')
pkgver=0.0.1
...
prepare() {
    cd "${srcdir}/${pkgbase}-${pkgver}"
    ...
}

Я бы хотел сделать что-то подобное в Perl. Я предполагаю, что ищу версию Perl source, которая может прочитать файл, оценить его и импортировать все подпрограммы и переменные в пространство имен вызывающей стороны. С версией Bash я мог бы написать PKGBUILD, который использует другой PKGBUILD, а затем переопределяет одну или две переменные; Я хочу, чтобы такого рода «наследование» было возможно и в моих конфигурационных файлах Perl.

Одна проблема с do в Perl состоит в том, что он, кажется, помещает переменные и подпрограммы файла в отдельное пространство имен. Кроме того, я не могу понять, как переопределить истинные подпрограммы, только именованные анонимные.

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

$ cat test-override
#!/usr/bin/perl

use warnings;
use strict;

my @tables = qw(a b c);

my $print_tables = sub {
   print join(", ", @tables), "\n";
};

eval(`cat "test-conf"`) or die "$@";

&$print_tables();

$ cat test-conf
@tables = qw(d e f);

my $old_print_tables = $print_tables;
$print_tables = sub {
  warn "In test-conf \$print_tables\n";
  &$old_print_tables();
}

$ ./test-override
In test-conf $print_tables
d, e, f

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

В документации по "do" упоминается возможность использования Perl в файлах конфигурации, поэтому я знаю, что эта проблема рассматривалась ранее. Есть ли канонический пример того, как сделать это «удобным для пользователя» способом *

1 Ответ

3 голосов
/ 17 марта 2019

Ваше описание того, что вы хотите сделать этим "файлом конфигурации" (импорт подпрограмм и переменных в пространство имен вызывающего, переопределение подпрограмм, классов, наследование ...) звучит подозрительно, как стандартный модуль Perl.Поэтому используйте стандартный модуль Perl.

Обратите внимание, что у этого подхода есть широко распространенный прецедент: стандартный клиент командной строки cpan сохраняет свою конфигурацию в модуле, расположенном по пути по умолчанию ~/.cpan/CPAN/MyConfig.pm on *системы типа nix.Конечно, cpan MyConfig.pm - это очень простой пример, который просто устанавливает хэш-ссылку $CPAN::Config, но нет никаких причин, по которым он не мог бы также делать все остальные вещи, которые делает любой модуль.

Но выполнениеэто с do довольно просто.Я подозреваю, что вы просто переосмыслили это:

$ cat test-override 
#!/usr/bin/perl

use warnings;
use strict;

our @tables = qw(a b c);

sub print_tables {
   print join(", ", @tables), "\n";
};

print_tables;

do "test-conf";

print_tables;

print "\@tables is @tables\n";

$ cat test-conf 
@tables = qw(d e f);

sub print_tables {
  print "print_tables from test_conf\n";
}

$ ./test-override 
a, b, c
print_tables from test_conf
@tables is d e f

Важное изменение, которое я сделал с @tables, состояло в том, чтобы изменить его с my, который виден только в пределах текущей области действия и текущейфайл , до our, который виден где-либо в пределах того же пакета (или из других пакетов, если он содержит имя пакета).

Но мой print_tables из файла конфигурации неНазовите оригинал print_tables, и вам просто не повезло.Поскольку может быть только один &main::print_tables, его замена полностью заменяет исходный, которого больше нет.Если вы хотите иметь возможность переопределить его и по-прежнему иметь возможность вызывать оригинал, вам нужно поместить два объявления в разные пакеты, что подразумевает использование OO Perl (так что вы сможете полиморфически вызывать правильный).

Также обратите внимание, что use имеет ту же лексическую область действия, что и my, что означает, что ваш use strict; use warnings; не не переносится в файл conf.Вы можете легко продемонстрировать это, добавив use warnings; к моей версии test-conf, после чего он выдаст предупреждение Subroutine print_tables redefined.

...