When defining methods from C, sometimes it is useful to have a single C function implement multiple Ruby methods. In order to have a single function implement multiple methods (and have slightly different behavior in each case), it is necessary to be able to attach data to the method. The usefulness of this becomes very apparent in C++ when template tricks are used to define Ruby methods.
It is possible in Ruby 1.6 to attach arbitrary data to a method using Module#define_method() and rb_iterate(). Note that this is an order of magnitide slower than a normal method.
It is possible in Ruby 1.8 to attach arbitrary data to a method like so:
struct Data {
int value;
};
VALUE foo(VALUE self) {
struct Data * data = (struct Data *)(ruby_current_node->nd_entry);
printf("%d\n", data->value);
}
NODE * node = NEW_CFUNC(foo, 0);
node->nd_entry = (global_entry *)data;
rb_add_method(rb_cFoo, rb_intern("foo"), node, NOEX_PUBLIC);
However, this code:
VALUE rb_get_function_data();
The above code can now be rewritten as:
struct Data {
int value;
};
VALUE foo(VALUE self) {
struct Data * data;
Data_Get_Struct(rb_get_function_data(), rb_cObject, data);
printf("%d\n", data->value);
}
rb_define_method(rb_cFoo, "foo", foo, 0);
VALUE v = Data_Wrap_Struct(rb_cObject, 0, 0, data);
rb_add_data_to_function(rb_cFoo, "foo", v);
--matz.
I'm not sure I understand why this solution isn't re-entrant. Can you elaborate?
I do like the idea of retrieving calling information via a struct. Such a struct could hold the name of the function that was called (if available) and the object it was called on, in addition to whatever Ruby object was attached to the function.
-- Paul Brannan
Back to RCRchive.
RCR Submission page and RCRchive powered by Ruby, Apache, RuWiki (modified), and RubLog