rb_block_given_p を調べたときのメモ
ruby 1.9.2 と tokyocabinet の ruby binding が動かない
ruby 1.9.2 と tokyocabinet の ruby binding の 1.29 を使っていると HDB#each などが動かない。 ブロックを与えているのだが「no block given」となる。 tokyocabinet の ruby binding のソースを見ると
if(rb_block_given_p() != Qtrue) rb_raise(rb_eArgError, "no block given");
の部分でエラーが起きているようだ。
ruby のソースコードを取得する
git clone https://github.com/ruby/ruby.git
でソースコードを取得する。
GNU GLOBAL
gtags -v
としてタグを作る。
GPATH GPL GRTAGS GSYMS GTAGS
ができる。
global rb_block_given_p
とすると
eval.c
と表示される。rb_block_given_p は eval.c で定義されていることがわかる。
rb_block_given_p を実行してみる
rb_block_given_p を実行する簡単なプログラムを作って調べる。 以下の 3 つのファイルを同じディレクトリを作成する。
extconf.rb
require 'mkmf'
create_makefile("block_given")
test_block_given.c
#include <ruby.h>
static VALUE block_given_test (VALUE self)
{
return rb_block_given_p();
}
void Init_block_given(){
VALUE block_given_class;
block_given_class = rb_define_class("TestBlockGiven", rb_cObject);
rb_define_method(block_given_class, "block_given_test", block_given_test, 0);
}
test.rb
require_relative './block_given'
test = TestBlockGiven.new
p test.block_given_test { |a| a }
実行する
ruby extconf.rb
make
ruby test.rb
とすると
0
と表示される。
rb_block_given_p() != Qtrue
だとすると true や false を返すはずなのだが、 どうも rb_block_given_p の返り値が変更されたようだ。
rb_block_given_p の変更を調べる
eval.c の 613 〜 625 行で rb_block_given_p が定義されているので
git blame -L 613,625 eval.c
として各行がどのコミットから来ているのかを調べる。
e07cb859 (nobu 2009-07-18 08:05:32 +0000 620) return TRUE;
となっているので rb_block_given_p は「e07cb859」から来ていることが分かる。
git show e07cb859
でそのコミットを調べる。
@@ -534,10 +536,10 @@ rb_block_given_p(void)
if ((th->cfp->lfp[0] & 0x02) == 0 &&
GC_GUARDED_PTR_REF(th->cfp->lfp[0])) {
- return Qtrue;
+ return TRUE;
}
else {
- return Qfalse;
+ return FALSE;
}
}
から返り値が Qtrue、Qfalse から TRUE、FALSE に変更されたことがわかる。 ruby 1.9.2 ではこの変更によって tokyocabinet の ruby binding が うまく動かなくなったことがわかった。
ruby 1.8.7 でどうなっているかは
git show origin/ruby_1_8_7:eval.c
を調べれば分かる。 1.8.7 では変更されていなかった。
tokyocabinet ruby binding の修正
単に 1.9.2 で動くようにするには tokyocabinet ruby binding の tokyocabinet.c で
rb_block_given_p() != Qtrue
を
!rb_block_given_p()
に変更する。