Skip to content

Instantly share code, notes, and snippets.

@mattwildig
Created January 19, 2012 23:31
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save mattwildig/1643711 to your computer and use it in GitHub Desktop.
Save mattwildig/1643711 to your computer and use it in GitHub Desktop.
/*
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);
}
# 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
@matejuh
Copy link

matejuh commented Apr 19, 2012

Is it also possible to have a class Foo in which I initialize a struct Address, wrap it to Ruby class object and use this object as attribute of Foo class? I'm not able to get it working. Wraping struct inside Ruby class is clear, but I'm not able to call method on Foo class in which I initialize struct and wrap it into other Ruby class... Thanks in advance.

@mattwildig
Copy link
Author

@matejuh I don't understand what you're trying to do. Can you give an example of what you want to be able to do?

@mattwildig
Copy link
Author

@matejuh have a look at this other gist: https://gist.github.com/2424479. Is it something like that you're after?

@matejuh
Copy link

matejuh commented Apr 20, 2012

Thanks, this is exactly what I needed. My problem was that I didn't realised, that memory for local allocated struts is released automaticaly and didn't used malloc...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment