开发者

Embedding Ruby, calling a function from C

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


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.


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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