2012-06-18 27 views
6

Tôi muốn gọi mã ruby ​​từ mã C của riêng tôi. Trong trường hợp ngoại lệ được nâng lên, tôi phải rb_protect mã ruby ​​tôi gọi. rb_protect trông như thế này:cách rb_protect mọi thứ trong ruby ​​

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

Vì vậy proc có phải là một chức năng mà phải mất VALUE đối số và trả VALUE. Tôi phải gọi rất nhiều chức năng không hoạt động theo cách đó. Làm cách nào để tôi có thể rb_protect họ từ việc tăng ngoại lệ?

Tôi đã nghĩ đến việc sử dụng Data_Make_Struct để bọc mọi thứ vào một đối tượng ruby ​​và các phương thức gọi trên đó. Data_Make_Struct có thể tự tăng ngoại lệ. Làm cách nào để tôi rb_protectData_Make_Struct?

Trả lời

4

Để sử dụng rb_protect theo cách linh hoạt (ví dụ: để gọi hàm Ruby với số lượng đối số tùy ý), hãy chuyển một hàm công văn nhỏ đến rb_protect. Ruby yêu cầu sizeof(VALUE) == sizeof(void*)rb_protect bỏ qua một cách mù quáng VALUE nhập dữ liệu vào chức năng gửi mà không kiểm tra hoặc sửa đổi nó. Điều này có nghĩa là bạn có thể chuyển bất kỳ dữ liệu nào bạn muốn cho hàm dispatch, cho phép nó giải nén dữ liệu và gọi (các) phương thức Ruby thích hợp.

Ví dụ, để rb_protect một cuộc gọi đến một phương pháp Ruby, bạn có thể sử dụng một cái gì đó như thế này:

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

Ngoài ra, hãy nhớ rằng rb_rescue hoặc rb_ensure có thể là một cách tiếp cận tốt hơn đối với một số vấn đề.

Các vấn đề liên quan