Вызов методов класса Ruby из C ++ - PullRequest
5 голосов
/ 30 января 2009

Я пытаюсь вызвать метод класса из C ++. Я перепробовал все комбинации rb_intern Я мог бы придумать, как это работает, но я ничего не получил.

Пример класса

class CallTest
   def go
    (do something here)
   end
end

Попытка вызова в C ++:

rb_funcall(?, rb_intern("go"), 0);

Что входит в? пространство? Я знаю, если я использую Qnil там, он будет вызывать глобальные функции, но я бы предпочел методы класса.

Я иду в неправильном направлении?

Кроме того, я бы предпочел не знать заранее имя класса, если возможно, но если мне потребуется, чтобы я знал, что это такое, я могу попробовать передав его по имени в мое приложение.

Я использую SWIG для генерации привязки.

Ответы [ 2 ]

7 голосов
/ 30 января 2009

Во-первых, go - это, как вы определили, не метод класса, а метод экземпляра .

Как объектно-ориентированный язык, все методы ruby ​​требуют приемника, то есть объекта, для которого вызывается метод. Для методов экземпляра получатель является экземпляром класса, для методов класса получатель является самим объектом класса.

? заполнитель у вас есть слот для получателя вызова метода.

Если вы хотите оставить его как метод экземпляра, то вам нужно сделать это:

rb_funcall(a_CallTest_instance, rb_intern("go"), 0);

где a_CallTest_instance был экземпляром CallTest, который вы создали с помощью rb_class_new_instance().

Если вы сделаете это методом класса:

class CallTest
  def self.go
    # ...
  end
end

Тогда вам нужно использовать сам класс CallTest в качестве получателя:

rb_funcall(klass, rb_intern("go"), 0);

Вы можете получить ссылку на класс CallTest, используя rb_const_get()

VALUE klass = rb_const_get(rb_cObject, rb_intern('CallTest'));

Используйте rb_cObject там, поскольку CallTest определено в глобальном контексте.

Я бы предложил прочитать главу кирки о расширении рубина.

3 голосов
/ 29 августа 2009

Я также использую SWIG. Эти конкретные примеры файлов должны помочь вам.

1) test.rb

require 'test.so'
class A
    def func1(buffer)
        puts "ruby instance method: #{buffer}"
    end
end
def func2(buffer)
    puts "ruby global method: #{buffer}"
end
module Z
    def Z.func3(buffer)
        puts "ruby module method: #{buffer}"
    end
end

a = A.new
t = Test::Test1.new()
t.call(a, "func1", "Hello", 5)
t.call(method(:func2), "func2", "Yabaaa", 6)
t.call(Z, "func3", "Yahooooooo", 10)

2) test.h:

#include <ruby.h>
class Test1
{
public:
    void call(VALUE obj, char* func_name, const char* buffer, int size)
    {
        VALUE val = rb_str_new(buffer, size);   
        rb_funcall(obj, rb_intern(func_name), 1, val);
    }
};

3) test.i:

%module test

%{
#include "test.h"
%}

%exception
{
    try
    {
        $action
    }
    catch (std::exception& ex)
    {
        static VALUE cpperror = rb_define_class("test Exception", rb_eStandardError);
        rb_raise(cpperror, ex.what());
    }
    catch (...)
    {
        static VALUE cpperror = rb_define_class("test UnknownException", rb_eStandardError);
        rb_raise(cpperror, "Unknown catched");
    }
}

%include "test.h"

ВЫВОД:

ruby ./test.rb 
ruby instance method: Hello
ruby global method: Yabaaa
ruby module method: Yahooooooo
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...