Techioz Blog

Ruby クラスを C 拡張機能で拡張するにはどうすればよいですか?

概要

Ruby で Foo::Bar を記述しており、C 拡張機能として Bar にメソッドを追加したいとします。今、Cで次のようにFoo::Barを作成すると、次のようになります。

static VALUE Foo;
static VALUE Bar;

static VALUE 
print_string(VALUE self, VALUE string) {
  printf("%s", StringValuePtr(string));
  return Qnil;
}

void Init_foo() {
    Foo = rb_define_module("Foo");
    Bar = rb_define_class_under(Foo, "Bar", rb_cObject);
    rb_define_method(Bar, "print_string", print_string, 1);
}

しかし問題は次のとおりです。

ruby-1.9.2-p180 :001 > require 'ext/foo'   #=> ["Foo"]
ruby-1.9.2-p180 :002 > f = Foo::Bar.new   #=> #<Foo::Bar:0x000001046bce48>
ruby-1.9.2-p180 :003 > f.original_ruby_method
NoMethodError: undefined method `original_ruby_method' for #<Foo::Bar:0x000001046bce48>

したがって、基本的に元の Foo::Bar を上書きしています。上書きせずに拡張するにはどうすればよいですか?

解決策

この問題を解決する方法を考え出しました。

void Init_foo() {
    rb_eval_string("require './lib/foo'");
    VALUE Bar = rb_path2class("Foo::Bar");
    rb_define_method(Bar, "print_string", print_string, 1);
}