Ruby C 拡張機能のクラス コンストラクターで奇妙な動作が見られます。
例を見てください: Foo
C 拡張であるクラスBar
と から継承するクラスがありFoo
ます:
extconf.rb
# extconf.rb
require 'mkmf'
create_makefile('foo/foo')
foo.c
// foo.c
#include "ruby.h"
#include <stdio.h>
VALUE
foo_new (VALUE class)
{
printf ("foo_new\n");
int *ptr;
VALUE tdata = Data_Wrap_Struct (class, 0, 0, ptr);
rb_obj_call_init (tdata, 0, 0);
return tdata;
}
VALUE
foo_init (VALUE self)
{
printf ("foo_init\n");
return self;
}
VALUE
foo_plus_one (VALUE self, VALUE x)
{
printf ("foo_plus_one\n");
return INT2FIX (FIX2INT (x) + 1);
}
void
Init_foo ()
{
VALUE foo = rb_define_class ("Foo", rb_cObject);
rb_define_singleton_method (foo, "new", foo_new, 0);
rb_define_method (foo, "initialize", foo_init, 0);
rb_define_method (foo, "plus_one", foo_plus_one, 1);
}
bar.rb
# bar.rb
require './foo'
class Bar < Foo
end
わかりました奇妙なものを見てみましょう...
この状況ではすべてうまくいきます:
x = Bar.new
と の 2 つのプリントを取得しfoo_new
ますfoo_init
。
わかりましたが、この方法でクラスを変更するとBar
:
# bar.rb
require './foo'
class Bar < Foo
def initialize(param = 1)
end
end
実行すると、最初の奇妙なものがあります
x = Bar.new
プリントは 1 つだけです: foo_new
. そしてfoo_init
??
わかりました、コンストラクターへの明示的な呼び出しを追加することで、この問題を回避できますFoo
。
# bar.rb
require './foo'
class Bar < Foo
def initialize(param = 1)
super()
end
end
2 つのプリントを取得します:foo_new
とfoo_init
を呼び出した場合x = Bar.new
。
2 番目の奇妙な点は次のとおりです。
x = Bar.new(2)
エラーが発生します
in `new': wrong number of arguments(1 for 0) (ArgumentError)
ただし、コンストラクターはBar
、デフォルト値を持つ 1 つのパラメーターを受け入れます。
なぜこれ?これはRubyのバグですか?
(ruby1.9.3-p0 [ x86_64 ] でテスト済み)