* Added command line tool example similar to 'sopranocmd'
[kdebindings.git] / ruby / krossruby / rubyfunction.h
blobd9863924552c9d697819440b28ed34608fbd6d3b
1 /***************************************************************************
2 * rubyfunction.h
3 * This file is part of the KDE project
4 * copyright (C)2007 by Sebastian Sauer (mail@dipe.org)
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public License
15 * along with this program; see the file COPYING. If not, write to
16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18 ***************************************************************************/
20 #ifndef KROSS_RUBYFUNCTION_H
21 #define KROSS_RUBYFUNCTION_H
23 #include "rubyconfig.h"
24 #include <kross/core/krossconfig.h>
25 #include <kross/core/manager.h>
26 #include <kross/core/metafunction.h>
28 #include <QObject>
29 #include <QWidget>
30 #include <QMetaObject>
31 #include <QMetaMethod>
32 #include <QByteArray>
34 namespace Kross {
36 /**
37 * The RubyFunction class implements a QObject to provide
38 * an adaptor between Qt signals+slots and ruby functions.
40 class RubyFunction : public MetaFunction
42 public:
44 /**
45 * Constructor.
47 * \param sender The QObject instance that sends the signal.
48 * \param signal The signature of the signal the QObject emits.
49 * \param method The callable ruby methods that should
50 * be executed if the QObject emits the signal.
52 RubyFunction(QObject* sender, const QByteArray& signal, VALUE method)
53 : MetaFunction(sender, signal), m_method(method)
55 #ifdef KROSS_RUBY_FUNCTION_CTORDTOR_DEBUG
56 m_debuginfo = QString("sender=%1 signature=%2 method=%3")
57 .arg( sender ? QString("%1 (%2)").arg(sender->objectName()).arg(sender->metaObject()->className()) : "NULL" )
58 .arg( signal.data() )
59 .arg( STR2CSTR(rb_inspect(method)) );
60 krossdebug( QString("RubyFunction Ctor %1").arg(m_debuginfo) );
61 #endif
62 rb_gc_register_address(&m_method);
65 /**
66 * Destructor.
68 virtual ~RubyFunction()
70 #ifdef KROSS_RUBY_FUNCTION_CTORDTOR_DEBUG
71 krossdebug( QString("RubyFunction Dtor %1").arg(m_debuginfo) );
72 #endif
73 rb_gc_unregister_address(&m_method);
76 /**
77 * This static function is called by Ruby if the callFunction bellow
78 * raises an exception.
80 static VALUE callFunctionException(VALUE args, VALUE error)
82 //#ifdef KROSS_RUBY_FUNCTION_DEBUG
83 krossdebug( QString("RubyFunction callFunctionException args=%1 error=%2")
84 .arg( STR2CSTR(rb_inspect(args)) ).arg( STR2CSTR(rb_inspect(error)) ) );
85 //#else
86 // Q_UNUSED(args);
87 // Q_UNUSED(error);
88 //#endif
89 VALUE info = rb_gv_get("$!");
90 VALUE bt = rb_funcall(info, rb_intern("backtrace"), 0);
91 VALUE message = RARRAY(bt)->ptr[0];
92 fprintf(stderr,"%s: %s (%s)\n", STR2CSTR(message), STR2CSTR(rb_obj_as_string(info)), rb_class2name(CLASS_OF(info)));
93 for(int i = 1; i < RARRAY(bt)->len; ++i)
94 if( TYPE(RARRAY(bt)->ptr[i]) == T_STRING )
95 fprintf(stderr,"\tfrom %s\n", STR2CSTR(RARRAY(bt)->ptr[i]));
96 //ruby_nerrs++;
97 return Qnil;
101 * This static function is called by Ruby to perform actions within
102 * a rescue block to provide with the callFunctionException function
103 * above an exception handler.
105 static VALUE callFunction(VALUE args)
107 #ifdef KROSS_RUBY_FUNCTION_DEBUG
108 krossdebug( QString("RubyFunction callFunction args=%1").arg(STR2CSTR(rb_inspect(args))) );
109 #endif
110 Q_ASSERT( TYPE(args) == T_ARRAY );
111 VALUE self = rb_ary_entry(args, 0);
112 int argsize = FIX2INT( rb_ary_entry(args, 1) );
113 VALUE arguments = rb_ary_entry(args, 2);
114 VALUE* argumentsP = new VALUE[argsize];
115 for(int idx = 0; idx < argsize; idx++)
117 argumentsP[idx] = rb_ary_entry(arguments, idx+1);
119 //krossdebug(QString("RubyScript::callExecute script=%1").arg(STR2CSTR( rb_inspect(script) )));
120 //krossdebug(QString("RubyScript::callExecute fileName=%1").arg(STR2CSTR( rb_inspect(fileName) )));
121 //krossdebug(QString("RubyScript::callExecute src=%1").arg(STR2CSTR( rb_inspect(src) )));
122 VALUE result = rb_funcall2(self, rb_intern("call"), argsize, argumentsP);
123 delete[] argumentsP;
124 return result;
128 * This method got called if a method this QObject instance
129 * defines should be invoked.
131 int qt_metacall(QMetaObject::Call _c, int _id, void **_a)
133 _id = QObject::qt_metacall(_c, _id, _a);
134 #ifdef KROSS_RUBY_FUNCTION_DEBUG
135 //krossdebug(QString("RubyFunction::qt_metacall id=%1").arg(_id));
136 #endif
137 if(_id >= 0 && _c == QMetaObject::InvokeMetaMethod) {
138 switch(_id) {
139 case 0: {
140 // convert the arguments
141 QMetaMethod method = metaObject()->method( metaObject()->indexOfMethod(m_signature) );
142 QList<QByteArray> params = method.parameterTypes();
143 const int argsize = params.size();
144 VALUE args = rb_ary_new2(argsize);
145 int idx = 1;
146 foreach(QByteArray param, params) {
147 int tp = QVariant::nameToType( param.constData() );
148 switch(tp) {
149 case QVariant::Invalid: // fall through
150 case QVariant::UserType: {
151 tp = QMetaType::type( param.constData() );
152 #ifdef KROSS_RUBY_FUNCTION_DEBUG
153 krossdebug( QString("RubyFunction::qt_metacall: metatypeId=%1").arg(tp) );
154 #endif
155 switch( tp ) {
156 case QMetaType::QObjectStar: {
157 QObject* obj = (*reinterpret_cast< QObject*(*)>( _a[idx] ));
158 rb_ary_store(args, idx, RubyExtension::toVALUE( new RubyExtension(obj), true /*owner*/ ) );
159 } break;
160 case QMetaType::QWidgetStar: {
161 QWidget* obj = (*reinterpret_cast< QWidget*(*)>( _a[idx] ));
162 rb_ary_store(args, idx, RubyExtension::toVALUE( new RubyExtension(obj), true /*owner*/ ) );
163 } break;
164 default: {
165 rb_ary_store(args, idx, Qnil);
166 } break;
168 } break;
169 default: {
170 QVariant v(tp, _a[idx]);
172 if( ! Kross::Manager::self().strictTypesEnabled() ) {
173 if( v.type() == QVariant::Invalid && QByteArray(param.constData()).endsWith("*") ) {
174 QObject* obj = (*reinterpret_cast<QObject*(*)>( _a[idx] ));
175 v.setValue( (QObject*) obj );
179 #ifdef KROSS_RUBY_FUNCTION_DEBUG
180 krossdebug( QString("RubyFunction::qt_metacall argument param=%1 typeId=%2").arg(param.constData()).arg(tp) );
181 #endif
182 rb_ary_store(args, idx, RubyType<QVariant>::toVALUE(v));
183 } break;
185 //rb_gc_register_address(&args[idx-1]);
186 ++idx;
189 /* makes no sense to init the stack here since we share one stack anyway and it's handled in the interpreter already
190 if (ruby_in_eval == 0) {
191 #ifdef RUBY_INIT_STACK
192 RUBY_INIT_STACK
193 #endif
197 // call the ruby function
198 //VALUE result = rb_funcall2(m_method, rb_intern("call"), argsize, args);
200 //TODO optimize
201 ruby_in_eval++;
202 VALUE argarray = rb_ary_new2(3);
203 rb_ary_store(argarray, 0, m_method); //self
204 rb_ary_store(argarray, 1, INT2FIX(argsize));
205 rb_ary_store(argarray, 2, args);
206 VALUE result = rb_rescue2((VALUE(*)(...))callFunction, argarray, (VALUE(*)(...))callFunctionException, Qnil, rb_eException, 0);
207 ruby_in_eval--;
209 // finally set the returnvalue
210 m_tmpResult = RubyType<QVariant>::toVariant(result);
211 #ifdef KROSS_RUBY_FUNCTION_DEBUG
212 QObject* sender = QObject::sender();
213 krossdebug( QString("RubyFunction::qt_metacall sender.objectName=%1 sender.className=%2 result=%3 variantresult=%4").arg(sender->objectName()).arg(sender->metaObject()->className()).arg(STR2CSTR(rb_inspect(result))).arg(m_tmpResult.toString()) );
214 #endif
215 //_a[0] = Kross::MetaTypeVariant<QVariant>(d->tmpResult).toVoidStar();
216 _a[0] = &(m_tmpResult);
218 //for(int i = 0; i < argsize; ++i) rb_gc_unregister_address(&args[i]);
219 #ifdef KROSS_RUBY_EXPLICIT_GC
220 rb_gc();
221 #endif
222 } break;
224 _id -= 1;
226 return _id;
229 private:
230 /// The pointer to the Ruby method.
231 VALUE m_method;
232 /// Dummy variable used to store the last result of a method call.
233 QVariant m_tmpResult;
235 #ifdef KROSS_RUBY_FUNCTION_CTORDTOR_DEBUG
236 /// \internal string for debugging.
237 QString m_debuginfo;
238 #endif
243 #endif