qml 0.0.5 → 0.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +57 -4
  3. data/changes.md +8 -0
  4. data/examples/fizzbuzz/fizzbuzz.rb +1 -1
  5. data/examples/imageprovider/imageprovider.rb +1 -1
  6. data/examples/todo_array/todo_array.rb +1 -1
  7. data/examples/todo_sequel/todo_sequel.rb +1 -1
  8. data/examples/twitter/twitter.rb +1 -1
  9. data/ext/qml/accessclass.cpp +5 -9
  10. data/ext/qml/conversionerror.h +14 -0
  11. data/ext/qml/ext_metaobject.cpp +30 -41
  12. data/ext/qml/init.cpp +5 -7
  13. data/ext/qml/rubyclass.cpp +6 -18
  14. data/ext/qml/rubyclass.h +22 -26
  15. data/ext/qml/rubyvalue.cpp +155 -221
  16. data/ext/qml/rubyvalue.h +30 -63
  17. data/ext/qml/signalforwarder.cpp +1 -3
  18. data/ext/qml/util.cpp +2 -25
  19. data/ext/qml/util.h +1 -21
  20. data/ext/qml/weakvaluereference.cpp +4 -5
  21. data/lib/qml/access.rb +9 -17
  22. data/lib/qml/application.rb +18 -21
  23. data/lib/qml/context.rb +1 -1
  24. data/lib/qml/dispatcher.rb +0 -1
  25. data/lib/qml/error_converter.rb +1 -0
  26. data/lib/qml/meta_object.rb +3 -3
  27. data/lib/qml/qt_object_base.rb +130 -5
  28. data/lib/qml/reactive/object.rb +34 -25
  29. data/lib/qml/reactive/signal.rb +6 -10
  30. data/lib/qml/reactive/unbound_property.rb +1 -1
  31. data/lib/qml/reactive/unbound_signal.rb +2 -2
  32. data/lib/qml/version.rb +1 -1
  33. data/spec/qml/reactive/object_spec.rb +14 -38
  34. data/spec/qml/reactive/signal_spec.rb +1 -1
  35. data/spec/qml/reactive/unbound_property_spec.rb +40 -0
  36. data/spec/qml/reactive/unbound_signal_spec.rb +70 -0
  37. data/spec/{shared_examples → shared}/qml/data/list_model.rb +0 -0
  38. data/spec/shared/qml/reactive/object.rb +39 -0
  39. data/spec/spec_helper.rb +1 -1
  40. metadata +12 -6
  41. data/lib/qml/class_builder.rb +0 -129
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 281f3641f4c5a3441c260dd874168fe99e6ce991
4
- data.tar.gz: 46b5c43d00a8a73d1553b327910581fe4569d147
3
+ metadata.gz: 88ec8d13931b6285ad6961a33b0fb5dd0e30582b
4
+ data.tar.gz: da96d985867d7ef034edcb60174cb4f64410783f
5
5
  SHA512:
6
- metadata.gz: 77c9acdfec3b5689b21425bcdfe4a5a11c2b27e615388faf520dc5c134cde441cfa1700b14f231d59a1a56d3dcc84f8c809b5400d1a4dbc6d5ffc3e8a52ab22b
7
- data.tar.gz: 83496cea61eb036a083457ee84d7be63b7b7b46d4c8968384eff708ad062b2cc1c5171716bec20c4ec9378a6e93f0d450491bd26835fe9e40ab0d04db94c0663
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=~/Qt/5.3/clang_64
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 (`~/Qt/5.3/clang_64` in this example) depends on your Qt installation configuration and Qt version.
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.application do |app|
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.application do |app|
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
@@ -38,6 +38,6 @@ module Examples
38
38
  end
39
39
  end
40
40
 
41
- QML.application do |app|
41
+ QML.run do |app|
42
42
  app.load_path Pathname(__FILE__) + '../main.qml'
43
43
  end
@@ -51,7 +51,7 @@ module Examples
51
51
  end
52
52
  end
53
53
 
54
- QML.application do |app|
54
+ QML.run do |app|
55
55
  app.engine.add_image_provider 'example', Examples::ImageProvider::Provider.new
56
56
  app.load_path Pathname(__FILE__) + '../main.qml'
57
57
  end
@@ -28,6 +28,6 @@ module Examples
28
28
  end
