From 4af5a369a146c8872fcda3846a292d147a32f862 Mon Sep 17 00:00:00 2001 From: hlogmans Date: Fri, 5 Feb 2016 16:12:26 +0100 Subject: [PATCH] accessing C from Ruby part --- ...your-Ruby-environment-and-accessing-it..md | 39 +++++++++++++++++-- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/Building-your-Ruby-environment-and-accessing-it..md b/Building-your-Ruby-environment-and-accessing-it..md index b8ce69c..6c09801 100644 --- a/Building-your-Ruby-environment-and-accessing-it..md +++ b/Building-your-Ruby-environment-and-accessing-it..md @@ -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. \ No newline at end of file