-
-
Save matejuh/1646430 to your computer and use it in GitHub Desktop.
Wrapping struct
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
N.B. this program doesn't include any error checking. In particular you'll have | |
to do all the rb_protect stuff | |
*/ | |
#include <stdio.h> | |
#include "ruby.h" | |
struct Address { | |
char * town; | |
}; | |
/* | |
Implementation of getter method for town | |
*/ | |
static VALUE wrap_address_get_town(VALUE self) { | |
/* | |
Data_Get_Struct is the reverse of Data_Wrap_Struct | |
It unpacks the struct associated with self, casts it to struct Address | |
and assigns it to address. | |
Note it's a macro, not a function. | |
*/ | |
struct Address * address; | |
Data_Get_Struct(self, struct Address, address); | |
/* | |
rb_str_new2 converts a C char* into a Ruby String | |
*/ | |
return rb_str_new2(address->town); | |
} | |
/* | |
Implementation of setter method for town | |
*/ | |
static VALUE wrap_address_set_town(VALUE self, VALUE new_town) { | |
struct Address * address; | |
Data_Get_Struct(self, struct Address, address); | |
/* | |
StringValuePtr gets the char* associated with a Ruby String | |
*/ | |
address->town = StringValuePtr(new_town); | |
} | |
int main(int argc, char **argv) { | |
//setup | |
ruby_init(); | |
ruby_init_loadpath(); | |
ruby_script("embed"); | |
/* | |
Define wrapper class for the struct | |
As an alternative to creating an anonymous class with rb_class_new, we could create | |
a named class with rb_define_class: | |
VALUE address_wrapper_class = rb_define_class("Address", rb_cObject); | |
if we did this, the class would be available in Ruby as the class "Address" | |
*/ | |
VALUE address_wrapper_class = rb_class_new(rb_cObject); | |
/* | |
Add #town and #town= methods to the new class | |
Here we associate the two implementation functions defined above with the | |
wrapper class, so that in ruby it will respond to the methods #town and #town= | |
*/ | |
rb_define_method(address_wrapper_class, "town", wrap_address_get_town, 0); //getter method: #town | |
rb_define_method(address_wrapper_class, "town=", wrap_address_set_town, 1);//setter method: #town= | |
/* | |
Create instance of the C struct | |
*/ | |
struct Address adr; | |
adr.town = "London"; | |
/* | |
Wrap the C struct to create Ruby object | |
Here is where we use Data_Wrap_Struct. The result is a Ruby object which is an instance | |
of the class we have just defined, so it will respond to the methods #town and #town= | |
Note that in Ruby the class understands the #town and #town= methods because of the | |
rb_define_method calls on the class, _not_ because the C struct has similarly named | |
members. | |
*/ | |
VALUE wrapped_address = Data_Wrap_Struct(address_wrapper_class, NULL, NULL, &adr); | |
/* | |
Create instance of our receiving Ruby class | |
*/ | |
rb_require("./ruby_code"); | |
VALUE test_object = rb_class_new_instance(0, NULL, rb_const_get(rb_cObject, rb_intern("TestKlass"))); | |
/* | |
Pass wrapped struct to print_info method on the instance of TestKlass | |
*/ | |
rb_funcall(test_object, rb_intern("print_info"), 1, wrapped_address); | |
/* | |
Demonstrate #town= method works | |
*/ | |
printf("Back in C, \"address.town\" is now %s\n", adr.town); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# If you use rb_define_class("Address", rb_cObject) | |
# instead of rb_class_new then this would reopen that | |
# class and redefine the inspect method. | |
class Address | |
def inspect | |
"Replaced #inspect: <Address: town:#{town}>" | |
end | |
end | |
class TestKlass | |
def print_info(struct) | |
puts "In Ruby" | |
puts struct.inspect | |
puts struct.town | |
struct.town = "Tokyo" | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment