Встраивание Ruby, вызывая функцию от C
-
25-09-2019 - |
Вопрос
Я пишу приложение, которое называет Ruby Code из 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 Code из моего файла C.
С уважением
Решение
Краткий ответ:
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
внутренности 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 это доступно, как указано выше.
Другие советы
Я пытаюсь использовать следующий подход:
Базовая структура для обмена данными
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);
Я не люблюзывать Ruby изнутри C, если у вас нет сложного проекта C, который вы не хотите построить в Ruby.
Есть два способа взаимодействия между C и Ruby. Вы можете продлить Ruby с кодом, написанным в C. см. Усадьба.
Или вы можете встроить Ruby, посмотреть здесь, здесь а также здесь.
Кстати, что вы упоминаете, «встроить» Ruby, а не «расширить» Ruby.