2012-06-18 6 views
6

Quiero llamar al código Ruby desde mi propio código C. En caso de que se levante una excepción, tengo que proteger rb_ el código ruby ​​que llamo. rb_protect se parece a esto:cómo proteger rb_todo todo en ruby ​​

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

Así proc tiene que haber una función que toma VALUE argumentos y devuelve VALUE. Tengo que llamar a muchas funciones que no funcionan de esa manera. ¿Cómo puedo I rb_protect de levantar excepciones?

He pensado en usar Data_Make_Struct para envolver todo en un objeto Ruby y llamar a métodos sobre él. Data_Make_Struct podría generar una excepción. ¿Cómo puedo rb_protectData_Make_Struct?

Respuesta

4

Para usar rb_protect de una manera flexible (por ejemplo, para llamar a una función de Ruby con un número arbitrario de argumentos), pase una pequeña función de envío a rb_protect. Ruby requiere que sizeof(VALUE) == sizeof(void*) y rb_protect pasen ciegamente los datos de tipo VALUE a la función de envío sin inspeccionarlo ni modificarlo. Esto significa que puede pasar los datos que desee a la función de despacho, dejar que descomprima los datos y llamar al (los) método (s) Ruby apropiado (s).

Por ejemplo, para rb_protect una llamada a un método de Rubí, se usa algo como esto:

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

Además, tenga en cuenta que rb_rescue o rb_ensure puede haber un mejor enfoque para algunos problemas.