テストスクリプトで 「クラスメソッドの返り値のアサーションで、is に括弧をつけると動くけれど、とると動かなくなるのはなぜ?」とチームメンバに質問された。
#!/usr/bin/perl use warnings; use strict; use 5.10.0; package MyClass; sub color { 'blue' }; package main; use Test::More; is(MyClass->color, 'blue'); is MyClass->color, 'blue'; # wrong! done_testing;
簡略化すると上のような感じ。実行すると、
Useless use of a constant (blue) in void context at sample.t line 16. ok 1 Can't locate object method "is" via package "MyClass" at sample.t line 16. # Tests were run but no plan was declared and done_testing() was not seen.
となる。
これは間接オブジェクト構文(indirect object syntax)の罠にハマったケースだね。 間接オブジェクト構文は、例えば C++ の new っぽく
my $obj = new MyClass;
と書ける構文(MyClass::new が呼ばれる)。前述では MyClass::is 呼ぼうとして怒られていると。間接オブジェクト構文は perldoc perlobj で説明されている。
ちなみにis じゃなくて組み込み関数だと違う解釈になる。
say(uc MyClass->color);
とすると MyClass::uc が呼ばれるのではなくて uc(MyClass->color) と解釈されるので "BLUE\n" が出力される。
また以下みたいに、意図しないまま動いちゃう場合もあるので注意かな。
#!/usr/bin/perl use warnings; use strict; use 5.10.0; package MyClass; sub color { 'blue' }; sub is { 'MyClass2' } package MyClass2; sub color { 'red' }; package main; use Test::More; is MyClass->color, 'green'; done_testing;
これだと MyClass::is が呼ばれて 'MyClass2' が返ってきて、そして MyClass2 の color が呼ばれて 'red' が返ってくる(そして 'green' は使われないし、Test::More::is も実行されない)。
Useless use of a constant (green) in void context at sample.t line 21. 1..0 # No tests run!
困ったらカッコつけようぜ。
Naney (なにい)です。株式会社ミクシィで SNS 事業の部長をしています。
nDiki は1999年1月に始めたコンピュータ日誌を前身とする Naney の Web 日記(兼パーソナルナレッジベース)です。ちょっとしたノートは nNote にあります。
※内容は個人的見解であり所属組織とは関係ありません。