Встраивание Ruby, вызов функции из C - PullRequest
4 голосов
/ 10 мая 2010

Я пишу приложение, которое вызывает код ruby ​​из c. У меня возникли небольшие трудности, и я подумал, может ли кто-нибудь указать мне направление обряда.

В настоящее время у меня есть C.

#include ruby.h

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

Мой ruby-файл находится в том же каталоге, что и мой c-файл, и называется myRubyFile.rb и содержит определение функции RubyFunction ().

Это сокращение от того, что я действительно хочу сделать, просто сделать его более читаемым для других. Мне просто нужна некоторая обратная связь относительно того, является ли этот метод правильным для вызова кода ruby ​​из моего файла c.

Привет

Ответы [ 3 ]

6 голосов
/ 11 мая 2010

Краткий ответ:

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);

Более длинный ответ:

Первым аргументом rb_funcall является получатель вызова метода.

Предполагая, что вы def ined RubyFunction() вне какого-либо явного класса или контекста модуля, он добавляется к собственному классу неявного, главного объекта на «верхнем уровне» каждого ruby ​​vm .

В ruby ​​этот объект доступен как верхний уровень 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

В C под 1.9 он доступен, как указано выше.

0 голосов
/ 10 августа 2015

Я стараюсь использовать следующий подход:

Базовая структура для обмена данными

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

Создать функцию для вызова объектов ruby ​​для некоторой части вашего кода

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);
}

В какой-то части вашего кода ...

    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";

Всегда хорошая идея обернуть rb_funcall с помощью rb_protect.

Еще одна интересная вещь - это знать параметры обратного вызова, один из подходов следующий

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);
0 голосов
/ 10 мая 2010

Мне не нравится вызывать ruby ​​изнутри C, если у вас нет сложного проекта C, который вы не хотите перестраивать в ruby.

Существует два способа взаимодействия между C и ruby.Вы можете расширить ruby ​​с помощью кода, написанного на C. См. SWIG .

Или вы можете встроить ruby, см. здесь , здесь и здесь .

Кстати, что вы упоминаете, это "вставлять" рубин, а не "расширять" рубин.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...