qml 0.0.5 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
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;