public
Created

  • Download Gist
embed.c
C
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
/*
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);
 
}
ruby_code.rb
Ruby
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
# 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

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.

@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?

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

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...

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.