通过 'require' 从模块 'used' 导出子程序

Exporting subroutines from a module 'used' via a 'require'

我正在使用一组编写我们的构建系统的 perl 脚本。不幸的是,它们不是作为一组模块编写的,而是一堆 'require' 彼此的 .pl 文件。

在对几乎所有其他文件都使用的 'LogOutput.pl' 进行一些更改后,我开始遇到一些由于文件被多次 'require'd 而引起的问题。

为了修复此问题,同时不更改每个文件(其中一些不在我的直接控制之下),我执行了以下操作:

-将 LogOutput.pl 中的所有内容移动到一个新文件 LogOutput.pm,这个文件拥有使其成为一个模块所需的一切(基于阅读 http://www.perlmonks.org/?node_id=102347)。

-用下面的

替换现有的LogOutput.pl
BEGIN
{
    use File::Spec;

    push @INC, File::Spec->catfile($BuildScriptsRoot, 'Modules');
}

use COMPANY::LogOutput qw(:DEFAULT);

1;

这有效,除了我需要更改调用代码以在子名称前添加新包(即 COMPANY::LogOutput::OpenLog 而不仅仅是 OpenLog)

我有什么方法可以从 LogOutput.pl 中导出新模块的子程序吗?

名为 Import::Into 的井可用于将模块的符号导出到另一个包中。

use Import::Into;

# As if Some::Package did 'use COMPANY::LogOutput'
COMPANY::LogOutput->import::into("Some::Package");

但是,这应该不是必需的。因为 LogOutput.pl 没有包,所以它的代码在需要它的包中。 use COMPANY::LogOutput 将导出到需要 LogOutput.pl 的包中。您编写的代码应该可以模拟 .pl 文件中的一堆函数。

这是我假设 LogOutput.pl 的样子(使用子例程 "pass" 代替您在其中的任何子例程)...

sub pass { print "pass called\n" }

1;

我假设 LogOutput.pl 和 LogOutput.pm 现在看起来像...

# LogOutput.pl
BEGIN
{
    use File::Spec;

    push @INC, File::Spec->catfile($BuildScriptsRoot, 'Modules');
}

use COMPANY::LogOutput qw(:DEFAULT);

1;


# LogOutput.pm
package test;

use strict;
use warnings;

use Exporter "import";

our @EXPORT_OK = qw(pass);
our %EXPORT_TAGS = (
    ':DEFAULT'    => [qw(pass)],
);

sub pass { print "pass called\n" }

1;

请注意,这不会改变 require 的基本性质。一个模块仍然只需要一次,之后再次需要它是一个空操作。所以这仍然行不通...

{
    package Foo;

    require "test.pl";  # this one will work
    pass();
}

{
    package Bar;

    require "test.pl";  # this is a no-op
    pass();
}

你可以让它发挥作用。 Perl 存储 %INC 中需要的文件列表。如果您删除和输入,Perl 将再次加载该文件。但是,您必须注意 .pl 文件中的所有代码都可以。 @INC 黑客必须确保它只有 运行 一次。

BEGIN
{
    use File::Spec;

    # Only run this code once, no matter how many times this
    # file is loaded.
    push @INC, File::Spec->catfile($BuildScriptsRoot, 'Modules')
        if $LogOutput_pl::only_once++;
}

use COMPANY::LogOutput qw(:DEFAULT);

# Allow this to be required and functions imported more
# than once.
delete $INC{"LogOutput.pl"};

1;

这是为数不多的使用全局变量的情况之一。必须声明词法 (my) 变量,并且会在每次加载库时重置。全局变量不需要声明,并且会在加载之间持续存在。

结果证明这只是我的一个愚蠢错误,我没有将潜艇放入@EXPORT 列表,只放入@EXPORT_OK.