web-dev-qa-db-ja.com

使用する前にPerlモジュールがあるかどうかを確認するにはどうすればよいですか?

端末の幅を取得するためにTerm::ReadKeyに依存する次のPerlコードがあります。私のNetBSDビルドにはこのモジュールがありません。そのため、モジュールが見つからない場合、ターミナルの幅をデフォルトで80にしたいと思います。

モジュールが利用可能かどうかを事前に知っているので、条件付きでモジュールを使用する方法がわかりません。現在の実装は、存在しない場合はTerm::ReadKeyが見つからないというメッセージで終了します。

#/usr/pkg/bin/Perl -w
# Try loading Term::ReadKey
use Term::ReadKey;
my ($wchar, $hchar, $wpixels, $hpixels) = GetTerminalSize();
my @p=(2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97);
my $plen=$#p+1;
printf("num |".("%".int(($wchar-5)/$plen)."d") x $plen."\n",@p);

NetBSDではPerl 5.8.7を、CygWinでは5.8.8を使用しています。これをスクリプトに効率的に実装するのを手伝っていただけますか?

50
dlamblin

別のモジュールを必要としない基本的なソリューションを次に示します。

my $rc = eval
{
  require Term::ReadKey;
  Term::ReadKey->import();
  1;
};

if($rc)
{
  # Term::ReadKey loaded and imported successfully
  ...
}

eval { use SomeModule }は間違っています。なぜなら、useステートメントは、コード内のどこにあるかに関係なく、コンパイル時に評価されるためです。したがって、SomeModuleが使用できない場合、スクリプトはコンパイル時にすぐに終了します。

useステートメントの文字列evalも機能します(eval 'use SomeModule';)ですが、require/importペアが同じことを実行し、コンパイル時に起動時に構文チェックされる場合、実行時に新しいコードを解析およびコンパイルする意味がありません。)

最後に、eval { ... }および$@ここでは、この例の目的のために簡潔です。実際のコードでは、 Try :: Tiny のようなものを使用するか、少なくとも 対処する問題に注意してください を使用する必要があります。

91
John Siracusa

CPANモジュール Module :: Load :: Conditional を確認してください。それはあなたが望むことをします。

11
m0j0

古典的な答え(少なくとも、「使用」が行われるずっと前にPerl 4にさかのぼります)は、モジュールを「require()」することでした。これは、コンパイル時ではなくスクリプトの実行時に実行され、成功または失敗をテストして適切に対応できます。

7
if  (eval {require Term::ReadKey;1;} ne 1) {
# if module can't load
} else {
Term::ReadKey->import();
}

または

if  (eval {require Term::ReadKey;1;}) {
#module loaded
Term::ReadKey->import();
}

注:1;は、require Term::...が正しく読み込まれました。

4
ShqTth

モジュールの特定のバージョンが必要な場合:

my $GOT_READKEY;
BEGIN {
    eval {
        require Term::ReadKey;
        Term::ReadKey->import();
        $GOT_READKEY = 1 if $Term::ReadKey::VERSION >= 2.30;
    };
}


# elsewhere in the code
if ($GOT_READKEY) {
    # ...
}
4
Hinrik

変数を使用する場合は機能しないと思います。確認してください このリンク 変数でどのように使用できるかを説明しています

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

Require関数は、@ INC配列で "Foo :: Bar"ファイルを探し、そこに "Foo :: Bar"が見つからないことを報告します。この場合、次のことができます。

 eval "require $class";
0
Utkarsh Kumar