代码之家  ›  专栏  ›  技术社区  ›  Robert P

如何创建一个为用户导入多个模块的模块?

  •  4
  • Robert P  · 技术社区  · 14 年前

    我用Perl实现了一个相当复杂的数据结构。这已经被分成大约20个班级。基本上,任何时候你想使用这些类中的一个,你都需要使用它们。

    现在,如果有人想使用此数据结构,他们需要执行以下操作:

    use Component::Root;
    use Component::Foo;
    use Component::Bar;
    use Component::Baz;
    use Component::Flib;
    use Component::Zen;
    use Component::Zen::Foo;
    use Component::Zen::Bar;
    use Component::Zen::Baz;
    ... # 15 more of these...
    use Component::Last;
    

    能够操纵它的所有部分。我怎样才能编写一个模块来为用户实现这一点,所以他们所要做的就是

    use Component;
    

    要导入所有其他模块?

    在这种特殊情况下,模块都是类,没有导出。

    5 回复  |  直到 14 年前
        1
  •  6
  •   cjm    14 年前

    如果这些只是类(即,当您 use

    只是创造 Component.pm :

    package Component;
    
    our $VERSION = '1.00';
    
    use Component::Root;
    use Component::Foo;
    use Component::Bar;
    use Component::Baz;
    use Component::Flib;
    use Component::Zen;
    use Component::Zen::Foo;
    use Component::Zen::Bar;
    use Component::Zen::Baz;
    ... # 15 more of these...
    use Component::Last;
    
    1; # Package return value
    

    Exporter 或者类似的。

    使用 使用 语句放入根节点的类中,或放入创建数据结构的模块中。也就是说,人们会想说:

    use Component::Root;
    my $root = Component::Root->new(...);
    

    use Component qw(build_structure);
    my $root = build_structure(...);
    

    取决于数据结构通常是如何创建的。人们可能会有点困惑:

    use Component;
    my $root = Component::Root->new(...);
    

    但这实际上取决于API的外观。如果有很多人可能会调用 new 那就开始吧 use Component

        2
  •  1
  •   Axeman maxelost    14 年前
    • export_to_level 对于所有那些 Exporter s。

      MyPackage->export_to_level($where_to_export, $package, @what_to_export);
      
    • 也可以只导出导入的所有符号。

      use PackageA qw<Huey Dewey Louie>;
      ...
      our @ISA = qw<Exporter>; #inherit Exporter
      our @EXPORT = qw<Huey Dewey Louie>;
      
    • 出口 任何符号,只想加载模块,然后包括那些 use 上面的语句,以及进程中的任何包都可以将它们实例化为类,比如说它们是否都是OO模块。

      %INC

        3
  •  0
  •   Pedro Silva    14 年前

    Moose::Exporter 似乎做到了这一点,虽然你的所有其他模块将不得不使用它以及。

    Component

    Moose::Exporter->setup_import_methods(
        also => [qw/Component::Root Component::..*/],
    );
    
        4
  •  0
  •   dolmen    14 年前

    如果模块没有导出任何内容,并且没有导入方法(与cjm的答案要求相同),则只需在不导入的情况下加载模块:

    package Component;
    
    our $VERSION = '1.00';
    
    require Component::Root;
    require Component::Foo;
    require Component::Bar;
    require Component::Baz;
    require Component::Flib;
    require Component::Zen;
    require Component::Zen::Foo;
    require Component::Zen::Bar;
    require Component::Zen::Baz;
    ... # 15 more of these...
    require Component::Last;
    
    1; # Package return value
    

    require Component;
    

    但是,如果某些模块执行导出,则必须调用它们的 import 方法 Component

    sub import
    {
        Component::Root->import;
        Component::Foo->import;
        ...
    }
    

    因此模块用户必须 use

    use Component;
    

    请注意,如果导入的模块必须在导入程序的上下文中插入符号,则可能需要使用其他一些技巧。例如,请参见 POE's import 是的。

        5
  •  0
  •   Greg Bacon    14 年前

    Modern::Perl 模块用一个命令启用现代Perl的所有特性,而这个命令就是

    use Modern::Perl;
    

    目前,这只启用strict和warnings pragmas,以及perl5.10中提供的所有特性。它还启用C3方法解析顺序;请参阅perldoc mro以获取解释。

    这对于一行代码来说太多了,根据 perlmod documentation 完全等同于

    BEGIN { require Module; import Module; }
    

    考虑一下Modern::Perl implementation

    package Modern::Perl;
    
    our $VERSION = '1.03';
    
    use 5.010_000;
    
    use strict;
    use warnings;
    
    use mro     ();
    use feature ();
    
    sub import {
        warnings->import();
        strict->import();
        feature->import( ':5.10' );
        mro::set_mro( scalar caller(), 'c3' );
    }
    
    1; # End of Modern::Perl
    

    为了适应你的情况,从你的顶级模块 use 所有其他要加载的模块,并调用它们的导入(如果有的话) MyTopLevelModule::import

    请注意,您不一定需要复制

    use 5.010_000;
    

    MyTopLevelModule.pm ,但这是个好主意!根据 use documentation :

    以奇特的方式 use VERSION 形式, 可以是正小数,例如 5.006 ,这将与 $] v5.6.1 ,这将与 $^V (又名 $PERL_VERSION 大于当前Perl解释器的版本;Perl不会尝试解析文件的其余部分。比较 require