Acme何thing? 出題編
makamakaです。突然ですがクイズです。
Acme::Anything
Acme::Everything
Acme::Nothing
Acme::Something
これらのうち、2011年12月19日現在CPANに存在していないモジュールはどれでしょう?
答えは明日の記事で!
やった、これで1日ういたよ!
ばははーい。
だとあまりにあんまりなので、一つずつみていきましょうか。
use 5.014; use Acme::Anything; use Ultra::Super::Delax::Module; use Carp; say "ok";
実行するとokが出ます。ところでUltra::Super::Delax::Moduleは私が今適当に考えたモジュールで実際には存在しません。普通は存在しないモジュールをuseすればdieしますよね?
そう、Acme::Anythingを最初にuseしてしまえば、その後は存在しない「どんな」モジュールをuseしてもエラーにならないのです! 素晴らしいですね!
ちなみにAcme::Anythingのコードはこういう感じなんですね。
push @main::INC, \ &handler_of_last_resort; sub handler_of_last_resort { my $fake_source_code = '1'; open my ($fh), '<', \ $fake_source_code; return $fh; };
@INCの最後にサブルーチンリファレンスが入っています。皆様ご存知の通り、パスの代わりにCODEREFがはいっていると、モジュール検索時に実行されます。この場合@INCの最後に入っていますので、モジュールが見つからなかった最後の手段として、このサブルーチンが呼び出されます。サブルーチンはファイルを見つけたらファイルハンドルを返さなければなりません。そこで1と書かれたファイル(openに\$scalarを与えると、$scalarの値を内容とするファイルとみなされます)のファイルハンドルを返します。これでどんなモジュールもロードに成功したとみなされるというわけです。
このテクニックはいくつかのAcmeモジュールだけでなく、他の様々なモジュールやライブラリでもしばしば使用されています。@INCにコードリファレンスやオブジェクトを突っ込むテクニックについて詳しくはperldoc perlfuncしてみてください。
ふーむ、だいぶ長くなったので、やっぱり続きはまた明日!