nDiki

2013年8月28日 (水)

PerlTest::More の is 呼び出しで () つけないと動かなくなるのはなぜ?

テストスクリプトで 「クラスメソッドの返り値のアサーションで、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!

困ったらカッコつけようぜ。

スポンサード リンク
[ 8月28日全て ]

About Me

Naney Naney (なにい)です。株式会社ミクシィで SNS 事業の部長をしています。

nDiki1999年1月に始めたコンピュータ日誌を前身とする NaneyWeb 日記(兼パーソナルナレッジベース)です。ちょっとしたノートは nNote にあります。

※内容は個人的見解であり所属組織とは関係ありません。

月別インデックス
Process Time: 0.105842s / load averages: 1.08, 1.59, 1.25
nDiki by WATANABE Yoshimasa (Naney)
Powered by DiKicker