Перезагрузка модулей и переопределение подпрограмм в Perl - PullRequest
4 голосов
/ 20 июля 2011

Я сейчас экспериментирую с перезагрузкой модуля. Цель, которую я надеюсь достичь, - это иметь возможность изменить что-то в определенной подпрограмме в файле модуля, а затем перезагрузить этот модуль, используя новые определения.

В настоящее время я изменяю оператор print в подпрограмме test для печати «это какой-то другой текст» после ожидания выполнения подпрограммой исходного кода и до перезагрузки модуля.

Однако в настоящее время я получаю сообщение:
Subroutine test redefined at /Test/testmodule.pm line 9.

Это именно то, что я хочу, но вывод выглядит следующим образом.

this is some text
Subroutine test redefined at /Test/testmodule.pm line 9.
this is some text

Я надеюсь, что когда модуль будет перезагружен и он поймет, что подпрограмма была переопределена, он при следующем выполнении подпрограммы test будет ссылаться на новое определение, а не на старое.

Я просматривал предыдущие вопросы о перезагрузке модулей, но были даны такие ответы, как зацикливание зависимостей (пакет A использует B, а B использует A) или столкновение пространства имен в пакетах, но здесь это не проблема. , Я хочу, чтобы подпрограмма была переопределена, и использовалось новое определение.

исходный код: main.pl

#!/usr/bin/perl
use strict;
use warnings;
use Module::Reload::Selective;
use Test::testmodule;

while(1) {
    test(); #run module's define subroutine
    sleep(5); #stop terminal from being flooded too quickly

    #Ensure that the module is reloaded
    $Module::Reload::Selective::Options->{SearchProgramDir} = 1;
    $Module::Reload::Selective::Options->{ReloadOnlyIfEnvVarsSet} = 0;
    Module::Reload::Selective->reload(qw(Test::testmodule)); #reload!
}

исходный код: testmodule.pm ./Test/ относительно main.pl )

#!/usr/bin/perl
use strict;
use warnings;

# allow exportation
require Exporter;
our @ISA = qw(Exporter);
our @EXPORT = qw(test);

sub test {
    print("this is some text\n"); # this line is edited in the source file to
                                  # 'print("this is some different text\n");'
}
1;

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

Все необходимые модули CPAN установлены, и я могу подтвердить, что testmodule.pm успешно записывается после изменения.

OS : Scientific Linux CERN 6, версия ядра 2.6.32-131.4.1.el6.x86_64
Perl : v5.10.1 (*) для x86_64-linux-thread-multi

Большое спасибо заранее,
Оуэн.

Ответы [ 3 ]

4 голосов
/ 20 июля 2011

Я не знаю, является ли это проблемой или нет, но вы пропускаете ваше заявление package в модуле. Это означает, что test это main::test, а не Test::testmodule::test.

Да, это была комбинация ответа cjm и моего. Этот код работает для меня:

В Test/testmodule.pm:

package Test::testmodule;

use strict;
use warnings;

# allow exportation
require Exporter;
our @ISA = qw(Exporter);
our @EXPORT = qw(test);

sub test {
    print "this is some text, counter 1\n";
}

1;

В main.pl:

#!/usr/bin/perl
use strict;
use warnings;
use Module::Reload::Selective;
use Test::testmodule;

while(1) {
    test(); #run module's define subroutine

    my $module = do {
        open my $fh, "<", "Test/testmodule.pm"
            or die "could not open the module: $!";

        local $/;
        <$fh>;
    };

    $module =~ s/counter ([0-9])/"counter " . ($1 + 1)/e;

    open my $fh, ">", "Test/testmodule.pm"
        or die "could not open the module: $!";

    print $fh $module;

    close $fh;

    #Ensure that the module is reloaded
    $Module::Reload::Selective::Options->{SearchProgramDir} = 1;
    $Module::Reload::Selective::Options->{ReloadOnlyIfEnvVarsSet} = 0;
    Module::Reload::Selective->reload(qw(Test::testmodule));
    Test::testmodule->import;
} continue {
    sleep 1;
}

Для пояснения, Perl 5 не создает пространство имен при создании файла .pm. Он создает пространство имен, когда вы говорите package NamespaceName или ссылаетесь на это пространство имен следующим образом

sub Test::testmodule::test {
    print "this is some text, counter 1\n";
}

Поскольку функция test в вашей версии не была в пространстве имен Test::testmodule, она никогда не перезагружалась.

3 голосов
/ 20 июля 2011

Вы пропустили часть Module :: Reload :: Selective документов, в которой говорится, что нужно вызвать import после перезагрузки. (Хотя он использует синтаксис косвенного объекта, лучше использовать стандартный вызов метода.) То есть вы должны были сказать:

Module::Reload::Selective->reload(qw(Test::testmodule)); #reload!
Test::testmodule->import;                                #reimport!

Причина в том, что Экспортер по существу делает:

*main::test = \&Test::testmodule::test;

То есть main::test присваивается ссылка на текущую версию из Test::testmodule::test. Перезагрузка модуля переопределяет Test::testmodule::test, но main::test продолжает ссылаться на исходный саб. Вызов метода import явным образом скопирует новую версию сабвуфера в main::test.

2 голосов
/ 20 июля 2011

Вы можете остановить выдаваемое предупреждение, набрав

no warnings 'redefine';

в загруженный модуль.

Также обратите внимание, что перезагрузка - довольно хрупкая концепция, и она может ограничить то, что вы можете делать в своих модулях.

...