Hatena::ブログ(Diary)

naoyaのはてなダイアリー

October 24, 2005

Perl::Critic / UNIVERSAL::require

このところ社内の技術勉強会で取り上げているテーマの Perl::Critic。このモジュールは、Damian Conway の Perl Best Pracitice に書かれているスタンダードな Perl のコーディングスタイルをチェックするためのものです。Perl::Critic をインストールすると perlcritic というコマンドがインストールされ、それを使うことで自分が書いた Perl のソースをチェックしたりできるという。

いろんなコーディングスタイルのルールとかは、Perl::Critic::Policy のサブクラスに記述されていて、pod で全部読めます。

この Perl::Critic なポリシーの中に Perl::Critic::Policy::BuiltinFunctions::ProhibitStringyEval というのがあります。これは eval には文字列じゃなくてブロックでコードを与えよ、というルール。

eval "print $foo";        #not ok
eval {print $foo};        #ok

理由は pod を参照していただくとして、eval を lazy な use や require のために使うときはどちらにしろ文字列で eval を使わないといけない。(コメントにありますが、モジュールファイル名で require したときのみなんとかなる) そこで、eval で use とか require するのが嫌! ってときには UNIVERSAL::require を使うという手があるかなと思いました。

これを使うと、

eval "require $module"

が、

$module->require;

と書け、OO厨*1にはたまらない感じ。

ただ、今 id:hideoki と話しててわかったのですが、UNIVERSAL::require も中では文字列で eval をしてるので、"The string form of eval is recompiled every time it is executed, whereas the block form is only compiled once. " という点においては一緒のようなんですけど。

ちなみに、UNIVERSAL::require は Catalyst で使われてるのをみて知りました。

*1:PofEAA読書会でみんなが連呼していた言葉。厨という言葉がついているが必ずしも揶揄というわけではないらしい。

miyagawamiyagawa 2005/10/24 15:38 eval { requre ”Foo/Bar.pm” }
なら文字列eval をする必要がないです。

UNIVERSAL::require が例外を投げない問題は
http://use.perl.org/~schwern/journal/27005
http://use.perl.org/~schwern/journal/26966
で最近議論がありました。

naoyanaoya 2005/10/24 16:03 文字列 eval をしなくていい唯一の抜け道が Foo::Bar → Foo/Bar.pm として eval { require ... } ってことですよね。

lazy load のときは「使わなきゃいけない」ってところが間違いになりますね、直しておこう。

miyagawamiyagawa 2005/10/24 16:46 sub eval_require {
my $mod = shift;
$mod =~ s!::!/!g;
eval { require ”$mod.pm” };
}

eval_require(”CGI::Carp”);

とすればOK。UNIVERSAL::require はなんでこうしないで eval ”” にしたんだっけなぁ。

ryu1roryu1ro 2005/10/24 17:30 今UNIVERSAL::require見たら、eval{}になってるような

# Load the module.
my $file = $module . ’.pm’;
$file =~ s{::}{/}g;
my $return = eval qq{
#line $call_line ”$call_file”
CORE::require(¥$file);
};

ryu1roryu1ro 2005/10/24 17:35 う、勘違い。qq{}でした。。あれれ?

UNIVERSAL::require no longer uses eval STRING in require(). This closes a security hole.

miyagawamiyagawa 2005/10/24 18:55 あ、2週間前のリリースで修正されたみたいですね。
http://search.cpan.org/~mschwern/UNIVERSAL-require-0.10/
相変わらず qq{} は使ってますが、require の方法はよりsafeに変更されたみたいです。

hideokihideoki 2005/10/24 23:26 ホントだ更新されてる。
そこまで置換してなんで、qq{}使う必要あるのかな?