简体   繁体   English

如何在 Perl 脚本中包含所有/一些“子模块”?

[英]How do I include all/some of the "sub modules" in a Perl script?

I'll just start out by saying I am not at all experienced with creating Perl modules so I'm sorry if I'm way off here.我首先要说我对创建 Perl 模块一点经验都没有,所以如果我离开这里,我很抱歉。

Let's say I am creating a few modules:假设我正在创建一些模块:

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

Since I don't know what they are called, I am calling the a.pm and b.pm modules "sub modules" since they are related to the bar.pm module, but could still be somewhat independent.因为我不知道它们叫什么,所以我将 a.pm 和 b.pm 模块称为“子模块”,因为它们与 bar.pm 模块相关,但仍然可以有些独立。

So one of my Perl scripts could use foo::bar::a, another script could use foo::bar::b, and maybe I have another script that needs to use functions from both "a" and "b".所以我的一个 Perl 脚本可以使用 foo::bar::a,另一个脚本可以使用 foo::bar::b,也许我还有另一个脚本需要使用来自“a”和“b”的函数。 Instead of saying this:而不是这样说:

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

I want to do something like this:我想做这样的事情:

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

In my mind, that would give my script access to everything in bar.pm, a.pm, and b.pm.在我看来,这将使我的脚本可以访问 bar.pm、a.pm 和 b.pm 中的所有内容。

I tested something like this, and I was obviously wrong.我测试了这样的东西,我显然错了。

Is something like this possible?这样的事情可能吗? I suppose I could have bar.pm use a.pm and b.pm, and then have "wrapper" functions that pass the call onto the "sub modules" but it seems like there would be an easier way.我想我可以让 bar.pm 使用 a.pm 和 b.pm,然后使用“包装器”函数将调用传递给“子模块”,但似乎有更简单的方法。

Look at my Test::Data module for an example about doing that.查看我的Test::Data模块以获取有关执行此操作的示例。 Even though you can make it happen, I've never been terribly fond of the result.即使你可以让它发生,我从来没有非常喜欢结果。 You might want to consider a Plugin or Mixin approach instead.您可能需要考虑使用 Plugin 或 Mixin 方法。 There are some modules on CPAN that can help with this. CPAN上有一些模块可以帮助解决这个问题。

Here's the custom import that I wrote for Test::Data:这是我为 Test::Data 编写的自定义import

sub import 
    {
    my $self   = shift;
    my $caller = caller;

    foreach my $package ( @_ )
        {
        my $full_package = "Test::Data::$package";
        eval "require $full_package; 1";
        if( $@ )
            {
            carp "Could not require Test::Data::$package: $@";
            }

        $full_package->export($caller);
        }

    }

Yes, you can do that.是的,你可以这样做。 It will probably involve writing a custom 'sub import' in foo::bar that interprets incoming arguments the way you want.它可能涉及在 foo::bar 中编写一个自定义的“子导入”,以您想要的方式解释传入的参数。

Probably you're using Exporter right now, and it's its lack of support for your syntax that's the issue.可能您现在正在使用 Exporter,问题在于它缺乏对您的语法的支持。 You'll find that there's nothing particularly special about the module syntax Exporter implements;您会发现 Exporter 实现的模块语法没有什么特别之处; it's just a common convention.这只是一个共同的约定。 You'll likely want to look at how it does business to get insight into how you'll want to, though.不过,您可能希望查看它的业务运作方式,以深入了解您想要的方式。

If you don't know what a module is called, why are you including it?如果您不知道模块的名称,为什么要包含它? You shouldn't need to include it.您不应该需要包含它。 Only include a module in the (calling) module that needs it, and nowhere else.只在需要它的(调用)模块中包含一个模块,而不在其他地方。

That is: if you are using it, then "use" it.也就是说:如果你正在使用它,那么“使用”它。 If you don't use it, don't "use" it.如果你不使用它,就不要“使用”它。

I have looked for a solution similar to the recent one.我一直在寻找类似于最近的解决方案。 I know - too old thread - but I'd like to comment on the answer ( Feb 12 '09 at 17:55 ) by brian d foy but sadly I don't have enough reputation to accomplish this.我知道 - 太旧的线程 - 但我想对brian d foy的答案(2009 年2 月 12 日 17:55 )发表评论,但遗憾的是我没有足够的声誉来完成这项工作。 That's why I add my comment as a new response.这就是为什么我将我的评论添加为新回复的原因。

His answer has helped me to solve the issue similar to the recent one.他的回答帮助我解决了与最近类似的问题。 But it requires some modification if is used with use lib .但如果与use lib一起use lib则需要进行一些修改。

I have a bunch of modules that look like A::B::* .我有一堆看起来像A::B::*的模块。 Those should be loaded to scripts by the general module A::B .这些应该由通用模块A::B加载到脚本中。 All those modules are within their files under the same directory as the loading script.所有这些模块都在与加载脚本相同的目录下的文件中。 Using the mechanism suggested by brian d foy we can get many subroutine redefined errors .使用brian d foy建议的机制,我们可以得到许多子程序重新定义的错误 To avoid all of them, I believe, I found a better solution, better than no warnings 'redefine' .为了避免所有这些,我相信,我找到了一个更好的解决方案,比no warnings 'redefine' Now we are free to use use lib , no warnings 'redefine' or shift @INC, ... in the main script.现在我们可以自由use lib ,在主脚本中no warnings 'redefine'shift @INC, ...

sub import {
        @TAGS = ( @_ );
        my $me = shift @TAGS;

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

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

            eval "use $module qw(:all)"; # You are free to use any items in the exporting list
            die "$me: Error while loading $module from $_: $@\n" if $@;
        }

        # Fill in @EXPORT_OK and %EXPORT_TAGS manually from each A::B::*::EXPORT_OK
        # ...

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

也试试看Class::MixinFactory

Yes, but you have to rig your own import sub:是的,但您必须装配自己的导入子:

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;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM