2012-06-18 1 views
6

나는 내 자신의 C 코드에서 루비 코드를 호출하고 싶다. 예외가 발생하는 경우, 내가 호출하는 루비 코드를 rb_protect해야합니다. rb_protect은 다음과 같습니다 루비의 모든 것을 rb_protect하는 방법

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

그래서 procVALUE 인수를하고 VALUE을 반환하는 함수이어야한다. 그런 식으로 작동하지 않는 많은 함수를 호출해야합니다. rb_protect 예외 발생을 어떻게 방지 할 수 있습니까?

Data_Make_Struct을 사용하여 모든 것을 하나의 루비 객체로 래핑하고 그 객체에 대한 메소드를 호출하는 방법을 생각해 보았습니다. Data_Make_Struct 자체가 예외를 발생시킬 수 있습니다. 어떻게해야합니까 rb_protectData_Make_Struct?

답변

4

rb_protect을 유연한 방법으로 사용하려면 (예 : 임의 개수의 인수가있는 루비 함수를 호출하려면) 작은 디스패치 함수를 rb_protect으로 전달하십시오. Ruby는 sizeof(VALUE) == sizeof(void*)이 필요하고 rb_protectVALUE 형식화 된 데이터를 검사하거나 수정하지 않고 맹목적으로 발송 기능에 전달합니다. 즉, 디스패치 함수에 원하는 모든 데이터를 전달하고 데이터의 압축을 풀고 적절한 Ruby 메서드를 호출 할 수 있습니다.

예를 들어, rb_protect 루비 메서드 호출로,이 같은 것을 사용할 수 있습니다 :

또한
#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 몇 가지 문제에 대한 더 나은 방법이 될 수 있음을 명심하십시오.