Commit 515b141d authored by Alexander Potashev's avatar Alexander Potashev

ruby: Basic port of the Ruby plugin to Qt5 and Ruby 1.9+

parent b5a9d732
......@@ -70,7 +70,7 @@ endif(PYTHON2_LIBS_FOUND)
# ecm_optional_add_subdirectory(falcon)
# endif(FALCON_FOUND)
# ecm_optional_add_subdirectory(ruby)
ecm_optional_add_subdirectory(ruby)
# ecm_optional_add_subdirectory(java)
feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES)
......
......@@ -4,22 +4,25 @@ if(RUBY_FOUND)
message(STATUS "Found Ruby: ${RUBY_EXECUTABLE} (found version \"${RUBY_VERSION}\")")
endif()
macro_log_feature(RUBY_FOUND
"Ruby" "Ruby libraries" "http://www.ruby-lang.org" FALSE "1.9.x" "Needed to compile the Ruby bindings")
set(krossruby_PART_SRCS
rubyvariant.cpp
rubyinterpreter.cpp
rubyextension.cpp
rubyscript.cpp
rubymodule.cpp
rubycallcache.cpp
rubyobject.cpp
)
rubyvariant.cpp
rubyinterpreter.cpp
rubyextension.cpp
rubyscript.cpp
rubymodule.cpp
rubycallcache.cpp
rubyobject.cpp
)
if(RUBY_FOUND)
include_directories(${RUBY_INCLUDE_DIRS})
kde4_add_plugin(krossruby ${krossruby_PART_SRCS})
target_link_libraries(krossruby ${QT_QTCORE_LIBRARY} ${QT_QTGUI_LIBRARY} ${KDE4_KROSSCORE_LIBS} ${RUBY_LIBRARY})
install(TARGETS krossruby DESTINATION ${PLUGIN_INSTALL_DIR})
include_directories(${RUBY_INCLUDE_DIRS})
add_library(krossruby MODULE ${krossruby_PART_SRCS})
target_link_libraries(krossruby
KF5::KrossCore
Qt5::Gui
Qt5::Widgets
${RUBY_LIBRARY}
)
install(TARGETS krossruby DESTINATION ${KDE_INSTALL_PLUGINDIR})
endif()
......@@ -57,7 +57,11 @@ namespace Kross {
Q_ASSERT(object);
d->metamethod = d->object->metaObject()->method(d->methodindex);
#ifdef KROSS_RUBY_CALLCACHE_CTORDTOR_DEBUG
d->debuginfo = QString("name=%1 class=%2 methodindex=%3 signature=%4").arg(object->objectName()).arg(object->metaObject()->className()).arg(d->methodindex).arg(d->metamethod.signature());
d->debuginfo = QString("name=%1 class=%2 methodindex=%3 signature=%4")
.arg(object->objectName())
.arg(object->metaObject()->className())
.arg(d->methodindex)
.arg(QString::fromLatin1(d->metamethod.methodSignature()));
krossdebug( QString("RubyCallCache Ctor %1 ").arg(d->debuginfo) );
#endif
}
......@@ -77,7 +81,11 @@ namespace Kross {
QVarLengthArray<void*> voidstarargs( typelistcount );
#ifdef KROSS_RUBY_CALLCACHE_DEBUG
krossdebug( QString("RubyCallCache::execfunction signature=%1 typeName=%2 argc=%3 typelistcount=%4").arg(d->metamethod.signature()).arg(d->metamethod.typeName()).arg(argc).arg(typelistcount) );
krossdebug(QString("RubyCallCache::execfunction signature=%1 typeName=%2 argc=%3 typelistcount=%4")
.arg(QString::fromLatin1(d->metamethod.methodSignature()))
.arg(d->metamethod.typeName())
.arg(argc)
.arg(typelistcount));
for(int i = 0; i < d->types.count(); ++i)
krossdebug( QString(" argument index=%1 typeId=%2 typeName=%3 metaTypeId=%4").arg(i).arg(d->types[i]).arg(QVariant::typeToName( (QVariant::Type)d->types[i] )).arg(d->metatypes[i]) );
#endif
......@@ -104,7 +112,12 @@ namespace Kross {
for(int idx = 1; idx < typelistcount; ++idx)
{
#ifdef KROSS_RUBY_CALLCACHE_DEBUG
krossdebug( QString("RubyCallCache::execfunction param idx=%1 inspect=%2 QVariantType=%3 QMetaType=%4").arg(idx).arg(STR2CSTR(rb_inspect(argv[idx]))).arg(QVariant::typeToName((QVariant::Type)d->types[idx])).arg(QMetaType::typeName(d->metatypes[idx])) );
VALUE inspectArg = rb_inspect(argv[idx]);
krossdebug(QString("RubyCallCache::execfunction param idx=%1 inspect=%2 QVariantType=%3 QMetaType=%4")
.arg(idx)
.arg(StringValuePtr(inspectArg))
.arg(QVariant::typeToName((QVariant::Type)d->types[idx]))
.arg(QMetaType::typeName(d->metatypes[idx])) );
#endif
MetaType* metatype = RubyMetaTypeFactory::create( typelist[idx-1], d->types[idx], d->metatypes[idx], argv[idx] );
......
......@@ -91,8 +91,7 @@ RubyExtension::RubyExtension(QObject* object)
const int count = metaobject->methodCount();
for(int i = 0; i < count; ++i) {
QMetaMethod member = metaobject->method(i);
const QString signature = member.signature();
const QByteArray name = signature.left(signature.indexOf('(')).toLatin1();
const QByteArray name = member.name();
if(! d->m_methods.contains(name))
d->m_methods.insert(name, i);
}
......@@ -369,8 +368,7 @@ VALUE RubyExtension::callMetaMethod(const QByteArray& funcname, int argc, VALUE
const int count = object->metaObject()->methodCount();
for(++methodindex; methodindex < count; ++methodindex) {
metamethod = object->metaObject()->method( methodindex );
const QString signature = metamethod.signature();
const QByteArray name = signature.left(signature.indexOf('(')).toLatin1();
const QByteArray name = metamethod.name();
if(name == funcname && metamethod.parameterTypes().size() == argumentcount) {
found = true;
break;
......@@ -383,7 +381,11 @@ VALUE RubyExtension::callMetaMethod(const QByteArray& funcname, int argc, VALUE
}
#ifdef KROSS_RUBY_EXTENSION_DEBUG
krossdebug( QString("QMetaMethod idx=%1 sig=%2 tag=%3 type=%4").arg(methodindex).arg(metamethod.signature()).arg(metamethod.tag()).arg(metamethod.typeName()) );
krossdebug(QString("QMetaMethod idx=%1 sig=%2 tag=%3 type=%4")
.arg(methodindex)
.arg(QString::fromLatin1(metamethod.methodSignature()))
.arg(metamethod.tag())
.arg(metamethod.typeName()));
#endif
QList<QByteArray> typelist = metamethod.parameterTypes();
......
......@@ -53,10 +53,14 @@ namespace Kross {
: MetaFunction(sender, signal), m_method(method)
{
#ifdef KROSS_RUBY_FUNCTION_CTORDTOR_DEBUG
VALUE inspectMethod = rb_inspect(method);
m_debuginfo = QString("sender=%1 signature=%2 method=%3")
.arg( sender ? QString("%1 (%2)").arg(sender->objectName()).arg(sender->metaObject()->className()) : "NULL" )
.arg( signal.data() )
.arg( StringValuePtr(rb_inspect(method)) );
.arg(sender
? QString("%1 (%2)").arg(sender->objectName())
.arg(sender->metaObject()->className())
: "NULL")
.arg(signal.data())
.arg(StringValuePtr(inspectMethod));
krossdebug( QString("RubyFunction Ctor %1").arg(m_debuginfo) );
#endif
rb_gc_register_address(&m_method);
......@@ -108,7 +112,9 @@ namespace Kross {
static VALUE callFunction(VALUE args)
{
#ifdef KROSS_RUBY_FUNCTION_DEBUG
krossdebug( QString("RubyFunction callFunction args=%1").arg(StringValuePtr(rb_inspect(args))) );
VALUE inspectArgs = rb_inspect(args);
krossdebug(QString("RubyFunction callFunction args=%1")
.arg(StringValuePtr(inspectArgs)));
#endif
Q_ASSERT( TYPE(args) == T_ARRAY );
VALUE self = rb_ary_entry(args, 0);
......@@ -155,18 +161,14 @@ namespace Kross {
#ifdef KROSS_RUBY_FUNCTION_DEBUG
krossdebug( QString("RubyFunction::qt_metacall: metatypeId=%1").arg(tp) );
#endif
switch( tp ) {
case QMetaType::QObjectStar: {
QObject* obj = (*reinterpret_cast< QObject*(*)>( _a[idx] ));
rb_ary_store(args, idx, RubyExtension::toVALUE( new RubyExtension(obj), true /*owner*/ ) );
} break;
case QMetaType::QWidgetStar: {
QWidget* obj = (*reinterpret_cast< QWidget*(*)>( _a[idx] ));
rb_ary_store(args, idx, RubyExtension::toVALUE( new RubyExtension(obj), true /*owner*/ ) );
} break;
default: {
rb_ary_store(args, idx, Qnil);
} break;
if (tp == QMetaType::QObjectStar) {
QObject *obj = (*reinterpret_cast<QObject*(*)>(_a[idx]));
rb_ary_store(args, idx, RubyExtension::toVALUE(new RubyExtension(obj), true /*owner*/));
} else if (tp == qMetaTypeId<QWidget*>()) {
QWidget *obj = (*reinterpret_cast<QWidget*(*)>(_a[idx]));
rb_ary_store(args, idx, RubyExtension::toVALUE(new RubyExtension(obj), true /*owner*/));
} else {
rb_ary_store(args, idx, Qnil);
}
} break;
default: {
......@@ -213,7 +215,14 @@ namespace Kross {
m_tmpResult = RubyType<QVariant>::toVariant(result);
#ifdef KROSS_RUBY_FUNCTION_DEBUG
QObject* sender = QObject::sender();
krossdebug( QString("RubyFunction::qt_metacall sender.objectName=%1 sender.className=%2 result=%3 variantresult=%4").arg(sender->objectName()).arg(sender->metaObject()->className()).arg(StringValuePtr(rb_inspect(result))).arg(m_tmpResult.toString()) );
VALUE inspectResult = rb_inspect(result);
krossdebug(QString(
"RubyFunction::qt_metacall sender.objectName=%1 "
"sender.className=%2 result=%3 variantresult=%4")
.arg(sender->objectName())
.arg(sender->metaObject()->className())
.arg(StringValuePtr(inspectResult))
.arg(m_tmpResult.toString()));
#endif
//_a[0] = Kross::MetaTypeVariant<QVariant>(d->tmpResult).toVoidStar();
_a[0] = &(m_tmpResult);
......
......@@ -44,7 +44,7 @@ namespace Kross {
/// \internal
class RubyInterpreterPrivate {
friend class RubyInterpreter;
public:
QHash<QString, QPointer<RubyModule> > modules;
static VALUE s_krossModule;
};
......@@ -136,7 +136,11 @@ void RubyInterpreter::finalizeRuby()
VALUE RubyInterpreter::require (VALUE self, VALUE name)
{
#ifdef KROSS_RUBY_INTERPRETER_DEBUG
krossdebug( QString("RubyInterpreter::require self=%1 name=%2").arg(STR2CSTR(rb_inspect(self))).arg(STR2CSTR(rb_inspect(name))) );
VALUE inspectSelf = rb_inspect(self);
VALUE inspectName = rb_inspect(name);
krossdebug(QString("RubyInterpreter::require self=%1 name=%2")
.arg(StringValuePtr(inspectSelf))
.arg(StringValuePtr(inspectName)));
#endif
QString modname = StringValuePtr(name);
......@@ -200,7 +204,10 @@ VALUE RubyInterpreter::require (VALUE self, VALUE name)
}
return val;
}
// We don't know about a module with such a name. So, let Ruby handle it...
#ifdef KROSS_RUBY_INTERPRETER_DEBUG
krossdebug(QString("Using ruby's require on %1").arg(StringValuePtr(inspectName)));
#endif
return rb_f_require(self, name);
}
......@@ -25,8 +25,11 @@ using namespace Kross;
static VALUE callExecuteException(VALUE self, VALUE error)
{
#ifdef KROSS_RUBY_OBJECT_DEBUG
krossdebug( QString("RubyScript::callExecuteException script=%1 error=%2")
.arg( STR2CSTR(rb_inspect(self)) ).arg( STR2CSTR(rb_inspect(error)) ) );
VALUE inspectSelf = rb_inspect(self);
VALUE inspectError = rb_inspect(error);
krossdebug(QString("RubyScript::callExecuteException script=%1 error=%2")
.arg(StringValuePtr(inspectSelf))
.arg(StringValuePtr(inspectError)));
#else
Q_UNUSED(self);
Q_UNUSED(error);
......
......@@ -78,7 +78,8 @@ static VALUE callExecuteException(VALUE self, VALUE error)
static VALUE callExecute(VALUE args)
{
#ifdef KROSS_RUBY_SCRIPT_DEBUG
krossdebug( QString("RubyScript::callExecute args=%1").arg( StringValuePtr(rb_inspect(args)) ) );
VALUE inspectArgs = rb_inspect(args);
krossdebug(QString("RubyScript::callExecute args=%1").arg(StringValuePtr(inspectArgs)));
#endif
Q_ASSERT( TYPE(args) == T_ARRAY );
VALUE self = rb_ary_entry(args, 0);
......@@ -123,7 +124,12 @@ namespace Kross {
const char *methodname = rb_id2name(SYM2ID(unit));
#ifdef KROSS_RUBY_SCRIPT_METHODADDED_DEBUG
krossdebug(QString("RubyScriptPrivate::method_added methodname=%1 self=%2 module=%3").arg(methodname).arg(StringValuePtr( rb_inspect(self) )).arg(StringValuePtr( rb_inspect(module) )));
VALUE inspectSelf = rb_inspect(self);
VALUE inspectModule = rb_inspect(module);
krossdebug(QString("RubyScriptPrivate::method_added methodname=%1 self=%2 module=%3")
.arg(methodname)
.arg(StringValuePtr(inspectSelf))
.arg(StringValuePtr(inspectModule)));
#endif
VALUE rubyscriptvalue = rb_funcall(self, rb_intern("const_get"), 1, ID2SYM(rb_intern("RUBYSCRIPTOBJ")));
......@@ -137,14 +143,16 @@ namespace Kross {
rubyscript->d->m_functionnames.append(methodname);
if( rubyscript->d->m_functions.contains(methodname) ) {
QPair< QObject* , QString > f = rubyscript->d->m_functions[methodname];
QPair<QObject *, QByteArray> f = rubyscript->d->m_functions[methodname];
VALUE method = rb_funcall(self, rb_intern("method"), 1, rb_str_new2(methodname));
#ifdef KROSS_RUBY_SCRIPT_METHODADDED_DEBUG
krossdebug(QString("RubyScriptPrivate::method_added method=%1").arg(StringValuePtr( rb_inspect(method) )));
VALUE inspectMethod = rb_inspect(method);
krossdebug(QString("RubyScriptPrivate::method_added method=%1")
.arg(StringValuePtr(inspectMethod)));
#endif
RubyFunction* function = rubyscript->connectFunction(f.first, f.second.toLatin1(), method);
RubyFunction* function = rubyscript->connectFunction(f.first, f.second, method);
Q_UNUSED(function);
}
......@@ -227,9 +235,9 @@ namespace Kross {
for(int i = 0; i < count; ++i) {
QMetaMethod metamethod = metaobject->method(i);
if( metamethod.methodType() == QMetaMethod::Signal ) {
const QString signature = metamethod.signature();
const QByteArray name = signature.left(signature.indexOf('(')).toLatin1();
m_functions.insert( name, QPair< QObject* , QString >(sender, signature) );
const QByteArray signature = metamethod.methodSignature();
const QByteArray name = metamethod.name();
m_functions.insert( name, QPair< QObject* , QByteArray >(sender, signature) );
}
}
}
......@@ -251,7 +259,7 @@ namespace Kross {
/// A hash for faster signal=>function access.
QHash< QByteArray, // the signalname, e.g. "mySignal"
QPair< QObject* , // the QObject the signal belongs to
QString > // the signature, e.g. "mySignal(QString,int)"
QByteArray> // the signature, e.g. "mySignal(QString,int)"
> m_functions;
/// List of \a RubyFunction instances the \a RubyScript is owner of.
//QList< RubyFunction* > m_rubyfunctions;
......@@ -348,7 +356,9 @@ QStringList RubyScript::functionNames()
static VALUE callFunction2(VALUE args)
{
#ifdef KROSS_RUBY_SCRIPT_DEBUG
krossdebug( QString("RubyScript::callFunction2 args=%1").arg( StringValuePtr(rb_inspect(args)) ) );
VALUE inspectArgs = rb_inspect(args);
krossdebug(QString("RubyScript::callFunction2 args=%1")
.arg(StringValuePtr(inspectArgs)));
#endif
Q_ASSERT( TYPE(args) == T_ARRAY );
VALUE self = rb_ary_entry(args, 0);
......@@ -434,7 +444,11 @@ RubyFunction* RubyScript::connectFunction(QObject* sender, const QByteArray& sig
return 0;
}
#ifdef KROSS_RUBY_SCRIPT_CONNECTFUNCTION_DEBUG
krossdebug( QString("RubyScript::method_added connected object='%1' signal='%2' method='%3'").arg(sender->objectName()).arg(signature.data()).arg(StringValuePtr(rb_inspect(method))) );
VALUE inspectMethod = rb_inspect(method);
krossdebug(QString("RubyScript::method_added connected object='%1' signal='%2' method='%3'")
.arg(sender->objectName())
.arg(signature.data())
.arg(StringValuePtr(inspectMethod)));
#endif
d->m_rubyfunctions.append( function );
return function;
......
......@@ -216,7 +216,10 @@ VALUE RubyType<QVariant>::toVALUE(const QVariant& v)
QVariant RubyType<QVariant>::toVariant(VALUE value)
{
#ifdef KROSS_RUBY_VARIANT_DEBUG
krossdebug(QString("RubyType<QVariant>::toVariant of type=%1 inspect=%2").arg(TYPE(value)).arg(STR2CSTR(rb_inspect(value))));
VALUE inspectValue = rb_inspect(value);
krossdebug(QString("RubyType<QVariant>::toVariant of type=%1 inspect=%2")
.arg(TYPE(value))
.arg(StringValuePtr(inspectValue)));
#endif
switch( TYPE(value) )
......@@ -418,25 +421,32 @@ MetaType* RubyMetaTypeFactory::create(const char* typeName, int typeId, int meta
if( metaTypeId > 0 ) {
//if( TYPE(value) == T_NIL ) {
switch(metaTypeId) {
case QMetaType::QObjectStar: // fall through
case QMetaType::QWidgetStar: {
if (metaTypeId == QMetaType::QObjectStar ||
metaTypeId == qMetaTypeId<QWidget*>()) {
if( TYPE(value) == T_DATA ) {
#ifdef KROSS_RUBY_VARIANT_DEBUG
QByteArray clazzname = rb_class2name(CLASS_OF(value));
krossdebug( QString("RubyMetaTypeFactory::create VALUE is class='%1' inspect='%2'").arg(clazzname.constData()).arg(STR2CSTR(rb_inspect(value))) );
VALUE inspectValue = rb_inspect(value);
krossdebug(QString("RubyMetaTypeFactory::create VALUE is class='%1' inspect='%2'")
.arg(clazzname.constData())
.arg(StringValuePtr(inspectValue)));
#endif
VALUE qt_module = rb_define_module("Qt");
VALUE qt_base_class = rb_define_class_under(qt_module, "Base", rb_cObject);
if ( rb_funcall(value, rb_intern("kind_of?"), 1, qt_base_class) == Qtrue ) {
if ( metaTypeId == QMetaType::QWidgetStar ) {
if (metaTypeId == qMetaTypeId<QWidget*>()) {
QWidget** wobj = 0;
Data_Get_Struct(value, QWidget*, wobj);
#ifdef KROSS_RUBY_VARIANT_DEBUG
//krossdebug( QString("RubyMetaTypeFactory::create QtRuby result=%1 [%2] obj=%3 [%4]").arg(STR2CSTR(rb_inspect(value))).arg(STR2CSTR(rb_inspect(CLASS_OF(value)))).arg(wobj ? *wobj->objectName() : "NULL").arg(*wobj ? *wobj->metaObject()->className() : "NULL") );
krossdebug( QString("RubyMetaTypeFactory::create QtRuby result=%1 [%2]").arg(STR2CSTR(rb_inspect(value))).arg(STR2CSTR(rb_inspect(CLASS_OF(value)))) );
VALUE inspectValue = rb_inspect(value);
VALUE inspectValueClass = rb_inspect(CLASS_OF(value));
krossdebug(QString("RubyMetaTypeFactory::create QtRuby result=%1 [%2]")
.arg(StringValuePtr(inspectValue))
.arg(StringValuePtr(inspectValueClass)));
#endif
return new MetaTypeVoidStar( metaTypeId, *wobj, false /*owner*/ );
} else if ( metaTypeId == QMetaType::QObjectStar ) {
......@@ -444,7 +454,12 @@ MetaType* RubyMetaTypeFactory::create(const char* typeName, int typeId, int meta
Data_Get_Struct(value, QObject*, qobj);
#ifdef KROSS_RUBY_VARIANT_DEBUG
//krossdebug( QString("RubyMetaTypeFactory::create QtRuby result=%1 [%2] obj=%3 [%4]").arg(STR2CSTR(rb_inspect(value))).arg(STR2CSTR(rb_inspect(CLASS_OF(value)))).arg(qobj ? *qobj->objectName() : "NULL").arg(*qobj ? *qobj->metaObject()->className() : "NULL") );
krossdebug( QString("RubyMetaTypeFactory::create QtRuby result=%1 [%2]").arg(STR2CSTR(rb_inspect(value))).arg(STR2CSTR(rb_inspect(CLASS_OF(value)))) );
VALUE inspectValue = rb_inspect(value);
VALUE inspectValueClass = rb_inspect(CLASS_OF(value));
krossdebug(QString("RubyMetaTypeFactory::create QtRuby result=%1 [%2]")
.arg(StringValuePtr(inspectValue))
.arg(StringValuePtr(inspectValueClass)));
#endif
return new MetaTypeVoidStar( metaTypeId, *qobj, false /*owner*/ );
}
......@@ -456,9 +471,6 @@ MetaType* RubyMetaTypeFactory::create(const char* typeName, int typeId, int meta
#endif
void* ptr = 0; //QMetaType::construct( metaTypeId, 0 );
return new MetaTypeVoidStar( metaTypeId, ptr, false /* owner */ );
} break;
default:
break;
}
//}
......@@ -483,7 +495,11 @@ MetaType* RubyMetaTypeFactory::create(const char* typeName, int typeId, int meta
if( tn.startsWith("QList<") && tn.endsWith("*>") ) {
QByteArray itemTypeName = tn.mid(6, tn.length()-7);
#ifdef KROSS_RUBY_VARIANT_DEBUG
krosswarning( QString("RubyMetaTypeFactory::create Convert VALUE '%1' to QList<void*> with typeName='%2' and itemTypeName='%3'").arg(STR2CSTR(rb_inspect(value))).arg(typeName).arg(itemTypeName.constData()) );
VALUE inspectValue = rb_inspect(value);
krosswarning( QString("RubyMetaTypeFactory::create Convert VALUE '%1' to QList<void*> with typeName='%2' and itemTypeName='%3'")
.arg(StringValuePtr(inspectValue))
.arg(typeName)
.arg(itemTypeName.constData()));
#endif
QList<void*> list;
if( TYPE(value) == T_ARRAY ) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment