From: Luis C Date: 2016-10-10T13:43:44+01:00 Subject: [ruby-core:77538] ruby callback issue (no implicit conversion of nil into String) --===============1231274630== Content-Type: multipart/alternative; boundary=94eb2c07abd24e0e84053e821ccf --94eb2c07abd24e0e84053e821ccf Content-Type: text/plain; charset=UTF-8 Hi all, The following code was working with swig 3.0 and with ruby < 2.3. So probably the problem is on the ruby interpreter. However, because I just swig to wrap the classes may be is something wrong on the definition or I miss something. I got the error "no implicit conversion of nil into String (TypeError)" from the callback parameter but if I access from a new instance, works. This have been working in old versions of ruby. Any similar problems? File compile.sh #!/bin/bash swig -globalmodule -c++ -ruby ruby_wrapper.i g++ -fPIC -std=c++11 -I/usr/include/ruby -c Callback.cc ruby_wrapper_wrap.cxx g++ -fPIC -shared -std=c++11 Callback.o ruby_wrapper_wrap.o -o example.so -lruby File Callback.h #ifndef SRC_CALLBACK_H_ #define SRC_CALLBACK_H_ #include #include "MyClass.h" #include class Callback { public: Callback():callback_set_(false),callback_(Qnil),memory_wrapper_(Qnil),cc("another") { memory_wrapper_ = Data_Wrap_Struct(0 /* klass */, staticMark, NULL, static_cast(this)); rb_gc_register_address(&memory_wrapper_); } virtual ~Callback() { rb_gc_unregister_address(&memory_wrapper_);} bool haveCallback() const { return callback_set_;} void setCallback(VALUE callback); void executeCallback(MyClass *c); void run(); protected: static void staticMark(Callback *me) { me->mark(); } void mark(); private: bool callback_set_; VALUE callback_; VALUE memory_wrapper_; MyClass cc; }; #endif // SRC_CALLBACK_H_ File Callback.cc #include "Callback.h" void Callback::setCallback(VALUE callback) { if (!NIL_P(callback)) { // Verify the number of arguments of the callback by calling the method arity VALUE value = rb_funcall(callback,rb_intern("arity"),0); int nargs = NUM2INT(value); if (nargs != 1) { rb_raise(rb_eRuntimeError,"Object should have one parameter.\n"); } callback_ = callback; callback_set_ = true; } else { callback_ = Qnil; callback_set_ = false; } } void Callback::executeCallback(MyClass *c) { if (!NIL_P(callback_)) { ID id = rb_intern("MyClass"); if (rb_const_defined(rb_cObject, id)) { VALUE rbClass = rb_const_get(rb_cObject,id); VALUE rbData = Data_Wrap_Struct(rbClass, 0, 0, c); rb_funcall(callback_,rb_intern("call"), 1, rbData); } } } void Callback::run() { executeCallback(&cc); } void Callback::mark() { if (!NIL_P(callback_)) { rb_gc_mark(callback_); } } File MyClass.h #ifndef SRC_MYCLASS_H_ #define SRC_MYCLASS_H_ #include class MyClass { public: MyClass():name_("default value"),value_(0) {} MyClass(const std::string name): name_(name),value_(0) {} virtual ~MyClass() {} int getInt() { return value_; } void setInt(int value) { value_ = value; } const char *getName() const { return name_.c_str(); } private: std::string name_; int value_; }; #endif File ruby_wrapper.i %module(directors="1") example %include %{ #include #include "Callback.h" #include "MyClass.h" using namespace std; %} %trackobjects; %rename("my_name") MyClass::getName; %rename("my_int") MyClass::getInt; %rename("my_int=") MyClass::setInt; %rename("callback=") Callback::setCallback; %include "MyClass.h" %include "Callback.h" File test.rb require './example' def callback(cc) print("From the callback") print(cc.methods.sort) print(cc.my_int) print(cc.my_name) end puts "Testing example" a = MyClass.new() print("From the main") print(a.methods.sort) puts a.my_name puts a.my_int c = Callback.new() c.callback = method(:callback) c.run() This code is working in ruby versions < 2.1, Any one have this problem? other way to pass the c++ mapped object as parameter to the callback? Thanks and regards, Luis --94eb2c07abd24e0e84053e821ccf Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: quoted-printable
Hi all,

= The following code=20 was working with swig 3.0 and with ruby < 2.3. So probably the=20 problem is on the ruby interpreter. However, because I just swig to wrap the classes may be is something wrong on the definition or I miss=20 something. I got the error "no implicit conversion of nil into String= =20 (TypeError)" from the callback parameter but if I access from a new in= stance,=20 works. This have been working in old versions of ruby. Any similar=20 problems?

File compile.sh
<= /div>
#!/bin/bash

swig -globalmodule = -c++ -ruby ruby_wrapper.i =C2=A0=C2=A0=C2=A0=C2=A0
g++ -fPIC -std=3Dc++1= 1 -I/usr/include/ruby -c Callback.cc ruby_wrapper_wrap.cxx=C2=A0
g++ -fP= IC -shared -std=3Dc++11 Callback.o ruby_wrapper_wrap.o -o example.so -lruby=

File Callback.h
#ifndef SR= C_CALLBACK_H_
#define SRC_CALLBACK_H_

#include <iostream>#include "MyClass.h"
#include <ruby.h>


