如何在Ruby C API

时间:2017-05-17 13:59:14

标签: c ruby api

我用Ruby的C API创建了一些类。我想创建一个函数,其行为将根据Ruby对象的类而改变。

我尝试使用Ruby中的is_a?,但是,我不认为这是做到这一点的好方法。我检查了“Creating Extension Libraries for Ruby”但没有成功。检查类的唯一直接方法是使用默认类型。

我的班级“Klass”已经创建:

VALUE rb_cKlass = rb_define_class("Klass", rb_cObject);

我想如何检查班级是否合适:

VALUE my_function(VALUE self, VALUE my_argument) {
    if(rb_check_class(my_argument), rb_cKlass)) {
        // do something if my_argument is an instance of Klass
    } else {
        return Qnil;
    }
}

有办法做到这一点吗?

3 个答案:

答案 0 :(得分:2)

每个ruby对象在内部由RObject struct表示(为了将来的读者,我将在这里复制源代码):

struct RObject {
  struct RBasic basic;
  union {
    struct {
      uint32_t numiv;
      VALUE *ivptr;
      void *iv_index_tbl; /* shortcut for RCLASS_IV_INDEX_TBL(rb_obj_class(obj)) */
    } heap;
    VALUE ary[ROBJECT_EMBED_LEN_MAX];
  } as;
};

第一个成员RBasic定义了类:

struct RBasic {
    VALUE flags;
    const VALUE klass;
}

要访问任何内容的RBasic元数据,可以使用RBASIC宏:

RBASIC(my_argument)

要直接获取课程,可以使用RBASIC_CLASS宏:

RBASIC_CLASS(my_argument)

答案 1 :(得分:0)

我最近遇到了这个问题,并使用了RBASIC_CLASS宏,但是由于某些无法解释的原因,在某些情况下出现了段错误。

扫描ruby.h后,我发现了CLASS_OF宏,该宏将给定对象的类返回为VALUE

VALUE obj = INT2NUM(10);
VALUE klass = CLASS_OF(obj); // rb_cInteger 

使用Ruby 2.5

答案 2 :(得分:0)

如果你想接近 is_a? Ruby 风格(即检查是否有任何祖先是预期的类),你可以直接使用 is_a?, {{1} 的 C 实现}:

rb_obj_is_kind_of

并且由于 rb_obj_is_kind_of(my_argument, rb_cKlass) // Qtrue OR Qfalse ,您可以使用该方法作为条件:

Qfalse == 0

要找到此方法,只需选中 Object#is_a? documentation 并单击以切换源代码,如果它是 C 函数,您将看到 C 实现(因此这适用于大多数标准库)。