Программист решил написать класс для работы с файлами конфигураций. Готов первый прототип: можно загружать и записывать yaml-файлы, читать и менять отдельные значения.
use strict;
use warnings;
package Config;
use YAML;
sub load
{
my ($class, %param) = @_;
my $conf;
if ( $param{file} =~ /\.yaml$/ ){
print $param{file}."\n";
$conf->{data} = YAML::LoadFile( $param{file} );
$conf->{format} = "yaml";
$conf->{file} = $param{file};
} else {
die "unsupported format of config, stop";
}
return bless $conf;
}
sub write
{
my ($self, %param) = @_;
YAML::DumpFile($param{file}, $self->{data});
return;
}
sub get
{
my ($self, $key) = @_;
return $self->{data}->{$key};
}
sub set
{
my ($self, $key, $value) = @_;
$self->{data}->{$key} = $value;
return;
}
1;
Программист решил протестировать, что получается:
#!/usr/bin/perl
use strict;
use warnings;
use Config;
my $conf = Config->load(file => "conf.yaml");
my $parallel_level = $conf->get("parallel-level");
$conf->set("parallel-level", $parallel_level * 2);
$conf->write(file => "conf2.yaml");
Но скрипт не заработал. Совсем.
Почему?
Можно скачать исходный код: модуль Config.pm, скрипт script.pl, пример данных conf.yaml.
Например, на компьютере одного из авторов скрипт завершается с сообщением
Goto undefined subroutine &Config::load at /usr/lib/perl/5.14/Config_heavy.pl line 1361.
Впрочем, если переместить файл Config.pm в другой каталог
и подключить его с помщью use lib
, скрипт начинает работать.
Дело в том, что в стандартной поставке perl с 1996 года присутствует модуль Config
,
предназначенный для чтения конфигурационных переменных perl’а.
Текущий каталог (.
) находится в самом конце массива @INC
,
поэтому при загрузке модуля через use Config
perl находит стандартный модуль
раньше, чем модуль из текущего каталога.
Изменить порядок поиска модулей можно с помощью прагмы lib
.
Результатом use lib
является добавление каталога в начало
массива @INC
, поэтому модули оттуда будут находиться раньше стандартных.
Тем не менее, во избежание неприятных сюрпризов лучше не давать своим модулям имена, уже занятые стандартной поставкой или популярными модулями с CPAN.
Примечания
Историю модуля Config в разных версиях perl см., например, здесь. Кстати, посмотрите и на остальные стандартные модули.
Смотрим порядок обхода каталогов при загрузке модулей:
> perl -le 'use lib "/tmp"; print join "\n", @INC'
/tmp
/etc/perl
/usr/local/lib/perl/5.14.2
/usr/local/share/perl/5.14.2
/usr/lib/perl5
/usr/share/perl5
/usr/lib/perl/5.14
/usr/share/perl/5.14
/usr/local/lib/site_perl
.
К слову, use lib "/some/dir"
– это практически то же самое,
что BEGIN { unshift(@INC, "/some/dir") }
. О небольшой разнице см.
perldoc lib.
Также признаемся, что на составление этой задачи нас вдохновил топик на StackOverflow: What is the error in this object oriented program?.