Я вижу странное поведение с конструкторами классов в расширении 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
.
Вторая странная вещь такова:
если мы позвоним
x = Bar.new(2)
мы получаем ошибку
in `new': wrong number of arguments(1 for 0) (ArgumentError)
Но конструктор Bar
принимает один параметр со значением по умолчанию.
Почему это? Это ошибка Ruby?
(протестировано с ruby1.9.3-p0 [x86_64])