Pergunta

Estou escrevendo um aplicativo que chama o código Ruby de c.Estou tendo um pouco de dificuldade e gostaria de saber se alguém poderia me indicar a direção do rito.

Atualmente tenho no meu C.

#include ruby.h

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

Meu arquivo Ruby está no mesmo diretório do meu arquivo c e é chamado myRubyFile.rb e contém uma definição da função RubyFunction().

Isso é uma redução do que eu realmente quero fazer, apenas tornando-o mais legível para outras pessoas.Eu só preciso de alguns comentários sobre se este é o método correto para chamar o código Ruby do meu arquivo c.

Cumprimentos

Foi útil?

Solução

Resposta curta:

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

Resposta mais longa:

O primeiro argumento a rb_funcall é o receptor da chamada do método.

Supondo que você defpreparado RubyFunction() fora de qualquer classe explícita ou contexto de módulo, então ele é adicionado à autoclasse do implícito, objeto principal no "nível superior" de cada Ruby VM.

Em Ruby, este objeto é acessível como o nível superior 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

Em C abaixo de 1.9 é acessível conforme indicado acima.

Outras dicas

Eu tento usar a seguinte abordagem:

Estrutura básica para compartilhar dados

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

Crie uma função para chamar objetos Ruby em alguma parte do seu código

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

Em alguma parte do seu código ...

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

É sempre uma boa ideia agrupar rb_funcall com rb_protect.

Outra coisa interessante é conhecer os parâmetros do callback, uma abordagem é a seguinte

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

Eu não gosto de chamar Ruby de dentro de C, a menos que você tenha um projeto C complexo que não deseja reconstruir em Ruby.

Existem duas maneiras de interagir entre C e Ruby.Você pode estender Ruby com código escrito em C.Ver GOLE.

Ou você pode incorporar Ruby, veja aqui, aqui e aqui.

Aliás, o que você mencionou é "incorporar" Ruby, não "estender" Ruby.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top