重新加载模块并重新定义Perl中的子例程

时间:2011-07-20 08:58:49

标签: perl perl-module

我正在尝试重新加载模块。我希望实现的目标是能够在模块文件中的已定义子例程中更改某些内容,然后使用新定义重新加载该模块。

目前,在等待子程序执行原始代码之后,以及重新加载模块之前,我正在更改test子程序中的print语句以打印“这是一些不同的文本”。

然而,我现在得到的是这样的信息:
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

我希望当模块重新加载并且它意识到子程序已被重新定义时,下次执行测试子程序时,它将引用新的定义而不是旧定义。 / p>

我已经搜索过以前关于重新加载模块的问题,但给出的答案是循环依赖项(包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

  

操作系统:Scientific Linux CERN 6,内核版本2.6.32-131.4.1.el6.x86_64
   Perl :为x86_64-linux-thread-multi构建的v5.10.1(*)

非常感谢提前,
欧文。

3 个答案:

答案 0 :(得分:4)

我不知道这是不是问题,但你错过了模块中的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;
}

为了澄清,在创建.pm文件时,Perl 5不会创建命名空间。当您说package NamespaceName或者像这样引用该命名空间时,它会创建一个命名空间

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

由于您的版本中的test函数不在Test::testmodule命名空间中,因此它从未重新加载。

答案 1 :(得分:3)

您错过了Module::Reload::Selective文档中重新加载后调用import的部分内容。 (虽然它使用间接对象语法,但最好使用标准方法调用。)也就是说,你应该说:

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

原因是Exporter基本上做了:

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

也就是说,main::test被分配了对Test::testmodule::test当前版本的引用。重新加载模块重新定义Test::testmodule::test,但main::test继续引用原始子。明确调用import方法会将新版本的子副本复制到main::test

答案 2 :(得分:2)

您可以通过添加

来停止发出警告
no warnings 'redefine';

进入加载模块。

另请注意,重新加载是非常脆弱的概念,它可能会限制您在模块中可以执行的操作。