Question

I'm writing an app that calls ruby code from c. I am having a little difficulty and wondered if anyone could point me in the rite direction.

I currently have in my C.

#include ruby.h

main()
{
  ruby_init();
  rb_require("myRubyFile");
  rb_funcall(rb_module_new(), rb_intern("RubyFunction"), 0, NULL);
}

My ruby file is in the same directory as my c file and is called myRubyFile.rb and contains a definition of the function RubyFunction().

This is a cut down of what I actually want to do, just making it more readable for others. I just require some feedback as to whether this is the correct method to call ruby code from my c file.

Regards

Was it helpful?

Solution

Short answer:

extern VALUE rb_vm_top_self(void); /* Assumes 1.9.  Under 1.8, use the global
                                    * VALUE ruby_top_self
                                    */
...
rb_funcall(rb_vm_top_self(),           /* irb> RubyFunction()                   */
           rb_intern("RubyFunction"),  /* irb> self.RubyFunction() # same thing */
           0,
           NULL);

Longer answer:

The first argument to rb_funcall is the receiver of the method call.

Assuming you defined RubyFunction() outside of any explicit class or module context, then it is added to the eigenclass of the implicit, main object at the "top level" of every ruby vm.

In ruby, this object is accessible as the top-level self:

$ cat myRubyFile.rb
# file: myRubyFile.rb
def foo
  puts "foo"
end

$ irb
irb> require "myRubyFile"
=> true
irb> foo
foo
=> nil
irb> self.foo()    # same thing, more explicit
foo
=> nil
irb> self
=> main

In C under 1.9 it is accessible as indicated above.

OTHER TIPS

I try to use the following approach:

Basic struct to share data

typedef struct ruby_shared_data {
    VALUE obj;
    ID method_id;
    int nargs;
    VALUE args[4];
} ruby_shared_data;

Create a function for call ruby objects on some part of your code

static VALUE ruby_callback(VALUE ptr) {

    ruby_shared_data *data = (ruby_shared_data*)ptr;

    return rb_funcall2(data->obj,data->method_id,data->nargs,data->args);
}

On some part of your code...

    ruby_shared_data rbdata;

    rbdata.obj = obj;
    rbdata.method_id = rb_intern("mycallback");
    rbdata.nargs = 1;
    rbdata.args[0] = rb_str_new2("im a parameter");

    int error = 0;
    VALUE result = rb_protect(ruby_callback,(VALUE)&rbdata,&error);

    if (error)
            throw "Ruby exception on callback";

Is always a good idea to wrap rb_funcall with rb_protect.

Another interesting thing is to know the parameters of the callback, one approach is the following

ruby_shared_data rbdata;

rbdata.obj = callback;
rbdata.method_id = rb_intern("arity"); 
rbdata.nargs = 0;

int error = 0;
VALUE result = rb_protect(ruby_callback,(VALUE)&rbdata,&error);

if (error)
        throw "Ruby exception on callback";

narguments = NUM2INT(result);

I don't like to call ruby from inside C unless you have complex C project which you don't want to re-build in ruby.

There are two ways to interact between C and ruby. You can extend ruby with code written in C. See SWIG.

Or you can embed ruby, see here, here and here.

BTW, what do you mention is "embed" ruby, not "extend" ruby.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top