qml 0.0.5 → 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +57 -4
- data/changes.md +8 -0
- data/examples/fizzbuzz/fizzbuzz.rb +1 -1
- data/examples/imageprovider/imageprovider.rb +1 -1
- data/examples/todo_array/todo_array.rb +1 -1
- data/examples/todo_sequel/todo_sequel.rb +1 -1
- data/examples/twitter/twitter.rb +1 -1
- data/ext/qml/accessclass.cpp +5 -9
- data/ext/qml/conversionerror.h +14 -0
- data/ext/qml/ext_metaobject.cpp +30 -41
- data/ext/qml/init.cpp +5 -7
- data/ext/qml/rubyclass.cpp +6 -18
- data/ext/qml/rubyclass.h +22 -26
- data/ext/qml/rubyvalue.cpp +155 -221
- data/ext/qml/rubyvalue.h +30 -63
- data/ext/qml/signalforwarder.cpp +1 -3
- data/ext/qml/util.cpp +2 -25
- data/ext/qml/util.h +1 -21
- data/ext/qml/weakvaluereference.cpp +4 -5
- data/lib/qml/access.rb +9 -17
- data/lib/qml/application.rb +18 -21
- data/lib/qml/context.rb +1 -1
- data/lib/qml/dispatcher.rb +0 -1
- data/lib/qml/error_converter.rb +1 -0
- data/lib/qml/meta_object.rb +3 -3
- data/lib/qml/qt_object_base.rb +130 -5
- data/lib/qml/reactive/object.rb +34 -25
- data/lib/qml/reactive/signal.rb +6 -10
- data/lib/qml/reactive/unbound_property.rb +1 -1
- data/lib/qml/reactive/unbound_signal.rb +2 -2
- data/lib/qml/version.rb +1 -1
- data/spec/qml/reactive/object_spec.rb +14 -38
- data/spec/qml/reactive/signal_spec.rb +1 -1
- data/spec/qml/reactive/unbound_property_spec.rb +40 -0
- data/spec/qml/reactive/unbound_signal_spec.rb +70 -0
- data/spec/{shared_examples → shared}/qml/data/list_model.rb +0 -0
- data/spec/shared/qml/reactive/object.rb +39 -0
- data/spec/spec_helper.rb +1 -1
- metadata +12 -6
- data/lib/qml/class_builder.rb +0 -129
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 88ec8d13931b6285ad6961a33b0fb5dd0e30582b
|
4
|
+
data.tar.gz: da96d985867d7ef034edcb60174cb4f64410783f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 07886e4fd25d9f242bf9fd8e8eca6e4ed8a3bb7886fdac811b16d9ca0b699cc8269899fe2299e4fcb6d5ad51456e7749831cde2437f70cd4453bc971ee0cd488
|
7
|
+
data.tar.gz: bde9ec75fa9b85c9e54d319f686a3d98a54ae6fd23af31f94e0bda49192903f818b04b0c47df34cc4b52621332dc4c54ce19a343563fdcdcec1e12a5a1b366e9
|
data/README.md
CHANGED
@@ -46,9 +46,9 @@ Both libffi and Qt5 are keg-only in Homebrew, so you must specify their paths ex
|
|
46
46
|
If you use [official Qt installation](http://qt-project.org/downloads), for example:
|
47
47
|
|
48
48
|
$ brew install pkg-config libffi
|
49
|
-
$ gem install qml -- --with-libffi-dir=$(brew --prefix libffi) --with-qt-dir
|
49
|
+
$ gem install qml -- --with-libffi-dir=$(brew --prefix libffi) --with-qt-dir=$HOME/Qt/5.3/clang_64
|
50
50
|
|
51
|
-
The Qt installation path (
|
51
|
+
The Qt installation path (`$HOME/Qt/5.3/clang_64` in this example) depends on your Qt installation configuration and Qt version.
|
52
52
|
|
53
53
|
### General (OSX and Linux)
|
54
54
|
|
@@ -87,7 +87,7 @@ The following code loads a QML file and shows an application window titled "Hell
|
|
87
87
|
```ruby
|
88
88
|
require 'qml'
|
89
89
|
|
90
|
-
QML.
|
90
|
+
QML.run do |app|
|
91
91
|
app.load_path Pathname(__FILE__) + '../main.qml'
|
92
92
|
end
|
93
93
|
```
|
@@ -215,7 +215,7 @@ class Foo
|
|
215
215
|
end
|
216
216
|
end
|
217
217
|
|
218
|
-
QML.
|
218
|
+
QML.run do |app|
|
219
219
|
app.context[:foo] = Foo.new
|
220
220
|
app.load_path Pathname(__FILE__) + '../main.qml'
|
221
221
|
end
|
@@ -434,6 +434,59 @@ obj = plugin.create_object
|
|
434
434
|
obj.prefer_managed false
|
435
435
|
```
|
436
436
|
|
437
|
+
### Use with EventMachine
|
438
|
+
|
439
|
+
You can use [EventMachine](https://github.com/eventmachine/eventmachine) with ruby-qml.
|
440
|
+
It is more powerful than the default ruby-qml event loop.
|
441
|
+
|
442
|
+
Instead of using `QML.run`, start an EventMachine event loop by `EM.run` and
|
443
|
+
process QML events periodically by `QML::Application#process_events`.
|
444
|
+
|
445
|
+
```ruby
|
446
|
+
require 'qml'
|
447
|
+
require 'eventmachine'
|
448
|
+
|
449
|
+
EM.run do
|
450
|
+
QML.init
|
451
|
+
EM.add_periodic_timer(0.01) { QML.application.process_events }
|
452
|
+
QML.application.load_path(Pathname.pwd + 'main.qml')
|
453
|
+
end
|
454
|
+
```
|
455
|
+
|
456
|
+
You can also use [em-synchrony](https://github.com/igrigorik/em-synchrony) to
|
457
|
+
write callback-free asynchronous operation for ruby-qml.
|
458
|
+
|
459
|
+
```
|
460
|
+
require 'qml'
|
461
|
+
require 'eventmachine'
|
462
|
+
require 'em-synchrony'
|
463
|
+
require 'em-http-request'
|
464
|
+
|
465
|
+
class Controller
|
466
|
+
include QML::Access
|
467
|
+
property :result, ''
|
468
|
+
|
469
|
+
def get
|
470
|
+
EM.synchrony do
|
471
|
+
content = EM::Synchrony.sync EM::HttpRequest.new('http://www.example.com/').get
|
472
|
+
self.result = content.response
|
473
|
+
end
|
474
|
+
end
|
475
|
+
|
476
|
+
def quit
|
477
|
+
EM.stop
|
478
|
+
end
|
479
|
+
|
480
|
+
register_to_qml under: 'Example', version: '0.1'
|
481
|
+
end
|
482
|
+
|
483
|
+
EM.run do
|
484
|
+
QML.init
|
485
|
+
EM.add_periodic_timer(0.01) { QML.application.process_events }
|
486
|
+
QML.application.load_path(Pathname.pwd + 'main.qml')
|
487
|
+
end
|
488
|
+
```
|
489
|
+
|
437
490
|
## Contributing
|
438
491
|
|
439
492
|
Contributions are welcome. When you are contributing to ruby-qml:
|
data/changes.md
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
## 0.0.6 (2014-08-19)
|
2
|
+
|
3
|
+
* Fix problems when using Fiber with ruby-qml
|
4
|
+
|
5
|
+
* Rename block-receiving `QML.application` to `QML.run`
|
6
|
+
|
7
|
+
* `QML.application` without block is still the same name
|
8
|
+
|
1
9
|
## 0.0.5 (2014-07-31)
|
2
10
|
|
3
11
|
* Support official Qt installation on Mac
|
data/examples/twitter/twitter.rb
CHANGED
data/ext/qml/accessclass.cpp
CHANGED
@@ -8,11 +8,9 @@ namespace RubyQml {
|
|
8
8
|
AccessClass::AccessClass(RubyValue className, RubyValue methodInfos, RubyValue signalInfos, RubyValue propertyInfos)
|
9
9
|
{
|
10
10
|
setClassName(className.to<QByteArray>());
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
rb_check_array_type(propertyInfos);
|
15
|
-
});
|
11
|
+
rb_check_array_type(methodInfos);
|
12
|
+
rb_check_array_type(signalInfos);
|
13
|
+
rb_check_array_type(propertyInfos);
|
16
14
|
for (int i = 0; i < RARRAY_LEN(VALUE(methodInfos)); ++i) {
|
17
15
|
RubyValue info = RARRAY_AREF(VALUE(methodInfos), i);
|
18
16
|
auto nameSym = info.send("name");
|
@@ -46,10 +44,8 @@ QVariant AccessClass::callMethod(ForeignObject *obj, size_t id, const QVariantLi
|
|
46
44
|
std::vector<VALUE> values(args.size());
|
47
45
|
std::transform(args.begin(), args.end(), values.begin(), &RubyValue::from<QVariant>);
|
48
46
|
RubyValue retValue;
|
49
|
-
|
50
|
-
|
51
|
-
retValue = rb_funcall2(self, id, values.size(), values.data());
|
52
|
-
});
|
47
|
+
rescueNotify([&] {
|
48
|
+
retValue = rb_funcall2(self, id, values.size(), values.data());
|
53
49
|
});
|
54
50
|
ret = retValue.to<QVariant>();
|
55
51
|
});
|
data/ext/qml/ext_metaobject.cpp
CHANGED
@@ -18,13 +18,11 @@ namespace {
|
|
18
18
|
|
19
19
|
RubyValue idListToArray(const QList<ID> &xs)
|
20
20
|
{
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
return ary;
|
27
|
-
});
|
21
|
+
auto ary = rb_ary_new();
|
22
|
+
for (ID id : xs) {
|
23
|
+
rb_ary_push(ary, ID2SYM(id));
|
24
|
+
}
|
25
|
+
return ary;
|
28
26
|
}
|
29
27
|
|
30
28
|
}
|
@@ -148,9 +146,8 @@ RubyValue Ext_MetaObject::invokeMethod(RubyValue object, RubyValue methodName, R
|
|
148
146
|
|
149
147
|
auto methodIndexes = findMethods(methodName);
|
150
148
|
|
151
|
-
|
152
|
-
|
153
|
-
});
|
149
|
+
args = rb_check_array_type(args);
|
150
|
+
|
154
151
|
auto obj = wrapperRubyClass<Ext_Pointer>().unwrap(object)->fetchQObject();
|
155
152
|
for (int i : methodIndexes) {
|
156
153
|
MethodInvoker invoker(args, mMetaObject->method(i));
|
@@ -158,17 +155,17 @@ RubyValue Ext_MetaObject::invokeMethod(RubyValue object, RubyValue methodName, R
|
|
158
155
|
return invoker.invoke(obj);
|
159
156
|
}
|
160
157
|
}
|
161
|
-
protect([&] {
|
162
|
-
auto to_class = rb_funcall(ID2SYM(rb_intern("class")), rb_intern("to_proc"), 0);
|
163
|
-
auto classes = rb_funcall_with_block(args, rb_intern("map"), 0, nullptr, to_class);
|
164
|
-
auto classes_str = rb_funcall(classes, rb_intern("to_s"), 0);
|
165
158
|
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
159
|
+
auto to_class = rb_funcall(ID2SYM(rb_intern("class")), rb_intern("to_proc"), 0);
|
160
|
+
auto classes = rb_funcall_with_block(args, rb_intern("map"), 0, nullptr, to_class);
|
161
|
+
auto classes_str = rb_funcall(classes, rb_intern("to_s"), 0);
|
162
|
+
|
163
|
+
rb_raise(rb_path2class("QML::MethodError"),
|
164
|
+
"method mismatch (%s with params %s in %s)",
|
165
|
+
mMetaObject->method(methodIndexes.first()).name().data(),
|
166
|
+
StringValueCStr(classes_str),
|
167
|
+
mMetaObject->className());
|
168
|
+
|
172
169
|
return Qnil;
|
173
170
|
}
|
174
171
|
|
@@ -190,11 +187,9 @@ RubyValue Ext_MetaObject::connectSignal(RubyValue object, RubyValue signalName,
|
|
190
187
|
new SignalForwarder(obj, method, proc);
|
191
188
|
return Qnil;
|
192
189
|
}
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
rb_id2name(id), mMetaObject->className());
|
197
|
-
});
|
190
|
+
rb_raise(rb_path2class("QML::MethodError"),
|
191
|
+
"signal not found (%s in %s)",
|
192
|
+
rb_id2name(id), mMetaObject->className());
|
198
193
|
return Qnil;
|
199
194
|
}
|
200
195
|
|
@@ -223,11 +218,9 @@ RubyValue Ext_MetaObject::setProperty(RubyValue object, RubyValue name, RubyValu
|
|
223
218
|
|
224
219
|
auto metaProperty = mMetaObject->property(findProperty(name));
|
225
220
|
if (!newValue.isConvertibleTo(metaProperty.userType())) {
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
rb_obj_classname(newValue), metaProperty.typeName());
|
230
|
-
});
|
221
|
+
rb_raise(rb_path2class("QML::PropertyError"),
|
222
|
+
"type mismatch (%s for %s)",
|
223
|
+
rb_obj_classname(newValue), metaProperty.typeName());
|
231
224
|
}
|
232
225
|
|
233
226
|
auto qobj = wrapperRubyClass<Ext_Pointer>().unwrap(object)->fetchQObject();
|
@@ -264,12 +257,10 @@ QList<int> Ext_MetaObject::findMethods(RubyValue name) const
|
|
264
257
|
auto id = name.toID();
|
265
258
|
auto methodIndexes = mMethodHash.values(id);
|
266
259
|
if (methodIndexes.size() == 0) {
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
mMetaObject->className());
|
272
|
-
});
|
260
|
+
rb_raise(rb_path2class("QML::MethodError"),
|
261
|
+
"method not found (%s in %s)",
|
262
|
+
rb_id2name(id),
|
263
|
+
mMetaObject->className());
|
273
264
|
}
|
274
265
|
return methodIndexes;
|
275
266
|
}
|
@@ -278,11 +269,9 @@ int Ext_MetaObject::findProperty(RubyValue name) const
|
|
278
269
|
{
|
279
270
|
auto id = name.toID();
|
280
271
|
if (!mPropertyHash.contains(id)) {
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
rb_id2name(id), mMetaObject->className());
|
285
|
-
});
|
272
|
+
rb_raise(rb_path2class("QML::PropertyError"),
|
273
|
+
"property not found (%s in %s)",
|
274
|
+
rb_id2name(id), mMetaObject->className());
|
286
275
|
}
|
287
276
|
return mPropertyHash[id];
|
288
277
|
}
|
data/ext/qml/init.cpp
CHANGED
@@ -48,7 +48,7 @@ void cleanup()
|
|
48
48
|
|
49
49
|
void setupEndProc()
|
50
50
|
{
|
51
|
-
rb_set_end_proc([](VALUE) {
|
51
|
+
rb_set_end_proc([](VALUE) { cleanup(); }, Qnil);
|
52
52
|
}
|
53
53
|
|
54
54
|
}
|
@@ -60,10 +60,8 @@ void Init_qml()
|
|
60
60
|
rb_require("qml/errors");
|
61
61
|
rb_require("qml/error_converter");
|
62
62
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
setupEndProc();
|
68
|
-
});
|
63
|
+
defineMetaTypes();
|
64
|
+
defineClasses();
|
65
|
+
setupGlobalGCMarking();
|
66
|
+
setupEndProc();
|
69
67
|
}
|
data/ext/qml/rubyclass.cpp
CHANGED
@@ -15,16 +15,12 @@ RubyModule::RubyModule(RubyValue moduleValue) :
|
|
15
15
|
|
16
16
|
RubyModule::RubyModule(const char *name)
|
17
17
|
{
|
18
|
-
|
19
|
-
mValue = rb_define_module(name);
|
20
|
-
});
|
18
|
+
mValue = rb_define_module(name);
|
21
19
|
}
|
22
20
|
|
23
21
|
RubyModule::RubyModule(const RubyModule &under, const char *name)
|
24
22
|
{
|
25
|
-
|
26
|
-
mValue = rb_define_module_under(under.toValue(), name);
|
27
|
-
});
|
23
|
+
mValue = rb_define_module_under(under.toValue(), name);
|
28
24
|
}
|
29
25
|
|
30
26
|
RubyModule &RubyModule::operator=(const RubyModule &other)
|
@@ -36,23 +32,17 @@ RubyModule &RubyModule::operator=(const RubyModule &other)
|
|
36
32
|
|
37
33
|
RubyModule RubyModule::fromPath(const char *path)
|
38
34
|
{
|
39
|
-
|
40
|
-
protect([&] {
|
41
|
-
ret = rb_path2class(path);
|
42
|
-
});
|
43
|
-
return ret;
|
35
|
+
return rb_path2class(path);
|
44
36
|
}
|
45
37
|
|
46
38
|
void RubyModule::aliasMethod(const char *newName, const char *originalName)
|
47
39
|
{
|
48
|
-
|
49
|
-
rb_alias(mValue, rb_intern(newName), rb_intern(originalName));
|
50
|
-
});
|
40
|
+
rb_alias(mValue, rb_intern(newName), rb_intern(originalName));
|
51
41
|
}
|
52
42
|
|
53
43
|
void RubyModule::checkType()
|
54
44
|
{
|
55
|
-
if (!
|
45
|
+
if (!mValue.isKindOf(rb_cModule)) {
|
56
46
|
throw std::logic_error("expected Module value");
|
57
47
|
}
|
58
48
|
}
|
@@ -67,9 +57,7 @@ namespace {
|
|
67
57
|
|
68
58
|
RubyValue defineClass(const RubyModule &under, const char *name)
|
69
59
|
{
|
70
|
-
return
|
71
|
-
return rb_define_class_under(under.toValue(), name, rb_cObject);
|
72
|
-
});
|
60
|
+
return rb_define_class_under(under.toValue(), name, rb_cObject);
|
73
61
|
}
|
74
62
|
|
75
63
|
}
|
data/ext/qml/rubyclass.h
CHANGED
@@ -30,26 +30,24 @@ public:
|
|
30
30
|
auto func = (VALUE (*)(...))wrapper::apply;
|
31
31
|
auto argc = wrapper::argc - 1;
|
32
32
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
rb_define_method(mValue , name, func, argc);
|
39
|
-
break;
|
40
|
-
case MethodAccess::Protected:
|
41
|
-
rb_define_protected_method(mValue, name, func, argc);
|
42
|
-
break;
|
43
|
-
case MethodAccess::Private:
|
44
|
-
rb_define_private_method(mValue, name, func, argc);
|
45
|
-
break;
|
46
|
-
}
|
33
|
+
switch (type) {
|
34
|
+
case MethodType::InstanceMethod:
|
35
|
+
switch (access) {
|
36
|
+
case MethodAccess::Public:
|
37
|
+
rb_define_method(mValue , name, func, argc);
|
47
38
|
break;
|
48
|
-
case
|
49
|
-
|
39
|
+
case MethodAccess::Protected:
|
40
|
+
rb_define_protected_method(mValue, name, func, argc);
|
41
|
+
break;
|
42
|
+
case MethodAccess::Private:
|
43
|
+
rb_define_private_method(mValue, name, func, argc);
|
50
44
|
break;
|
51
45
|
}
|
52
|
-
|
46
|
+
break;
|
47
|
+
case MethodType::ModuleFunction:
|
48
|
+
rb_define_module_function(mValue, name, func, argc);
|
49
|
+
break;
|
50
|
+
}
|
53
51
|
}
|
54
52
|
|
55
53
|
template <typename T>
|
@@ -92,7 +90,7 @@ private:
|
|
92
90
|
RubyValue ret;
|
93
91
|
// use tuple to avoid gcc 4.8's bug (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=55914)
|
94
92
|
auto tuple = std::make_tuple(args...);
|
95
|
-
|
93
|
+
convertCppErrors([&] {
|
96
94
|
ret = applyWithTuple(function, tuple);
|
97
95
|
});
|
98
96
|
return ret;
|
@@ -133,19 +131,17 @@ public:
|
|
133
131
|
}
|
134
132
|
mInstance.reset(new WrapperRubyClass(*this));
|
135
133
|
|
136
|
-
|
137
|
-
rb_define_alloc_func(toValue(), &alloc);
|
138
|
-
});
|
134
|
+
rb_define_alloc_func(toValue(), &alloc);
|
139
135
|
}
|
140
136
|
|
141
137
|
T *unwrap(RubyValue value)
|
142
138
|
{
|
143
139
|
auto klass = this->toValue();
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
140
|
+
|
141
|
+
if (!RTEST(rb_obj_is_kind_of(value, klass))) {
|
142
|
+
rb_raise(rb_eTypeError, "expected %s, got %s", rb_class2name(klass), rb_obj_classname(value));
|
143
|
+
}
|
144
|
+
|
149
145
|
T *ptr;
|
150
146
|
Data_Get_Struct(VALUE(value), T, ptr);
|
151
147
|
return ptr;
|