4

我首先要说我在创建 Perl 模块方面一点经验都没有,所以如果我离开这里,我很抱歉。

假设我正在创建一些模块:

foo::bar
foo::bar::a
foo::bar::b

因为我不知道它们叫什么,所以我将 a.pm 和 b.pm 模块称为“子模块”,因为它们与 bar.pm 模块相关,但仍然可能有些独立。

所以我的一个 Perl 脚本可以使用 foo::bar::a,另一个脚本可以使用 foo::bar::b,也许我还有另一个脚本需要使用“a”和“b”中的函数。而不是这样说:

use foo::bar;
use foo::bar::a qw(one two);
use foo::bar::b;

我想做这样的事情:

use foo::bar qw(:a :b);

在我看来,这将使我的脚本可以访问 bar.pm、a.pm 和 b.pm 中的所有内容。

我测试了这样的东西,我显然错了。

这样的事情可能吗?我想我可以让 bar.pm 使用 a.pm 和 b.pm,然后使用“包装器”函数将调用传递给“子模块”,但似乎会有更简单的方法。

4

6 回答 6

5

查看我的Test::Data模块以获取有关执行此操作的示例。即使你可以做到这一点,我从来没有非常喜欢这个结果。您可能需要考虑使用插件或 Mixin 方法。CPAN上有一些模块可以帮助解决这个问题。

import是我为 Test::Data 编写的自定义:

子导入
    {
    我的 $self = 班次;
    我的 $caller = 来电者;

    foreach 我的 $package (@_)
        {
        我的 $full_package = "Test::Data::$package";
        eval "需要 $full_package; 1";
        如果($@)
            {
            carp "不能要求 Test::Data::$package: $@";
            }

        $full_package->export($caller);
        }

    }
于 2009-02-12T17:55:39.253 回答
2

是的,你可以这么做。它可能涉及在 foo::bar 中编写自定义的“子导入”,以您想要的方式解释传入的参数。

可能您现在正在使用 Exporter,问题在于它不支持您的语法。您会发现 Exporter 实现的模块语法没有什么特别之处;这只是一个常见的约定。不过,您可能想看看它是如何开展业务的,以深入了解您想要的方式。

于 2009-02-12T17:37:19.640 回答
1

如果你不知道一个模块叫什么,你为什么要包括它?您不需要包含它。仅在需要它的(调用)模块中包含一个模块,而不是其他任何地方。

那就是:如果你正在使用它,那么“使用”它。如果您不使用它,请不要“使用”它。

于 2009-02-12T19:03:35.547 回答
0

还可以尝试查看Class::MixinFactory

于 2009-02-12T17:52:18.620 回答
0

是的,但是您必须安装自己的导入子:

use strict;
use warnings;

package ab;
use base qw<Exporter>;
our @EXPORT_OK;
our %EXPORT_TAGS;
BEGIN { 
    @EXPORT_OK   = qw<>;
    %EXPORT_TAGS = ( a => 1, b => 1, all => \@EXPORT_OK );
}

sub setup_part { 
    #use Smart::Comments;
    my $code = shift;
    my $mini_path = "foo/bar/$code.pm";
    return if exists $INC{$mini_path};
    require $mini_path; 
    my $arr_ref 
        = do { no strict 'refs';
            \@{Symbol::qualify( 'EXPORT_OK', $code )};
        };
    $code->import( @$arr_ref );
    push @EXPORT_OK, @$arr_ref;
    $EXPORT_TAGS{$code} = [ @$arr_ref ];
    return;
}

sub import { 
    my ( $package_name, @imports ) = @_;
    my %import_hash = map { $_ => 1 } @imports;
    if ( exists $import_hash{':all'} ) { 
        @import_hash{qw<:a :b>} = ( 1, 1 );
    }
    foreach my $import ( grep { exists $import_hash{$_} } qw<:a :b> ) { 
        setup_part( substr( $import, 1 ));
    }
    goto &{Exporter->can( 'import' )};
}

1;
于 2009-02-12T18:18:24.377 回答
0

我一直在寻找类似于最近的解决方案。我知道 - 太旧的线程 - 但我想评论brian d foy的答案(2009年 2 月 12 日 17:55),但遗憾的是我没有足够的声誉来完成这个。这就是为什么我将我的评论添加为新的回复。

他的回答帮助我解决了与最近类似的问题。但如果与use lib.

我有一堆看起来像A::B::*. 这些应该由通用模块加载到脚本中A::B。所有这些模块都在加载脚本所在目录下的文件中。使用brian d foy建议的机制,我们可以得到许多子程序重新定义的错误。为了避免所有这些,我相信,我找到了一个更好的解决方案,比no warnings 'redefine'. 现在我们可以自由使用use libno warnings 'redefine'或者shift @INC, ...在主脚本中。

    子导入{
        @TAGS = (@_);
        我的 $me = shift @TAGS;

        (我的 $pm = $me) =~ s|::|/|g;
        $pm .= ".pm";

        ( $dir = $INC{$pm} ) =~ s/\.pm$//;
        foreach ( glob "$dir/*.pm" ) {
            /(\w+)\.pm$/;
            我的 $module = "${me}::$1";

            eval "使用 $module qw(:all)"; # 您可以自由使用导出列表中的任何项目
            die "$me: Error while loading $module from $_: $@\n" if $@;
        }

        # 从每个 A::B::*::EXPORT_OK 手动填写 @EXPORT_OK 和 %EXPORT_TAGS
        # ...

        转到 &{ Exporter->can( "import" ) };
    }

于 2014-04-09T06:42:44.567 回答