00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "rubyextension.h"
00020
00021 #include <st.h>
00022
00023 #include <qmap.h>
00024 #include <qstring.h>
00025
00026 #include "api/list.h"
00027
00028 #include "rubyconfig.h"
00029
00030 namespace Kross {
00031
00032 namespace Ruby {
00033
00034
00035 class RubyExtensionPrivate {
00036 friend class RubyExtension;
00037
00038 Kross::Api::Object::Ptr m_object;
00039
00040 static VALUE s_krossObject;
00041 };
00042
00043 VALUE RubyExtensionPrivate::s_krossObject = 0;
00044
00045 VALUE RubyExtension::method_missing(int argc, VALUE *argv, VALUE self)
00046 {
00047 #ifdef KROSS_RUBY_EXTENSION_DEBUG
00048 kdDebug() << "method_missing(argc, argv, self)" << endl;
00049 #endif
00050 if(argc < 1)
00051 {
00052 return 0;
00053 }
00054 #ifdef KROSS_RUBY_EXTENSION_DEBUG
00055 kdDebug() << "Converting self to Kross::Api::Object" << endl;
00056 #endif
00057
00058 Kross::Api::Object::Ptr object = toObject( self );
00059 return RubyExtension::call_method(object, argc, argv);
00060 }
00061
00062 VALUE RubyExtension::call_method( Kross::Api::Object::Ptr object, int argc, VALUE *argv)
00063 {
00064 QString funcname = rb_id2name(SYM2ID(argv[0]));
00065 QValueList<Api::Object::Ptr> argsList;
00066 #ifdef KROSS_RUBY_EXTENSION_DEBUG
00067 kdDebug() << "Building arguments list for function : " << funcname << " there are " << (argc-1) << " arguments." << endl;
00068 #endif
00069 for(int i = 1; i < argc; i++)
00070 {
00071 Kross::Api::Object::Ptr obj = toObject(argv[i]);
00072 if(obj) argsList.append(obj);
00073 }
00074 Kross::Api::Object::Ptr result;
00075 if(object->hasChild(funcname)) {
00076 #ifdef KROSS_RUBY_EXTENSION_DEBUG
00077 kdDebug() << QString("Kross::Ruby::RubyExtension::method_missing name='%1' is a child object of '%2'.").arg(funcname).arg(object->getName()) << endl;
00078 #endif
00079 result = object->getChild(funcname)->call(QString::null, new Api::List(argsList));
00080 }
00081 else {
00082 #ifdef KROSS_RUBY_EXTENSION_DEBUG
00083 kdDebug() << QString("Kross::Ruby::RubyExtension::method_missing try to call function with name '%1' in object '%2'.").arg(funcname).arg(object->getName()) << endl;
00084 #endif
00085 result = object->call(funcname, new Api::List(argsList));
00086 }
00087
00088 return toVALUE(result);
00089 }
00090
00091 RubyExtension::RubyExtension(Kross::Api::Object::Ptr object) : d(new RubyExtensionPrivate())
00092 {
00093 d->m_object = object;
00094 }
00095
00096
00097 RubyExtension::~RubyExtension()
00098 {
00099 }
00100
00101 typedef QMap<QString, Kross::Api::Object::Ptr> mStrObj;
00102
00103 int RubyExtension::convertHash_i(VALUE key, VALUE value, VALUE vmap)
00104 {
00105 QMap<QString, Kross::Api::Object::Ptr>* map;
00106 Data_Get_Struct(vmap, mStrObj, map);
00107 if (key != Qundef)
00108 {
00109 Kross::Api::Object::Ptr o = RubyExtension::toObject( value );
00110 if(o) map->replace(STR2CSTR(key), o);
00111 }
00112 return ST_CONTINUE;
00113 }
00114
00115 Kross::Api::Object::Ptr RubyExtension::toObject(VALUE value)
00116 {
00117 #ifdef KROSS_RUBY_EXTENSION_DEBUG
00118 kdDebug() << "RubyExtension::toObject of type " << TYPE(value) << endl;
00119 #endif
00120 switch( TYPE( value ) )
00121 {
00122 case T_DATA:
00123 {
00124 #ifdef KROSS_RUBY_EXTENSION_DEBUG
00125 kdDebug() << "Object is a Kross Object" << endl;
00126 #endif
00127 VALUE result = rb_funcall(value, rb_intern("kind_of?"), 1, RubyExtensionPrivate::s_krossObject );
00128 if(TYPE(result) == T_TRUE)
00129 {
00130 RubyExtension* objectExtension;
00131 Data_Get_Struct(value, RubyExtension, objectExtension);
00132 Kross::Api::Object::Ptr object = objectExtension->d->m_object;
00133 return object;
00134 } else {
00135 kdWarning() << "Cannot yet convert standard ruby type to kross object" << endl;
00136 return 0;
00137 }
00138 }
00139 case T_FLOAT:
00140 return new Kross::Api::Variant(NUM2DBL(value));
00141 case T_STRING:
00142 return new Kross::Api::Variant(QString(STR2CSTR(value)));
00143 case T_ARRAY:
00144 {
00145 QValueList<Kross::Api::Object::Ptr> l;
00146 for(int i = 0; i < RARRAY(value)->len; i++)
00147 {
00148 Kross::Api::Object::Ptr o = toObject( rb_ary_entry( value , i ) );
00149 if(o) l.append(o);
00150 }
00151 return new Kross::Api::List(l);
00152 }
00153 case T_FIXNUM:
00154 return new Kross::Api::Variant((Q_LLONG)FIX2INT(value));
00155 case T_HASH:
00156 {
00157 QMap<QString, Kross::Api::Object::Ptr> map;
00158 VALUE vmap = Data_Wrap_Struct(rb_cObject, 0,0, &map);
00159 rb_hash_foreach(value, (int (*)(...))convertHash_i, vmap);
00160 return new Kross::Api::Dict(map);
00161 }
00162 case T_BIGNUM:
00163 {
00164 return new Kross::Api::Variant((Q_LLONG)NUM2LONG(value));
00165 }
00166 case T_TRUE:
00167 {
00168 return new Kross::Api::Variant(true);
00169 }
00170 case T_FALSE:
00171 {
00172 return new Kross::Api::Variant(false);
00173 }
00174 case T_SYMBOL:
00175 {
00176 return new Kross::Api::Variant(QString(rb_id2name(SYM2ID(value))));
00177 }
00178 case T_MATCH:
00179 case T_OBJECT:
00180 case T_FILE:
00181 case T_STRUCT:
00182 case T_REGEXP:
00183 case T_MODULE:
00184 case T_ICLASS:
00185 case T_CLASS:
00186 kdWarning() << QString("This ruby type '%1' cannot be converted to a Kross::Api::Object").arg(TYPE(value)) << endl;
00187 default:
00188 case T_NIL:
00189 return 0;
00190 }
00191 }
00192
00193 VALUE RubyExtension::toVALUE(const QString& s)
00194 {
00195 return s.isNull() ? rb_str_new2("") : rb_str_new2(s.latin1());
00196 }
00197
00198 VALUE RubyExtension::toVALUE(QStringList list)
00199 {
00200 VALUE l = rb_ary_new();
00201 for(QStringList::ConstIterator it = list.constBegin(); it != list.constEnd(); ++it)
00202 rb_ary_push(l, toVALUE(*it));
00203 return l;
00204 }
00205
00206
00207 VALUE RubyExtension::toVALUE(QMap<QString, QVariant> map)
00208 {
00209 VALUE h = rb_hash_new();
00210 for(QMap<QString, QVariant>::Iterator it = map.begin(); it != map.end(); ++it)
00211 rb_hash_aset(h, toVALUE(it.key()), toVALUE(it.data()) );
00212 return h;
00213
00214 }
00215
00216 VALUE RubyExtension::toVALUE(QValueList<QVariant> list)
00217 {
00218 VALUE l = rb_ary_new();
00219 for(QValueList<QVariant>::Iterator it = list.begin(); it != list.end(); ++it)
00220 rb_ary_push(l, toVALUE(*it));
00221 return l;
00222 }
00223
00224
00225 VALUE RubyExtension::toVALUE(const QVariant& variant)
00226 {
00227
00228 switch(variant.type()) {
00229 case QVariant::Invalid:
00230 return Qnil;
00231 case QVariant::Bool:
00232 return (variant.toBool()) ? Qtrue : Qfalse;
00233 case QVariant::Int:
00234 return INT2FIX(variant.toInt());
00235 case QVariant::UInt:
00236 return UINT2NUM(variant.toUInt());
00237 case QVariant::Double:
00238 return rb_float_new(variant.toDouble());
00239 case QVariant::Date:
00240 case QVariant::Time:
00241 case QVariant::DateTime:
00242 case QVariant::ByteArray:
00243 case QVariant::BitArray:
00244 case QVariant::CString:
00245 case QVariant::String:
00246 return toVALUE(variant.toString());
00247 case QVariant::StringList:
00248 return toVALUE(variant.toStringList());
00249 case QVariant::Map:
00250 return toVALUE(variant.toMap());
00251 case QVariant::List:
00252 return toVALUE(variant.toList());
00253
00254
00255
00256
00257
00258 case QVariant::LongLong: {
00259 return INT2NUM((long)variant.toLongLong());
00260 }
00261 case QVariant::ULongLong:
00262 return UINT2NUM((unsigned long)variant.toULongLong());
00263 default: {
00264 kdWarning() << QString("Kross::Ruby::RubyExtension::toVALUE(QVariant) Not possible to convert the QVariant type '%1' to a VALUE.").arg(variant.typeName()) << endl;
00265 return Qundef;
00266 }
00267 }
00268 }
00269
00270 VALUE RubyExtension::toVALUE(Kross::Api::Object::Ptr object)
00271 {
00272 if(! object) {
00273 return 0;
00274 }
00275
00276 if(object->getClassName() == "Kross::Api::Variant") {
00277 QVariant v = static_cast<Kross::Api::Variant*>( object.data() )->getValue();
00278 return toVALUE(v);
00279 }
00280
00281 if(object->getClassName() == "Kross::Api::List") {
00282 Kross::Api::List* list = static_cast<Kross::Api::List*>( object.data() );
00283 return toVALUE((Kross::Api::List::Ptr)list);
00284 }
00285
00286 if(object->getClassName() == "Kross::Api::Dict") {
00287 Kross::Api::Dict* dict = static_cast<Kross::Api::Dict*>( object.data() );
00288 return toVALUE((Kross::Api::Dict::Ptr)dict);
00289 }
00290
00291 if(RubyExtensionPrivate::s_krossObject == 0)
00292 {
00293 RubyExtensionPrivate::s_krossObject = rb_define_class("KrossObject", rb_cObject);
00294 rb_define_method(RubyExtensionPrivate::s_krossObject, "method_missing", (VALUE (*)(...))RubyExtension::method_missing, -1);
00295 }
00296 return Data_Wrap_Struct(RubyExtensionPrivate::s_krossObject, 0, free, new RubyExtension(object) );
00297 }
00298
00299 VALUE RubyExtension::toVALUE(Kross::Api::List::Ptr list)
00300 {
00301 VALUE l = rb_ary_new();
00302 uint count = list ? list->count() : 0;
00303 for(uint i = 0; i < count; i++)
00304 rb_ary_push(l, toVALUE(list->item(i)));
00305 return l;
00306
00307 }
00308
00309 }
00310
00311 }