19#include "rubyextension.h"
20#include "rubyinterpreter.h"
22#define HAVE_STRLCAT_PROTO 1
23#define HAVE_STRLCPY_PROTO 1
30#define STR2CSTR(x) StringValuePtr(x)
38#include "rubyconfig.h"
45class RubyExtensionPrivate {
46 friend class RubyExtension;
50 static VALUE s_krossObject;
51 static VALUE s_krossException;
54VALUE RubyExtensionPrivate::s_krossObject = 0;
55VALUE RubyExtensionPrivate::s_krossException = 0;
57VALUE RubyExtension::method_missing(
int argc, VALUE *argv, VALUE self)
59#ifdef KROSS_RUBY_EXTENSION_DEBUG
60 krossdebug(
"method_missing(argc, argv, self)");
66#ifdef KROSS_RUBY_EXTENSION_DEBUG
67 krossdebug(
"Converting self to Kross::Api::Object");
71 return RubyExtension::call_method(
object, argc, argv);
76 TQString funcname = rb_id2name(SYM2ID(argv[0]));
77 TQValueList<Api::Object::Ptr> argsList;
78#ifdef KROSS_RUBY_EXTENSION_DEBUG
79 krossdebug(TQString(
"Building arguments list for function: %1 there are %2 arguments.").arg(funcname).arg(argc-1));
81 for(
int i = 1; i < argc; i++)
84 if(obj) argsList.append(obj);
89 Kross::Api::Callable* callable =
dynamic_cast<Kross::Api::Callable*
>(
object.data());
90 if(callable && callable->
hasChild(funcname)) {
91#ifdef KROSS_RUBY_EXTENSION_DEBUG
92 krossdebug( TQString(
"Kross::Ruby::RubyExtension::method_missing name='%1' is a child object of '%2'.").arg(funcname).arg(object->getName()) );
94 result = callable->
getChild(funcname)->call(TQString(),
new Api::List(argsList));
97#ifdef KROSS_RUBY_EXTENSION_DEBUG
98 krossdebug( TQString(
"Kross::Ruby::RubyExtension::method_missing try to call function with name '%1' in object '%2'.").arg(funcname).arg(object->getName()) );
100 result =
object->call(funcname,
new Api::List(argsList));
104#ifdef KROSS_RUBY_EXTENSION_DEBUG
105 krossdebug(
"c++ exception catched, raise a ruby error");
107 throw convertFromException(exception);
110 throw convertFromException(
new Kross::Api::Exception(
"Unknow error" ));
115 return toVALUE(result);
118void RubyExtension::delete_object(
void*
object)
126void RubyExtension::delete_exception(
void*
object)
128 Kross::Api::Exception* exc =
static_cast<Kross::Api::Exception*
>(object);
129 exc->_TDEShared_unref();
135 d->m_object = object;
145typedef TQMap<TQString, Kross::Api::Object::Ptr> mStrObj;
147int RubyExtension::convertHash_i(VALUE key, VALUE value, VALUE vmap)
149 TQMap<TQString, Kross::Api::Object::Ptr>* map;
150 Data_Get_Struct(vmap, mStrObj, map);
154 if(o) map->replace(STR2CSTR(key), o);
159bool RubyExtension::isOfExceptionType(VALUE value)
161 VALUE result = rb_funcall(value, rb_intern(
"kind_of?"), 1, RubyExtensionPrivate::s_krossException );
162 return (TYPE(result) == T_TRUE);
165bool RubyExtension::isOfObjectType(VALUE value)
167 VALUE result = rb_funcall(value, rb_intern(
"kind_of?"), 1, RubyExtensionPrivate::s_krossObject );
168 return (TYPE(result) == T_TRUE);
174 if( isOfExceptionType(value) )
176 Kross::Api::Exception* exception;
177 Data_Get_Struct(value, Kross::Api::Exception, exception);
185 if(RubyExtensionPrivate::s_krossException == 0)
189 exc->_TDEShared_ref();
190 return Data_Wrap_Struct(RubyExtensionPrivate::s_krossException, 0, RubyExtension::delete_exception, exc.data() );
196#ifdef KROSS_RUBY_EXTENSION_DEBUG
197 krossdebug(TQString(
"RubyExtension::toObject of type %1").arg(TYPE(value)));
199 switch( TYPE( value ) )
203#ifdef KROSS_RUBY_EXTENSION_DEBUG
206 if( isOfObjectType(value) )
213 krosswarning(
"Cannot yet convert standard ruby type to kross object");
218 return new Kross::Api::Variant(NUM2DBL(value));
220 return new Kross::Api::Variant(TQString(STR2CSTR(value)));
223 TQValueList<Kross::Api::Object::Ptr> l;
225 for(
int i = 0; i < RARRAY_LEN(value); i++)
227 for(
int i = 0; i < RARRAY(value)->len; i++)
233 return new Kross::Api::List(l);
236 return new Kross::Api::Variant((TQ_LLONG)FIX2INT(value));
239 TQMap<TQString, Kross::Api::Object::Ptr> map;
240 VALUE vmap = Data_Wrap_Struct(rb_cObject, 0,0, &map);
241 rb_hash_foreach(value, (
int (*)(...))convertHash_i, vmap);
242 return new Kross::Api::Dict(map);
246 return new Kross::Api::Variant((TQ_LLONG)NUM2LONG(value));
250 return new Kross::Api::Variant(
true);
254 return new Kross::Api::Variant(
false);
258 return new Kross::Api::Variant(TQString(rb_id2name(SYM2ID(value))));
268 krosswarning(TQString(
"This ruby type '%1' cannot be converted to a Kross::Api::Object").arg(TYPE(value)));
275VALUE RubyExtension::toVALUE(
const TQString& s)
277 return s.isNull() ? rb_str_new2(
"") : rb_str_new2(s.latin1());
280VALUE RubyExtension::toVALUE(TQStringList list)
282 VALUE l = rb_ary_new();
283 for(TQStringList::ConstIterator it = list.constBegin(); it != list.constEnd(); ++it)
284 rb_ary_push(l, toVALUE(*it));
289VALUE RubyExtension::toVALUE(TQStringVariantMap map)
291 VALUE h = rb_hash_new();
292 for(TQStringVariantMap::Iterator it = map.begin(); it != map.end(); ++it)
293 rb_hash_aset(h, toVALUE(it.key()), toVALUE(it.data()) );
298VALUE RubyExtension::toVALUE(TQValueList<TQVariant> list)
300 VALUE l = rb_ary_new();
301 for(TQValueList<TQVariant>::Iterator it = list.begin(); it != list.end(); ++it)
302 rb_ary_push(l, toVALUE(*it));
307VALUE RubyExtension::toVALUE(
const TQVariant& variant)
310 switch(variant.type()) {
311 case TQVariant::Invalid:
313 case TQVariant::Bool:
314 return (variant.toBool()) ? Qtrue : Qfalse;
316 return INT2FIX(variant.toInt());
317 case TQVariant::UInt:
318 return UINT2NUM(variant.toUInt());
319 case TQVariant::Double:
320 return rb_float_new(variant.toDouble());
321 case TQVariant::Date:
322 case TQVariant::Time:
323 case TQVariant::DateTime:
324 case TQVariant::ByteArray:
325 case TQVariant::BitArray:
326 case TQVariant::CString:
327 case TQVariant::String:
328 return toVALUE(variant.toString());
329 case TQVariant::StringList:
330 return toVALUE(variant.toStringList());
332 return toVALUE(variant.toMap());
333 case TQVariant::List:
334 return toVALUE(variant.toList());
340 case TQVariant::LongLong: {
341 return INT2NUM((
long)variant.toLongLong());
343 case TQVariant::ULongLong:
344 return UINT2NUM((
unsigned long)variant.toULongLong());
346 krosswarning( TQString(
"Kross::Ruby::RubyExtension::toVALUE(TQVariant) Not possible to convert the TQVariant type '%1' to a VALUE.").arg(variant.typeName()) );
354 if(!
object.data()) {
357 if(object->getClassName() ==
"Kross::Api::Variant") {
358 TQVariant v =
static_cast<Kross::Api::Variant*
>(
object.data() )->getValue();
362 if(object->getClassName() ==
"Kross::Api::List") {
363 Kross::Api::List* list =
static_cast<Kross::Api::List*
>(
object.data() );
367 if(object->getClassName() ==
"Kross::Api::Dict") {
368 Kross::Api::Dict* dict =
static_cast<Kross::Api::Dict*
>(
object.data() );
372 if(RubyExtensionPrivate::s_krossObject == 0)
375 rb_define_method(RubyExtensionPrivate::s_krossObject,
"method_missing", (VALUE (*)(...))RubyExtension::method_missing, -1);
377 return Data_Wrap_Struct(RubyExtensionPrivate::s_krossObject, 0, RubyExtension::delete_object,
new RubyExtension(
object) );
382 VALUE l = rb_ary_new();
383 uint count = list ? list->count() : 0;
384 for(uint i = 0; i < count; i++)
385 rb_ary_push(l, toVALUE(list->item(i)));
bool hasChild(const TQString &name) const
Returns if the defined child is avaible.
Object::Ptr getChild(const TQString &name) const
Return the defined child or NULL if there is no such object with that name avaible.
TDESharedPtr< Exception > Ptr
Shared pointer to implement reference-counting.
TDESharedPtr< List > Ptr
Shared pointer to implement reference-counting.
TDESharedPtr< Object > Ptr
Shared pointer to implement reference-counting.
RubyExtension(Kross::Api::Object::Ptr object)
Constructor.
~RubyExtension()
Destructor.
static VALUE krossModule()
The Ruby plugin for the Kross scripting framework.
The Kross scripting bridge to embed scripting functionality into an application.
KOFFICE_EXPORT void krossdebug(const TQString &s)
Debugging function.
KOFFICE_EXPORT void krosswarning(const TQString &s)
Warning function.