Perlモジュールを動的に含める必要がありますが、作業コーディング標準のため、可能であればevalを避けたいと思います。これは機能します:
$module = "My::module";
eval("use $module;");
しかし、可能であればeval
なしでそれを行う方法が必要です。すべてのグーグル検索はeval
メソッドにつながりますが、他の方法ではありません。
eval
なしでそれを行うことは可能ですか?
require
を使用して、実行時にモジュールをロードします。モジュールをロードできない場合に備えて、これを(文字列ではなく)ブロックeval
でラップすることをお勧めします。
eval {
require My::Module;
My::Module->import();
1;
} or do {
my $error = $@;
# Module load failed. You could recover, try loading
# an alternate module, die with $error...
# whatever's appropriate
};
eval {...} or do {...}
構文と$@
のコピーを作成する理由は、$@
がさまざまな方法で設定できるグローバル変数であるためです。他の何かが値を別の値に設定する競合状態を回避するために、値をできるだけアトミックに取得する必要があります。
実行時までモジュールの名前がわからない場合は、モジュール名(My :: Module)とファイル名(My/Module.pm)の間の変換を手動で行う必要があります。
my $module = 'My::Module';
eval {
(my $file = $module) =~ s|::|/|g;
require $file . '.pm';
$module->import();
1;
} or do {
my $error = $@;
# ...
};
コアモジュールを使用するのはどうですか Module :: Load
あなたの例で:
use Module::Load;
my $module = "My::module";
load $module;
「Module :: Load-モジュールとファイルの両方のランタイム要件」
「ロードにより、ファイルとモジュールのどちらが必要かを知る必要がなくなります。」
失敗すると、 "@ INCでxxxが見つかりません(@INCに含まれるもの:...")のようなもので終了します。
まあ、常に require
のようにあります
require 'My/Module.pm';
My::Module->import();
実行時ではなくコンパイル時に呼び出されるimport
から得た効果はすべて失われることに注意してください。
編集:これとevalの方法のトレードオフは次のとおりです。evalを使用すると、通常のモジュール構文を使用でき、モジュール名が無効な場合(単に見つからない場合ではなく)、より明確なエラーが発生します。 OTOH、評価方法は(潜在的に)任意のコードインジェクションの影響を受けやすくなります。
いいえ、eval
がなくてはなりません。これは、 perldoc -f require で説明されているように、require()
がベアワードモジュール名を必要とするためです。ただし、任意のコードの挿入を許可しないため、evalの悪用ではありません(もちろん、require
ingしているファイルの内容を制御できると仮定します)。
EDIT:コードは以下で修正されましたが、完全を期すために最初のバージョンを残しています。
私が使う私は実行時に動的ロードを行うためにこの小さな砂糖モジュールを使用していました:
_package MyApp::Util::RequireClass;
use strict;
use warnings;
use Exporter 'import'; # gives you Exporter's import() method directly
our @EXPORT_OK = qw(requireClass);
# Usage: requireClass(moduleName);
# does not do imports (wrong scope) -- you should do this after calling me: $class->import(@imports);
sub requireClass
{
my ($class) = @_;
eval "require $class" or do { die "Ack, can't load $class: $@" };
}
1;
_
PS。私はこの定義を見つめています(私はかなり前にそれを書きました)そして私はこれを追加することを考えています:$class->export_to_level(1, undef, @imports);
... itshouldwork、しかし、テストされていません。
[〜#〜] edit [〜#〜]:バージョン2になりました。評価がなくても、はるかに優れています(ysthに感謝)::)
_package MyApp::Util::RequireClass;
use strict;
use warnings;
use Exporter 'import'; # gives you Exporter's import() method directly
our @EXPORT_OK = qw(requireClass);
# Usage: requireClass(moduleName);
# does not do imports (wrong scope) -- you should do this after calling me: $class->import(@imports);
sub requireClass
{
my ($class) = @_;
(my $file = $class) =~ s|::|/|g;
$file .= '.pm';
require $file; # will die if there was an error
}
1;
_
CPANのClass :: MOPには、このためのload_classメソッドがあります: http://metacpan.org/pod/Class::MOP
私は次のようなことをするのが好きです。
require Win32::Console::ANSI if ( $^O eq "MSWin32" );