2009-02-12 89 views
4

我刚开始说我对创建Perl模块一点经验都没有,所以我很抱歉如果我不在这里。如何在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 。下午。

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

是这样的可能吗?我想我可以有bar.pm使用a.pm和b.pm,然后有“包装”功能将呼叫传递到“子模块”,但似乎会有更简单的方法。

回答

5

查找有关这样做的例子。尽管你可以做到这一点,但我从来不喜欢这个结果。您可能需要考虑插件或Mixin方法。 CPAN上有一些模块可以帮助解决这个问题。

这里的风俗import我所写的Test ::数据:

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

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

     $full_package->export($caller); 
     } 

    } 
2

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

可能您现在正在使用Exporter,并且它缺少对您的语法支持的问题。您会发现Exporter实现的模块语法没有特别的特殊之处;这只是一个常见的惯例。不过,你可能会想看看它是如何做生意的,以便洞察你的想法。

+0

是的,我使用的是出口商。好点 - 我确定我的语法不正确 - 我不是故意将责任归于出口模块。 – BrianH 2009-02-12 17:42:28

+0

我不是故意说你做错了什么。我的意思是说你正在做的是(可能)在出口商的范围/任务之外,并且需要你自己的实施。 (虽然你也许应该仔细阅读出口商的文档,也许可以教这样做。) – chaos 2009-02-12 17:46:17

+0

哦,没问题。我查看了出口商的文档,发现了EXPORT_TAGS,这是我以为会这样 - 但我无法让它正常工作 – BrianH 2009-02-12 17:52:20

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; 
1

如果你不知道什么一个模块被调用,你为什么包括它?你不需要包含它。只需要在需要它的(调用)模块中包含一个模块,而无需其他地方。

即:如果您正在使用它,然后“使用”它。如果你不使用它,不要“使用”它。

0

我已经寻找类似于最近的解决方案。我知道 - 太老线程,但我想评论答案(09年2月12日在17:55布莱恩d福伊但可悲的是我没有足够的声誉来完成这一点。这就是为什么我添加我的评论作为新的回应。

他的回答帮助我解决了类似于最近的问题。但是,如果与use lib一起使用,则需要进行一些修改。

我有一堆看起来像A::B::*的模块。这些应该由通用模块A::B加载到脚本中。所有这些模块都位于与加载脚本相同的目录下的文件中。使用brian d foy建议的机制,我们可以得到许多子程序重新定义了错误。为了避免所有这些,我相信,我找到了更好的解决方案,比no warnings 'redefine'更好。现在我们可以在主脚本中自由使用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 $_: [email protected]\n" if [email protected]; 
     } 

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

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