clas= s Callback=C2=A0
{
public:
=C2=A0=C2=A0=C2=A0 Callback():callback_= set_(false),callback_(Qnil),memory_wrapper_(Qnil),cc("anothe= r") {
=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 memory_wrapper_ =3D Dat= a_Wrap_Struct(0 /* klass */, staticMark, NULL, static_cast<void*>(thi= s));
=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 rb_gc_register_address(&m= emory_wrapper_);

=C2=A0=C2=A0=C2=A0 }
=C2=A0=C2=A0=C2=A0 vir= tual ~Callback() { rb_gc_unregister_address(&memory_wrapper_);}
=C2=A0=C2=A0=C2=A0 bool haveCallback() const { return callback_set_;}<= br>=C2=A0=C2=A0=C2=A0=C2=A0
=C2=A0=C2=A0=C2=A0 void setCallback(VALUE ca= llback);
=C2=A0=C2=A0=C2=A0 void executeCallback(MyClass *c);=C2=A0
<= br>=C2=A0=C2=A0=C2=A0 void run();
=C2=A0=C2=A0=C2=A0=C2=A0
protected:=
=C2=A0=C2=A0=C2=A0 static void staticMark(Callback *me) { me->mark()= ; }

=C2=A0=C2=A0=C2=A0 void mark();
private:
=C2=A0=C2=A0=C2= =A0 bool callback_set_;
=C2=A0=C2=A0=C2=A0 VALUE callback_;
=C2=A0=C2= =A0=C2=A0 VALUE memory_wrapper_;
=C2=A0=C2=A0=C2=A0 MyClass cc;
};
#endif=C2=A0 // SRC_CALLBACK_H_

File Callback.cc
#include "Callback.h"

void Call= back::setCallback(VALUE callback) {

=C2=A0=C2=A0=C2=A0 if (!NIL_P(ca= llback)) {
=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 // Verify the number of= arguments of the callback by calling the method arity

=C2=A0=C2=A0= =C2=A0 =C2=A0=C2=A0=C2=A0 VALUE value =3D rb_funcall(callback,rb_intern("arity"),0);
=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 int nargs= =3D NUM2INT(value);

=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 if (nargs= !=3D 1) {
=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 rb_r= aise(rb_eRuntimeError,"Object should have one parameter.\n")= ;
=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 }=C2=A0=C2=A0=C2=A0=C2=A0
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 callback_ = =3D callback;
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 callback_set_ =3D true;
=C2=A0=C2=A0= =C2=A0 } else {
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0= =C2=A0 callback_ =3D Qnil;
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 callback_set_ =3D false;
= =C2=A0=C2=A0=C2=A0 }
}


void Callback::executeCallback(MyClass *c) {

=C2=A0=C2=A0=C2=A0 if (!NIL_P(callback_)) {
=C2=A0=C2= =A0=C2=A0 =C2=A0=C2=A0=C2=A0 ID id =3D rb_intern("MyClass");
= =C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 if (rb_const_defined(rb_cObject, id))= {=C2=A0=C2=A0=C2=A0=C2=A0
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0 VALUE rbClass =3D rb_const_get(rb_cObject,id);
=C2=A0= =C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 VALUE rbData =3D Data_Wrap_Struct(rbClass, 0= , 0, c);=C2=A0=C2=A0=C2=A0=C2=A0
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 = =C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 rb_funcall(callbac= k_,rb_intern("call"), 1, rbData);
=C2=A0=C2=A0=C2=A0 =C2= =A0=C2=A0=C2=A0 }
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 }
}
<= br>void Callback::run() {

=C2=A0=C2=A0=C2=A0 executeCallback(&cc= );
}


void Callback::mark() {

=C2=A0=C2=A0=C2=A0 if (!N= IL_P(callback_)) {
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0=C2= =A0=C2=A0 rb_gc_mark(callback_);
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0 }
}

File MyClass.h
#= ifndef SRC_MYCLASS_H_
#define SRC_MYCLASS_H_

#include <iostrea= m>


class MyClass=C2=A0
{
public:
=C2=A0=C2=A0=C2=A0 = MyClass():name_("default value"),value_(0) {}
=C2=A0=C2=A0=C2= =A0 MyClass(const std::string name): name_(name),value_(0) {}
=C2=A0=C2= =A0=C2=A0 virtual ~MyClass() {}=C2=A0

=C2=A0=C2=A0=C2=A0 int getInt(= ) { return value_; }
=C2=A0=C2=A0=C2=A0 void setInt(int value) { value_ = =3D value; }

=C2=A0=C2=A0=C2=A0 const char *getName() const { return= name_.c_str(); }
private:
=C2=A0=C2=A0=C2=A0 std::string name_;=C2= =A0=C2=A0=C2=A0=C2=A0
=C2=A0=C2=A0=C2=A0 int value_;
};

#endif=

File ruby_wrapper.i
%modul= e(directors=3D"1") example=C2=A0
%include <std_string.i>=

%{
#include <iostream>
#include "Callback.h"<= br>#include "MyClass.h"

using namespace std;
%}

= %trackobjects;

%rename("my_name") MyClass::getName;
%re= name("my_int") MyClass::getInt;
%rename("my_int=3D")= MyClass::setInt;
%rename("callback=3D") Callback::setCallback= ;

%include "MyClass.h"
%include "Callback.h"<= br>
File test.rb
require '.= /example'

def callback(cc)=C2=A0
=C2=A0 print("From the = callback")
=C2=A0 print(cc.methods.sort)
=C2=A0 print(cc.my_int)=
=C2=A0 print(cc.my_name)
end

puts "Testing example"=

a =3D MyClass.new()

print("From the main")
prin= t(a.methods.sort)
puts a.my_name
puts a.my_int

c =3D Callback.= new()

c.callback =3D method(:callback)

c.run()

<= div style=3D"font-size:12.8px">This code is working in ruby versions < 2.1, Any one have this problem?=20 other way to pass the c++ mapped object as parameter to the callback?

Thanks and regards,
Luis
--94eb2c07abd24e0e84053e821ccf-- --===============1231274630== Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Disposition: inline Unsubscribe: --===============1231274630==--