BlogもどきのWeblog

備忘録と日々の呟きとメモとCGIの実験場とされる何か。
プロフィール

GLANSHE
絵描き担当らしい

Total: 31355
Today: 10
Yesterday: 219
最新の記事

コンテンツ

最新のコメント

最新のトラックバック

カテゴリー

リンク

ニコ動MyListLink

[Perl]モジュールの動的ロードの方法メモ
Perlでモジュールの動的ロードをする話。

$modName = "Test::Module";
require $modName;

これが通らない。いや通らないのは別にいい。
本来の使い方が違うだけなのだから。
と言う訳でその方法を調べてみた。


他の人はどうやってモジュールの動的ロードを行っているのかと思って色々調べていると、次のような方法があるらしい。

1. evalに文字列としてスクリプトを与え、文字列展開を行ってモジュールをロードする方法

requireの仕様として

require Test::Module;

というように直接モジュール名を指定した場合は、ライブラリにあるTest/Module.pmをロードしてくれる。
但し、

require $modName;

とした場合は、$modNameを文字列そのものとして扱うため、ライブラリにあるTest::Moduleファイルを探しに行ってしまう。
当然、そんなファイルはある訳がないので、

Can't locate Test::Module in @INC (@INC contains: ./lib /etc/perl /usr/local/lib/perl/5.10.0 /usr/local/share/perl/5.10.0 /usr/lib/perl5 /usr/share/perl5 /usr/lib/perl/5.10 /usr/share/perl/5.10 /usr/local/lib/site_perl .)

こんな感じのエラーが出る訳だ。

そのため、

eval "require $modName";

とすることで、文字列展開したスクリプトをevalで実行することで、うまくモジュールをロードしてもらおうと言うのがこの方法。

しかし、この方法は遅いらしいし(未検証)、$modNameにPerlスクリプトが書いてあった場合、それも実行してしまうため、$modNameが自由に書き換えられる状態ではセキュリティ的にも危ないので、あまり使い方としてはよくないらしい。(人から聞いた話)

2. Test/Module.pmを直接requireする方法

use './lib';

とかをして、自分でモジュール用のファイルディレクトリを掘ってその中のモジュールファイルをrequireしたい場合などに使える方法

既に言ったが、

require $modName;

では、$modNameを文字列そのものとして扱うため、この中にモジュールファイルを指すパスを指定してやれば、正しく動く。

大昔のjcode.plのロードと同じ使い方。

require './jcode.pl';
require './lib/Test/Module.pm'

但し、これはモジュールが存在している場所を開発者が知らない場合は使えない。
モジュールとして既にインストールされている場合、モジュールファイル自体はシステムのディレクトリの方にあるため、自分でそれを拾いに行くのは難しい。
もしくは、許可されていない可能性もある。
自分の場合はここに入っていた
/usr/local/share/perl/5.10.0


上記は間違いでした。
require "Test/Module.pm";
で、Perlのライブラリとして登録されている場所を探索し、存在した場合それを読み込むようです。

3. UNIVERSAL::requireを使う方法

今はこれがモダンな方法らしい?具体的な意味はよく知らない。

use UNIVERSAL::require;

$modName = "Test::Module";
$modName->require;

のように書けば、指定したモジュールをロードしてくれる。

これを使おうとしてやってみたところ、UNIVERSALとか書いてあるくせに標準で入ってなかった…

use UNIVERSAL::require;

$modName = "Test::Module";
$modName->require;

結果
Can't locate UNIVERSAL/require.pm in @INC (@INC contains: ./lib /etc/perl /usr/local/lib/perl/5.10.0 /usr/local/share/perl/5.10.0 /usr/lib/perl5 /usr/share/perl5 /usr/lib/perl/5.10 /usr/share/perl/5.10 /usr/local/lib/site_perl .)

しかもUNIVERSALであるので勝手にロードされてると思い込んで使おうとしたら、ロードされてなかった…
明示的にUNIVERSAL::requireをuseしてやる必要があるらしい

#use UNIVERSAL::require;

$modName = "Test::Module";
$modName->require;

結果
Can't locate object method "require" via package "Test::Module" (perhaps you forgot to load "Test::Module"?)

但し、このUNIVERSAL::requireは、結局内部的に

my $file = $module . '.pm';
$file =~ s{::}{/}g;

return eval { 1 } if $INC{$file};

my $return = eval qq{
  CORE::require(\$file);
};

こーいう事をしてるらしい。
安全性は高くなったものの、ロード時間に関しては1の方法と大して変わらないのかも(未検証)。

参考
UNIVERSAL::requireによるモジュールの動的ロード
Perl::Critic / UNIVERSAL::require


time stamp:2010/03/27 11:07:13
トラックバック(0)|コメント(0)
この記事のトラックバックURL:

コメントを書く
名前:
タイトル:
MAIL:
URL:
コメント:
PASS:
何かしら