Как передать параметры в подпрограммы Perl, определенные с помощью eval? - PullRequest
4 голосов
/ 19 января 2010

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

---
action: >
        use List::MoreUtils;
        my $value = $_;
        any { $value eq $_ } qw(fatal keep merge non-fatal replace);
dir   : return defined $_ ? -d $_ : -1;
file  : return defined $_ ? -f $_ : -1;
string: 1;


---
config-element:
    value: foo
    type : file
etc ...

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

#throw sub refs into hash
my %type_sub;
foreach my $key (keys %$type_def_ref) {
    my $sub_str = "sub {$type_def_ref->{$key}}";
    $type_sub{$key} = eval $sub_str;

}

#validate (myfile is a real file in the cwd)
print $type_sub{file}->('myfile'),"\n";
print $type_sub{action}->('fatal'), "\n";

Проблема в том, что подпрограммы в% type_sub, похоже, не принимают параметры. В вышеприведенном случае первый оператор вывода выдает -1, а второй выводит:

Use of uninitialized value $value in string eq at (eval 15) line 1.
Use of uninitialized value $_ in string eq at (eval 15) line 1.
Can't call method "any" without a package or object reference at 
(eval 15) line 1.

что совсем не то, что я ожидаю, но подпрограммы называются.

Что я делаю не так?

EDIT: Я был небрежным, и теперь все работает нормально. Спасибо Фридо.

Ответы [ 2 ]

5 голосов
/ 19 января 2010

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

Об этом подробно говорится в главе «Конфигурация» в Мастеринг Perl , а также в главах о динамических подпрограммах.

Код не входит в конфигурацию. Скажи это, пока не поверишь.

3 голосов
/ 19 января 2010

Параметры вашей подпрограммы будут в массиве @_, а не $_.Чтобы получить первый параметр, посмотрите в $_[0] или выполните my $foo = shift;.(shift работает на @_ по умолчанию.)

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

any( sub { $value eq $_ }, qw(fatal keep merge non-fatal replace) );
...