如何rb_protect ruby​​中的所有内容

joh*_*nes 6 ruby ruby-c-extension

我想从我自己的C代码中调用ruby代码.如果引发异常,我必须rb_protect我调用的ruby代码.rb_protect看起来像这样:

VALUE rb_protect(VALUE (* proc) (VALUE), VALUE data, int * state)
Run Code Online (Sandbox Code Playgroud)

所以proc必须是一个接受VALUE参数和返回的函数VALUE.我必须调用许多不能以这种方式工作的函数.他怎么能rb_protect提出例外呢?

我曾想过Data_Make_Struct用来将所有东西都包装成一个ruby对象并在其上调用方法.Data_Make_Struct本身可以提出例外.我怎么样rb_protect Data_Make_Struct

sfs*_*man 4

要以灵活的方式使用rb_protect(例如,使用任意数量的参数调用 Ruby 函数),请将一个小的调度函数传递给rb_protect. Ruby 要求这样做sizeof(VALUE) == sizeof(void*),并且rb_protect盲目地通过了VALUE给调度函数,而不对其进行检查或修改。这意味着您可以将所需的任何数据传递给调度函数,让它解压数据并调用适当的 Ruby 方法。

例如,要rb_protect调用 Ruby 方法,您可以使用如下内容:

#define MAX_ARGS 16
struct my_callback_stuff {
  VALUE obj;
  ID method_id;
  int nargs;
  VALUE args[MAX_ARGS];
};

VALUE my_callback_dispatch(VALUE rdata)
{
  struct my_callback_stuff* data = (struct my_callback_stuff*) rdata;
  return rb_funcall2(data->obj, data->method_id, data->nargs, data->args);
}

... in some other function ...
{
  /* need to call Ruby */
  struct my_callback_stuff stuff;
  stuff.obj = the_object_to_call;
  stuff.method_id = rb_intern("the_method_id");
  stuff.nargs = 3;
  stuff.args[0] = INT2FIX(1);
  stuff.args[1] = INT2FIX(2);
  stuff.args[2] = INT2FIX(3);

  int state = 0;
  VALUE ret = rb_protect(my_callback_dispatch, (VALUE)(&stuff), &state);
  if (state) {
    /* ... error processing happens here ... */
  }
}
Run Code Online (Sandbox Code Playgroud)

另外,请记住,rb_rescuerb_ensure可能是解决某些问题的更好方法。