accessing C from Ruby part

hlogmans
2016-02-05 16:12:26 +01:00
parent 38af9344d0
commit 4af5a369a1
+36 -3
@@ -1,12 +1,12 @@
## Building your Ruby environment
You can create classes both from C and Ruby together. Define the class in Ruby code just as a regular Ruby class, and then add C-code the manipulate the class definition.
You can create classes both from C and Ruby together. Define the class in Ruby code just as a regular Ruby class, and then add C-code the manipulate the class definition. Or define everything in C. Your choice.
### Access Ruby from C
Lets first define some class in Ruby code, and try to access this from C:
Create a file `wiki-example.rb` with the following content:
Create a file `wiki-example.rb` with the following content. This class is already prepared for the next section (manipulating Ruby classes from C). We now only need the 'get_version' method.
`````
module WikiExample
@@ -74,4 +74,37 @@ Compile this code with `gcc -std=c99 -Iinclude wiki-example.c build/host/lib/l
### Calling C methods from Ruby
Coming soon...
The strategy is first to update the existing class. Here we add a C-method to the class, but we can even define the module and class from C.
To add a method to a class, we first need a reference to the class. We can copy the lines from the first example for getting a reference to the class WikiManager, of just insert the next lines just before the `If crashed...` comment line.
`````
// add the method to the WikiManager class
mrb_define_method(mrb, class, "_we_connected", we_connected, MRB_ARGS_NONE());
// call the connect method on WikiManager
mrb_value res2 = mrb_funcall(mrb, c, "connect", 0);
`````
Then we add the following method between the `#include` and `int main` lines:
`````
mrb_value
we_connected(mrb_state* mrb, mrb_value self){
// we need an int from the args
mrb_int i = 0;
// retrieve one arg of type int (see mruby.h)
mrb_get_args(mrb, "i", &i);
// we always need to return a mrb_value object, and mrb_bool_value converts a C bool to a mrb_value.
return mrb_bool_value(i >= 2);
}
`````
Compile (see above) and run. You will get the output `result: 2`. Now edit the Ruby file and change the get_version to return 1. Do not compile, just run the executable again, and see the output `result: 1
Connection failed`.
This will give you unlimited results, as you don't even need to recompile to update your Ruby code. Image writing unit-tests in Ruby calling your C-methods in classes. You will be able to mock classes the Ruby-way.
Passing the arguments is quite straightforward (both ways). But someone might update this page with some code on how to pass a C struct to Ruby and use the result.