29
29
  end
30
30
 
31
- QML.application do |app|
31
+ QML.run do |app|
32
32
  app.load_path Pathname(__FILE__) + '../main.qml'
33
33
  end
@@ -61,6 +61,6 @@ module Examples
61
61
  end
62
62
  end
63
63
 
64
- QML.application do |app|
64
+ QML.run do |app|
65
65
  app.load_path Pathname(__FILE__) + '../main.qml'
66
66
  end
@@ -72,6 +72,6 @@ module Examples
72
72
  end
73
73
  end
74
74
 
75
- QML.application do |app|
75
+ QML.run do |app|
76
76
  app.load_path Pathname(__FILE__) + '../main.qml'
77
77
  end
@@ -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
- protect([&] {
12
- rb_check_array_type(methodInfos);
13
- rb_check_array_type(signalInfos);
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
- protect([&] {
50
- rescueNotify([&] {
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
  });
@@ -0,0 +1,14 @@
1
+ #pragma once
2
+
3
+ #include <stdexcept>
4
+ #include <QString>
5
+
6
+ namespace RubyQml {
7
+
8
+ class ConversionError : public std::runtime_error
9
+ {
10
+ public:
11
+ ConversionError(const QString &str) : std::runtime_error(str.toStdString()) {}
12
+ };
13
+
14
+ }
@@ -18,13 +18,11 @@ namespace {
18
18
 
19
19
  RubyValue idListToArray(const QList<ID> &xs)
20
20
  {
21
- return protect([&] {
22
- auto ary = rb_ary_new();
23
- for (ID id : xs) {
24
- rb_ary_push(ary, ID2SYM(id));
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
- protect([&] {
152
- args = rb_check_array_type(args);
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
- rb_raise(rb_path2class("QML::MethodError"),
167
- "method mismatch (%s with params %s in %s)",
168
- mMetaObject->method(methodIndexes.first()).name().data(),
169
- StringValueCStr(classes_str),
170
- mMetaObject->className());
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
- protect([&] {
194
- rb_raise(rb_path2class("QML::MethodError"),
195
- "signal not found (%s in %s)",
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
- protect([&] {
227
- rb_raise(rb_path2class("QML::PropertyError"),
228
- "type mismatch (%s for %s)",
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
- protect([&] {
268
- rb_raise(rb_path2class("QML::MethodError"),
269
- "method not found (%s in %s)",
270
- rb_id2name(id),
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
- protect([&] {
282
- rb_raise(rb_path2class("QML::PropertyError"),
283
- "property not found (%s in %s)",
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
  }
@@ -48,7 +48,7 @@ void cleanup()
48
48
 
49
49
  void setupEndProc()
50
50
  {
51
- rb_set_end_proc([](VALUE) { unprotect(cleanup); }, Qnil);
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
- unprotect([&] {
64
- defineMetaTypes();
65
- defineClasses();
66
- setupGlobalGCMarking();
67
- setupEndProc();
68
- });
63
+ defineMetaTypes();
64
+ defineClasses();
65
+ setupGlobalGCMarking();
66
+ setupEndProc();
69
67
  }
@@ -15,16 +15,12 @@ RubyModule::RubyModule(RubyValue moduleValue) :
15
15
 
16
16
  RubyModule::RubyModule(const char *name)
17
17
  {
18
- protect([&] {
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
- protect([&] {
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
- RubyValue ret;
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
- protect([&] {
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 (!protect([&] { return rb_obj_is_kind_of(mValue, rb_cModule); })) {
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 protect([&] {
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
  }
@@ -30,26 +30,24 @@ public:
30
30
  auto func = (VALUE (*)(...))wrapper::apply;
31
31
  auto argc = wrapper::argc - 1;
32
32
 
33
- protect([&] {
34
- switch (type) {
35
- case MethodType::InstanceMethod:
36
- switch (access) {
37
- case MethodAccess::Public:
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 MethodType::ModuleFunction:
49
- rb_define_module_function(mValue, name, func, argc);
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
- unprotect([&] {
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
- protect([&] {
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
- protect([&] {
145
- if (!RTEST(rb_obj_is_kind_of(value, klass))) {
146
- rb_raise(rb_eTypeError, "expected %s, got %s", rb_class2name(klass), rb_obj_classname(value));
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;