From: gga Date: 2007-01-16T22:50:11+09:00 Subject: Re: Ruby and E.V.E. Paradox GD ha escrito: > I'm keeping things fairly simple; I mostly just bind functions/methods > and wrap pointers in opaque data structures (eg. using Data_Wrap_Struct > in the Ruby version). My plan was to store a pointer to the calling class > in an opaque structure and store it in the corresponding Ruby class, so > I can reference it when needed. That's possible, but it can get ugly. Do what SWIG does. Create a hash that stores a mapping between the ruby object and the C++ object (and/or viceversa). Every time you allocate a new class, you enter it in the hash. Every time the free function for the class is called, the mapping is removed from the hash. You can even use ruby's own hashes to do so. That way, you don't need to pass any pointer, and can access any class at any time from any function. Also, if your classes contain or return pointers to other C++ classes, you need to keep telling the GC about it. See the SWIG Zoo/Animal tutorial in the Ruby section. > > I have data structures in the C++ side, no names, so rb_eval_string and > company can't be used. This makes no sense to me. > > > >>- The documentation is not at all clear how you protect something from the > >>garbage collector, or indicate it is no longer in use. > > > > Should some of the tricks used by SWIG be mentioned on the official > Ruby site, perhaps? Seems odd that an offsite source is considered > (mildly) authoritative. Well, all that stuff IS properly documented in the PickAxe, in the extending Ruby section. The PickAxe is somewhat poor in that it does cover properly wrapping methods that return new C++ objects (the Zoo and Animal tutorial in SWIG is a top-notch example of all the headaches you can run into on wrapping a complex library). You also have this, if you haven't read it. http://metaeditor.sourceforge.net/embed/ I found it somewhat confusing, but it is probably another source. > > Okay, so just like an object. Good news. Very elegant and Ruby-ish. :) > Any way to grab the class from the Ruby script? What I really want is > to replace your first line with something like: > > VALUE cFoo = rb_grab_class_from_script("ClassDefinedInScript") > Class names are just constants. If your class is in the global namespace, use: VALUE cFoo = rb_const_get( rb_cObject, rb_intern("YourClass") ); If not, replace rb_cObject for the proper module name. > Each level defines its own class and I need to create an object of > the correct type. I can't find a call to lookup a class name and > return a VALUE. There is probably one, I just don't know what it is. > > >>- rb_protect() is a complete mess. Rather than being able to call an arbitrary > >>function with a void pointer, you are stuck calling something that takes a > >>single VALUE arg. //-------------------------------------------------------------------------------------------- // g++ -fPIC -shared -I/usr/include/ -I /usr/include/ruby/\ // -I/usr/lib/ruby/1.8/x86_64-linux/ callback.cpp -o callback.so // // > irb // irb> require 'callback.so' // irb> wrap() // irb> wrap 'crap', 'hello' // #include #include #define VALUEFUNC(f) ((VALUE (*)(ANYARGS)) f) struct CallbackData_t { void* crapola; VALUE method; VALUE arg0; }; VALUE wrap_callback( VALUE v ) { using namespace std; CallbackData_t* data = static_cast< CallbackData_t* >((void*)v); cerr << "wrap callback got: " << data->crapola << endl; // do any rb_funcall2() or rb_apply() here if ( rb_obj_is_kind_of( data->arg0, rb_cString ) ) cerr << "arg0 is " << StringValueCStr( data->arg0 ) << endl; return Qnil; } VALUE wrap_protect(int argc, VALUE *argv, VALUE self) { CallbackData_t data; data.crapola = (void*)0xDEADBEEF; // 0 mandatory arguments, 2 optional rb_scan_args( argc, argv, "02", &data.method, &data.arg0 ); int error; VALUE result = rb_protect( wrap_callback, VALUE(&data), &error ); if ( error ) rb_raise( rb_eRuntimeError, "Something crappy happened" ); return result; } extern "C" void Init_callback(void) { rb_define_method(rb_cObject, "wrap", VALUEFUNC(wrap_protect), -1); } //-------------------------------------------------------------------------------- > The Python docs look decent, I'd just rather not relearn Python again, > I chose Ruby years ago, I'm good with it, and I like it better than > Python! :) But I'd rather move on from LUA if I can... Python is worse at embedding than Ruby is. So if you have troubles with Ruby, good luck with Python! On python you don't need to just take care of garbage collecting, but of reference counting. It is a royal pain if you are doing it manually like you are. > LUA has some very nice elements; there is a call to get a context, a > call to tear it down, so forth. It works. Indeed. > My knowledge of TCL is non-existent. Keep it that way. If you don't like Lua, TCL will scare the shit out of you. TCL syntax can look pretty but it often does not. It does have one of the best embedding interface for embedding of any language (and 20+ years of knowledge you can rely on). > I've spent close to two days on embedding Ruby and can't get the basic > things I've described working. You should be able to get ruby up and running in about a couple of hours (that's all it took me). Wrapping complex classes that return pointers to other classes and the like, however, is hairy. But SWIG is there to help now. > I dearly want to be completely wrong. You are.