Class::MOP::Class->get_method_map()の挙動が不安定な件
get_method_map()は基本的にサブルーチンスタブ(宣言のみで実体なし)を拾わないようになっているんだけど,実際にはプログラムの状態によってスタブを拾ったり拾わなかったりと安定しない*1。特に,Devel::Coverの元で動かすとこの「拾ったり拾わなかったり」という問題が顕在化して,cover -testだとテストが通らない。
#!perl -w use strict; { package Foo; use metaclass; # install "->meta" property sub m1; # 拾われない sub m2 :method; # 拾われる sub m3; our $m3; # 拾われる sub m4; m4() if 0;# 拾われる } use Data::Dumper; print Dumper [Foo->meta->get_method_list]; __END__ # 結果 $VAR1 = [ 'm3', 'm4', 'm2', 'meta' ];
これは,get_method_map()がシンボルテーブル(スタッシュ stash)にグロブが存在するかどうかで判断しているため。ところが,単なるスタブやプロトタイプつきスタブはスタッシュにグロブを作らない。ところが,たとえば同名のour変数を作るなどして何らかの理由でそのグロブが作られる状況を作ると,そのグロブのCODEスロットに空のコードリファレンスが入るわけだ。今のget_method_map()はグロブなしの純粋なスタブは無視して,空のコードリファレンスによるスタブは拾ってしまう*2。
じゃあどういう仕様にするべきか。このケースは幸いperlが答えてくれる。
#!perl -w use strict; { package Base; sub foo{} } { package Derived; use parent -norequire => qw(Base); sub foo; } Derived->foo(); __END__ # 結果 Undefined subroutine &Derived::foo called.