gorynlexx (gorynlexx) wrote in ru_perl,
gorynlexx
gorynlexx
ru_perl

Использование модуля с генерируемым "на лету" именем.

Задача такая. Есть ряд модулей, каждый в отдельном PM-файле. Внутри модулей хранится хэш с данными, имя хэша во всех модулях одинаковое %Hash. Причем одновременно может быть загружен не один модуль.
Имена модулей имеют вид
Module_aaa.pm
Module_bbb.pm
Module_ccc.pm
...
В текущий момент я знаю. что мне нужно взять данные из модуля 'aaa' или 'ccc'. С помощью Module::Load я могу загрузить только нужные мне в текущий запуск скрипта модули. Но как мне обратиться к нужному модулю по ключу? Понятно, что напрашивается куча тернарников вида

$value = $key='aaa' ? $Module_aaa::Hash{key} : $key='bbb' ? $Module_bbb::Hash{key} :$key='ccc' ? $Module_ccc::Hash{key} : '';

Но ведь наверняка есть способ сделать это через генерацию имени для обращения. Подскажите пожалуйста, как такое лучше организовать.

Если знаете, подскажите также вариант для случая, если модуль один, а данные хранятся в нем в хэшах %Hash_aaa, %Hash_bbb и т.д.

P.S. Вариант использовать один сложных хэшей с ключами aaa, bbb, и т.д. очевиден, но тут надо в идеале, чтобы они были разнесены по разным файлам модулей с точки зрения архитектуры проекта.

Subscribe
  • Post a new comment

    Error

    default userpic

    Your reply will be screened

    Your IP address will be recorded 

    When you submit the form an invisible reCAPTCHA check will be performed.
    You must follow the Privacy Policy and Google Terms of use.
  • 14 comments
Используйте eval.

$value=eval '$Module_'.${key}.'::Hash{otherkey};'

Для варианта, когда модуль один, а имена хэшей формируются динамически, ответ будет тот же.
За такое использование eval надо.... обижаться. perldoc perlmod, конкретно - Symbol tables
$ perl -MB -le 'no strict; $_=q(B); print ${$_ . '::VERSION'}'
1.42_02

infist_xxi

February 3 2017, 15:06:40 UTC 1 year ago Edited:  February 3 2017, 15:07:50 UTC

Как-то так?

package A;
our %H = ( 'key' => 'A' );
1;

package D;
our %H = ( 'key' => 'D' );
1;

--- run.pl ---

print &get_from( 'A', 'key' ), "\n";
print &get_from( 'D', 'key' ), "\n";
print &get_from( 'A', 'key' ), "\n";

sub get_from(@) {
    my $module = shift || '';
    my $key = shift || '';
    if ( $module and $key ) {
        require "$module.pm";
        my $h = \%{*{$module.'::'.'H'}{HASH}};
        return $h->{$key};
    }
    return;
}
Большое спасибо, воспользовался вашим методом. Попробовать вытащить через typeglob сам не догадался.
Один раз сохранить где-нибудь указатели на нужное в удобном формате и потом по ним обращаться. У перла нет сборки мусора ;-)

lodin

February 3 2017, 22:44:34 UTC 1 year ago Edited:  February 3 2017, 22:45:14 UTC

use strict;
use warnings;
use Module::Load;
use Test::More;

my $module_name = 'Module_bbb';


Вариант 1: no strict.

my $value = do {
    load $module_name;
    no strict 'refs';
    ${ $module_name .'::'. 'Hash' }{key};
};
is ($value, 42, "type 1 works");


Вариант 2. Сделать функцию для доставания интересующих значений из хэша.

is (get_value($module_name, 'key'), 42, "type 2 works");
sub get_value {
    my ($module, $key) = @_;
    load $module;
    no strict 'refs';
    return ${ $module.'::'. 'Hash' }{key};
};


Вариант 3. "Выдать" всем модулям метод, идентичный варианту 2, и вызывать через стрелочку:

{
    package Module_bbb;
    use parent qw(Module_base);
};

is ($module_name->get_value('key'), 42, "type 3 works");

done_testing;


# Module_base.pm
package Module_base;

use strict;
use warnings;

sub get_value {
    my ($self, $key) = @_;

    no strict 'refs';
    return ${ $self .'::'. 'Hash' }{key};    
};

1;


По-моему, так (с)
процентов на 90, если вам нужны "модуля с генерируемым "на лету" именем", то что-то не то и в филармонии и с дизайном программы.
Ага. Конфиги можно в YAML-е хранить, например.
А по делу?
Это было по делу: автор, по ходу, хочет конфиги на perl-е, я скорее согласен с Вами, что так не надо.
Пардон, я не много не так понял, обидеть не хотел. ))

Мне "повезло" и я в своей жизни имел удовольствие поработать с генерацией кода на лету и/или при старте приложухи. Сам даже руки прикладывал. Отладка такого кода полный пипец, особенно когда генерятся и используются анонимные сабы. И теперь у меня просто нервная реакция, когда кто предлагает или хочет сделать такое.
Конфиги можно держать в формате данных через запятую (как список) и потом их читать из файла с помощью do.

my %opts = do 'app.conf' ;
То, что на похапе такой код пишется легко и непринужденно, еще не значит, что так надо писать в принципе.
Так не надо писать. Это уродство.