【问题标题】:Reloading modules and redefining subroutines in Perl在 Perl 中重新加载模块和重新定义子例程
【发布时间】:2011-07-20 08:58:49
【问题描述】:

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

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

但是,我目前收到的是消息:
Subroutine test redefined at /Test/testmodule.pm line 9.

这正是我想要的,但是输出如下。

这是一些文字
在 /Test/testmodule.pm 第 9 行重新定义了子程序测试。
这是一些文字

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

我已经搜索过有关重新加载模块的先前问题,但给出的答案是循环依赖项(包 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:v5.10.1 (*) 专为x86_64-linux-thread-multi

非常感谢,
欧文。

【问题讨论】:

  • 什么新定义?您正在重新加载相同的子程序,得到相同的输出。
  • 感谢您的发帖。在第二段中,我提到我更改了 testmodule.pm 中的一行源代码。我应该编辑帖子以使其更加明确。感谢您提请我注意。

标签: perl perl-module


【解决方案1】:

我不知道这是否是问题所在,但您在模块中缺少package 语句。这意味着testmain::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 命名空间中,因此它从未被重新加载。

【讨论】:

  • 啊,我忘记了包装声明...总是在一天结束时对我来说真的很简单...不过谢谢您的回答,这很有帮助很多。编辑:当我直接修改文件而不是通过代码修改文件时,它也可以工作。非常感谢您(和 cjm)的帮助!
【解决方案2】:

您错过了 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 方法会将新版本的sub 复制到main::test

【讨论】:

  • 非常感谢您的回答。虽然很有希望,但不幸的是,重新导入似乎没有任何区别。也许它与新重新导入的子程序的范围错误有关? IE。子例程只能作用于while 块而不是整个文件?
【解决方案3】:

您可以通过放置来停止发出警告

no warnings 'redefine';

进入加载的模块。

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

【讨论】:

  • 感谢您的意见。但是,警告不是我遇到的问题。问题在于使用子例程的新定义。
猜你喜欢
  • 2011-03-26
  • 2011-07-18
  • 1970-01-01
  • 2012-10-19
  • 2011-07-03
  • 1970-01-01
  • 2014-09-03
  • 2019-03-14
  • 2015-02-07
相关资源
最近更新 更多