3

I am facing an issue with calling of mruby VM in C. I could invoke the mruby vm and execute the ruby code from C. I could also trigger the methods defined in the ruby code as well. But I am facing issue while trying to read the return value of the ruby method. I have provided my example scenario below.

CODE:

#include <stdlib.h>
#include <stdio.h>

#include <mruby.h>
#include <mruby/compile.h>

int main(void)
{
  mrb_state *mrb = mrb_open();
  char code[] = "def helloworld() return'OK' end";
  printf("Executing Ruby code from C!\n");

  mrb_load_string(mrb, code);
  mrb_load_string(mrb, "helloworld()");
  // How to read the return value?
  return 0;
}

I am not sure if this is the right way of calling the ruby methods? I couldnt find any documentation or examples on the web. Anyone who tried calling ruby code via c (using mruby) can you please help me?

Regards,

programmer
  • 582
  • 2
  • 4
  • 16

1 Answers1

2

The return value of mrb_load_string() is the value of the last evaluated expression. But it's also mrb_undef_value() on failure that happened during parsing or code generation like a syntax error. In general the exc member of mrb_state is non-null if there was an uncaught exception:

mrb_value rv = mrb_load_string(mrb, "helloworld()");
if (mrb->exc) {            // if uncaught exception …
   if (!mrb_undef_p(rv)) { // … during execution/run-time
     mrb_print_error(mrb); // write backtrace and other details to stderr
   }
}
else {
  mrb_p(mrb, rv); // similar to Kernel#p
}

If you only want to call a method, the mrb_funcall() family of functions can be used:

mrb_value rv = mrb_funcall(mrb, mrb_top_self(mrb), "helloworld", 0);

Or:

mrb_value rv = mrb_funcall_argv(mrb, mrb_top_self(mrb), mrb_intern_cstr(mrb, "helloworld"), 0, NULL);

Then the parser and code generator won't be used, thus it'll be faster and unless they're used elsewhere, the executable or (shared) library will be much smaller too. Plus mrb_undef_value() isn't a possible return value, otherwise checking for an uncaught exception and retrieving the return value can be done in the same way.

cremno
  • 4,672
  • 1
  • 16
  • 27
  • ,I tried the mrb_funcall but I did not know how to pass arguments. Also mrb_funcall did not work for me. Can you give me an example which can call 'helloworld' and pass an argument (Ex: 'test', 123) and read the return value? This is my requirement. Also thanks for the code snippet and explanation. – programmer Jun 10 '15 at 04:26
  • 1
    @programmer: `mrb_funcall(mrb, mrb_top_self(mrb), "helloworld", 2, mrb_str_new_cstr(mrb, "test"), mrb_fixnum_value(123));` – cremno Jun 10 '15 at 05:00
  • Thanks, and how to read the return value (here from ruby I was returning 'OK'). – programmer Jun 10 '15 at 05:46
  • @programmer: The same way as with `mrb_load_string()` (except the `mrb_undef_value()` part since it doesn't use the parser/codegen). I'll edit the post. – cremno Jun 10 '15 at 05:50
  • Thanks! this mrb_p(mrb, rv); did print the return value "OK". One more thing, how do I get rv value to char* or (std::string in C++)? This would be good for me to proceed! :). Alsoif I use: mrb_funcall_argv, can you share with me 1 example on how to pass some inputs (say my ruby code was like this: def helloworld(var1, var2) ... where var1 is a string and var 2 is a integer)? – programmer Jun 10 '15 at 09:08
  • @programmer: `mrb_inspect()` (calls `#inspect` and ensures that the value to be returned is a Ruby string). Then use either the `RSTRING_PTR()` macro or, if it shouldn't contain NUL (which you usually want to do in C and perhaps even C++), the `mrb_str_to_cstr()` function. – cremno Jun 10 '15 at 09:20
  • @programmer: Also, it would be better to ask a new question since it doesn't have anything to do with your original question. – cremno Jun 10 '15 at 09:22
  • I have a new query on mruby. The url is here: http://stackoverflow.com/questions/30778119/mruby-issue-with-require-and-require-relative can you help me? – programmer Jun 11 '15 at 15:01
  • Like RSTRING_PTR() , if ruby was to return a Boolean value, what is the alternative? I couldnt find anything with R*Bool*. Really appreciate your help here. – programmer Jul 02 '15 at 16:34
  • Just like in Ruby call either `#inspect` (`mrb_inspect()`) or `#to_s` (`mrb_obj_as_string()`). Those functions additionally make sure the return value is a string as `#inspect` could return a float or sth. else and then `RSTRING_PTR()` would not work. – cremno Jul 02 '15 at 17:13