如何使用仅在运行时知道的Perl包?

时间:2021-05-15 03:12:53

I have a Perl program, that needs to use packages (that I also write). Some of those packages are only chosen in Runtime (based on some environment variable). I don't want to put in my code a "use" line for all of those packages, of course, but only one "use" line, based on this variable, something like:

我有一个Perl程序,需要使用包(我也写)。其中一些软件包仅在运行时选择(基于某些环境变量)。当然,我不想在我的代码中为所有这些包添加“使用”行,但只有一个“使用”行,基于此变量,如下所示:

use $ENV{a};

Unfortunately, this doesn't work, of course. Any ideas on how to do this?

不幸的是,这当然不起作用。关于如何做到这一点的任何想法?

Thanks in advance, Oren

提前谢谢,奥伦

7 个解决方案

#1


8  

eval "require $ENV{a}";

"use" doesn't work well here because it only imports in the context of the eval.

“use”在这里不能很好地工作,因为它只在eval的上下文中导入。

As @Manni said, actually, it's better to use require. Quoting from man perlfunc:

正如@Manni所说,实际上,最好使用require。引自man perlfunc:

If EXPR is a bareword, the require assumes a ".pm" extension and 
replaces "::" with "/" in the filename for you, to make it easy to 
load standard modules.  This form of  loading of modules does not 
risk altering your namespace.

In other words, if you try this:

        require Foo::Bar;    # a splendid bareword

The require function will actually look for the "Foo/Bar.pm" file 
in the directories specified in the @INC array.

But if you try this:

        $class = 'Foo::Bar';
        require $class;      # $class is not a bareword
    #or
        require "Foo::Bar";  # not a bareword because of the ""

The require function will look for the "Foo::Bar" file in the @INC 
array and will complain about not finding "Foo::Bar" there.  In this 
case you can do:

        eval "require $class";

#2


8  

"use" Statements are run at compilation time, not at run time. You will need to require your modules instead:

“use”语句在编译时运行,而不是在运行时运行。您需要改为使用模块:

my $module = "Foo::Bar";
eval "require $module";

#3


6  

I would use UNIVERSAL::require. It has both require and use methods to use a package. The use method will also call import for the package.

我会使用UNIVERSAL :: require。它既有要求也有使用方法来使用包。 use方法也会调用包的import。

use UNIVERSAL::require;
$ENV{a}->use or die 'Could not import package:  ' . $@;

#4


4  

You probably want to use require instead of use if you don't want it to happen at compile time, and then manually import any symbols you might need. See this link to the Perl Cookbook (from Google Books) for a good discussion of methods you can use to achieve what you want.

如果您不希望它在编译时发生,您可能希望使用require而不是use,然后手动导入您可能需要的任何符号。有关可用于实现所需方法的详细讨论,请参阅Perl Cookbook(来自Google Books)的链接。

#5


4  

I think that a module loaded in runtime can be a Plugin. I have this kind of problem, having specific modules to some cases that are loaded in run time as plugins with Module::Pluggable.

我认为在运行时加载的模块可以是插件。我有这样的问题,具有特定模块的一些案例,在运行时作为插件与Module :: Pluggable加载。

