6

自作の C コードから ruby​​ コードを呼び出したい。例外が発生した場合に備えて、呼び出した ruby​​ コードを rb_protect する必要があります。rb_protect は次のようになります。

VALUE rb_protect(VALUE (* proc) (VALUE), VALUE data, int * state)

したがって、引数を取り、 を返すproc関数でなければなりません。そのようには機能しない多くの関数を呼び出さなければなりません。例外を発生させないようにするにはどうすればよいですか?VALUEVALUErb_protect

Data_Make_Structすべてを 1 つの Ruby オブジェクトにラップし、その上でメソッドを呼び出すために使用することを考えました。Data_Make_Structそれ自体が例外を発生させる可能性があります。どうすればいいrb_protect Data_Make_Structですか?

4

1 に答える 1

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 ... */
  }
}

rb_rescueまた、いくつかの問題に対しては、またはrb_ensureがより良いアプローチである可能性があることを覚えておいてください。

于 2013-02-27T06:43:22.437 に答える