Maybe you need to change the logic of your modules, but it works and scale very well (my app started with four modules and now have twenty and it's growing).

也许你需要改变你的模块的逻辑,但它的工作和扩展非常好(我的应用程序从四个模块开始,现在有二十个,而且它正在增长)。

#6


3  

How about using the core module Module::Load

如何使用核心模块Module :: Load

With your example:

用你的例子:

use Module::Load;
load $ENV{a};

"Module::Load - runtime require of both modules and files"

“Module :: Load - 运行时需要模块和文件”

"load eliminates the need to know whether you are trying to require either a file or a module."

“加载消除了你是否需要知道是否需要文件或模块的需要。”

If it fails it will die with something of the like "Can't locate xxx in @INC (@INC contains: ...".

如果它失败了它会死于类似“无法在@INC中找到xxx(@INC包含:......”)。

#7


1  

Many years later, eval "use $mod_name"; seems to work just fine (as of at least 5.8.8).

许多年后,eval“使用$ mod_name”;似乎工作得很好(截至至少5.8.8)。

The advantage over eval "require $mod_name"; is that the loaded module's default exports are automatically imported; in other words:

优于eval的优势“require $ mod_name”;是加载模块的默认导出是自动导入的;换一种说法:

eval "use $mod_name";

eval“use $ mod_name”;

is the shorter equivalent of

是更短的等价物

eval "require $mod_name"; $mod_name->import();

eval“require $ mod_name”; $ mod_name->导入();

Here's a test command, which passes the name of the module via env. variable mod_name, loads and imports the module, then uses an imported function (assumes a POSIX-like shell):

这是一个测试命令,它通过env传递模块的名称。变量mod_name,加载和导入模块,然后使用导入的函数(假设类似POSIX的shell):

 $ mod_name='Data::Dumper' perl -e 'eval "use $ENV{mod_name}"; print Dumper("hi!")'
 $VAR1 = 'hi!';

I may be missing subtleties; if so, please let me know.

我可能会遗漏细微之处;如果是的话,请告诉我。

#1


8  

eval "require $ENV{a}";

"use" doesn't work well here because it only imports in the context of the eval.

“use”在这里不能很好地工作,因为它只在eval的上下文中导入。

As @Manni said, actually, it's better to use require. Quoting from man perlfunc:

正如@Manni所说,实际上,最好使用require。引自man perlfunc:

If EXPR is a bareword, the require assumes a ".pm" extension and 
replaces "::" with "/" in the filename for you, to make it easy to 
load standard modules.  This form of  loading of modules does not 
risk altering your namespace.

In other words, if you try this:

        require Foo::Bar;    # a splendid bareword

The require function will actually look for the "Foo/Bar.pm" file 
in the directories specified in the @INC array.

But if you try this:

        $class = 'Foo::Bar';
        require $class;      # $class is not a bareword
    #or
        require "Foo::Bar";  # not a bareword because of the ""

The require function will look for the "Foo::Bar" file in the @INC 
array and will complain about not finding "Foo::Bar" there.  In this 
case you can do:

        eval "require $class";

#2


8  

"use" Statements are run at compilation time, not at run time. You will need to require your modules instead:

“use”语句在编译时运行,而不是在运行时运行。您需要改为使用模块:

my $module = "Foo::Bar";
eval "require $module";

#3


6  

I would use UNIVERSAL::require. It has both require and use methods to use a package. The use method will also call import for the package.

我会使用UNIVERSAL :: require。它既有要求也有使用方法来使用包。 use方法也会调用包的import。

use UNIVERSAL::require;
$ENV{a}->use or die 'Could not import package:  ' . $@;

#4


4  

You probably want to use require instead of use if you don't want it to happen at compile time, and then manually import any symbols you might need. See this link to the Perl Cookbook (from Google Books) for a good discussion of methods you can use to achieve what you want.

如果您不希望它在编译时发生,您可能希望使用require而不是use,然后手动导入您可能需要的任何符号。有关可用于实现所需方法的详细讨论,请参阅Perl Cookbook(来自Google Books)的链接。

#5


4  

I think that a module loaded in runtime can be a Plugin. I have this kind of problem, having specific modules to some cases that are loaded in run time as plugins with Module::Pluggable.

我认为在运行时加载的模块可以是插件。我有这样的问题,具有特定模块的一些案例,在运行时作为插件与Module :: Pluggable加载。

Maybe you need to change the logic of your modules, but it works and scale very well (my app started with four modules and now have twenty and it's growing).

也许你需要改变你的模块的逻辑,但它的工作和扩展非常好(我的应用程序从四个模块开始,现在有二十个,而且它正在增长)。

#6


3  

How about using the core module Module::Load

如何使用核心模块Module :: Load

With your example:

用你的例子:

use Module::Load;
load $ENV{a};

"Module::Load - runtime require of both modules and files"

“Module :: Load - 运行时需要模块和文件”

"load eliminates the need to know whether you are trying to require either a file or a module."

“加载消除了你是否需要知道是否需要文件或模块的需要。”

If it fails it will die with something of the like "Can't locate xxx in @INC (@INC contains: ...".

如果它失败了它会死于类似“无法在@INC中找到xxx(@INC包含:......”)。

#7


1  

Many years later, eval "use $mod_name"; seems to work just fine (as of at least 5.8.8).

许多年后,eval“使用$ mod_name”;似乎工作得很好(截至至少5.8.8)。

The advantage over eval "require $mod_name"; is that the loaded module's default exports are automatically imported; in other words:

优于eval的优势“require $ mod_name”;是加载模块的默认导出是自动导入的;换一种说法:

eval "use $mod_name";

eval“use $ mod_name”;

is the shorter equivalent of

是更短的等价物

eval "require $mod_name"; $mod_name->import();

eval“require $ mod_name”; $ mod_name->导入();

Here's a test command, which passes the name of the module via env. variable mod_name, loads and imports the module, then uses an imported function (assumes a POSIX-like shell):

这是一个测试命令,它通过env传递模块的名称。变量mod_name,加载和导入模块,然后使用导入的函数(假设类似POSIX的shell):

 $ mod_name='Data::Dumper' perl -e 'eval "use $ENV{mod_name}"; print Dumper("hi!")'
 $VAR1 = 'hi!';

I may be missing subtleties; if so, please let me know.

我可能会遗漏细微之处;如果是的话,请告诉我。