qml 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (170) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +46 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +15 -0
  5. data/.yardopts +4 -0
  6. data/Gemfile +4 -0
  7. data/LICENSE.txt +22 -0
  8. data/README.md +351 -0
  9. data/Rakefile +6 -0
  10. data/examples/assets/fonts/fontawesome-webfont.ttf +0 -0
  11. data/examples/fizzbuzz/fizzbuzz.rb +43 -0
  12. data/examples/fizzbuzz/main.qml +38 -0
  13. data/examples/imageprovider/imageprovider.rb +57 -0
  14. data/examples/imageprovider/main.qml +51 -0
  15. data/examples/todo/main.qml +70 -0
  16. data/examples/todo/todo.rb +36 -0
  17. data/examples/twitter/main.qml +36 -0
  18. data/examples/twitter/twitter.rb +55 -0
  19. data/ext/qml/accessclass.cpp +71 -0
  20. data/ext/qml/accessclass.h +19 -0
  21. data/ext/qml/accessobject.cpp +30 -0
  22. data/ext/qml/accessobject.h +22 -0
  23. data/ext/qml/application.cpp +54 -0
  24. data/ext/qml/application.h +17 -0
  25. data/ext/qml/common.h +18 -0
  26. data/ext/qml/ext_accesssupport.cpp +77 -0
  27. data/ext/qml/ext_accesssupport.h +42 -0
  28. data/ext/qml/ext_gcmarker.cpp +39 -0
  29. data/ext/qml/ext_gcmarker.h +27 -0
  30. data/ext/qml/ext_kernel.cpp +62 -0
  31. data/ext/qml/ext_kernel.h +11 -0
  32. data/ext/qml/ext_metaobject.cpp +410 -0
  33. data/ext/qml/ext_metaobject.h +62 -0
  34. data/ext/qml/ext_pluginloader.cpp +55 -0
  35. data/ext/qml/ext_pluginloader.h +32 -0
  36. data/ext/qml/ext_pointer.cpp +134 -0
  37. data/ext/qml/ext_pointer.h +43 -0
  38. data/ext/qml/ext_testutil.cpp +42 -0
  39. data/ext/qml/ext_testutil.h +11 -0
  40. data/ext/qml/extconf.rb +84 -0
  41. data/ext/qml/foreignclass.cpp +72 -0
  42. data/ext/qml/foreignclass.h +88 -0
  43. data/ext/qml/foreignmetaobject.cpp +345 -0
  44. data/ext/qml/foreignmetaobject.h +46 -0
  45. data/ext/qml/foreignobject.cpp +22 -0
  46. data/ext/qml/foreignobject.h +21 -0
  47. data/ext/qml/functioninfo.h +16 -0
  48. data/ext/qml/init.cpp +69 -0
  49. data/ext/qml/listmodel.cpp +112 -0
  50. data/ext/qml/listmodel.h +43 -0
  51. data/ext/qml/markable.h +12 -0
  52. data/ext/qml/objectdata.cpp +26 -0
  53. data/ext/qml/objectdata.h +20 -0
  54. data/ext/qml/objectgc.cpp +69 -0
  55. data/ext/qml/objectgc.h +28 -0
  56. data/ext/qml/plugins/core/applicationextension.cpp +34 -0
  57. data/ext/qml/plugins/core/applicationextension.h +28 -0
  58. data/ext/qml/plugins/core/componentextension.cpp +41 -0
  59. data/ext/qml/plugins/core/componentextension.h +28 -0
  60. data/ext/qml/plugins/core/contextextension.cpp +39 -0
  61. data/ext/qml/plugins/core/contextextension.h +29 -0
  62. data/ext/qml/plugins/core/core.pro +29 -0
  63. data/ext/qml/plugins/core/coreplugin.cpp +87 -0
  64. data/ext/qml/plugins/core/coreplugin.h +49 -0
  65. data/ext/qml/plugins/core/engineextension.cpp +27 -0
  66. data/ext/qml/plugins/core/engineextension.h +28 -0
  67. data/ext/qml/plugins/core/imageprovider.cpp +38 -0
  68. data/ext/qml/plugins/core/imageprovider.h +18 -0
  69. data/ext/qml/plugins/core/imagerequestpromise.cpp +19 -0
  70. data/ext/qml/plugins/core/imagerequestpromise.h +21 -0
  71. data/ext/qml/plugins/core/qmlexception.cpp +11 -0
  72. data/ext/qml/plugins/core/qmlexception.h +17 -0
  73. data/ext/qml/plugins/testutil/objectlifechecker.cpp +17 -0
  74. data/ext/qml/plugins/testutil/objectlifechecker.h +24 -0
  75. data/ext/qml/plugins/testutil/ownershiptest.cpp +26 -0
  76. data/ext/qml/plugins/testutil/ownershiptest.h +30 -0
  77. data/ext/qml/plugins/testutil/testobject.cpp +6 -0
  78. data/ext/qml/plugins/testutil/testobject.h +108 -0
  79. data/ext/qml/plugins/testutil/testobjectsubclass.cpp +10 -0
  80. data/ext/qml/plugins/testutil/testobjectsubclass.h +19 -0
  81. data/ext/qml/plugins/testutil/testutil.pro +20 -0
  82. data/ext/qml/plugins/testutil/testutilplugin.cpp +47 -0
  83. data/ext/qml/plugins/testutil/testutilplugin.h +32 -0
  84. data/ext/qml/qmltyperegisterer.cpp +74 -0
  85. data/ext/qml/qmltyperegisterer.h +30 -0
  86. data/ext/qml/rubyclass.cpp +94 -0
  87. data/ext/qml/rubyclass.h +234 -0
  88. data/ext/qml/rubyvalue.cpp +690 -0
  89. data/ext/qml/rubyvalue.h +256 -0
  90. data/ext/qml/signalforwarder.cpp +66 -0
  91. data/ext/qml/signalforwarder.h +29 -0
  92. data/ext/qml/util.cpp +120 -0
  93. data/ext/qml/util.h +101 -0
  94. data/ext/qml/valuereference.cpp +50 -0
  95. data/ext/qml/valuereference.h +22 -0
  96. data/ext/qml/weakvaluereference.cpp +27 -0
  97. data/ext/qml/weakvaluereference.h +19 -0
  98. data/lib/qml.rb +41 -0
  99. data/lib/qml/access.rb +137 -0
  100. data/lib/qml/application.rb +139 -0
  101. data/lib/qml/class_builder.rb +126 -0
  102. data/lib/qml/component.rb +53 -0
  103. data/lib/qml/context.rb +71 -0
  104. data/lib/qml/data.rb +2 -0
  105. data/lib/qml/data/array_model.rb +103 -0
  106. data/lib/qml/data/error.rb +5 -0
  107. data/lib/qml/data/list_model.rb +146 -0
  108. data/lib/qml/dispatchable.rb +34 -0
  109. data/lib/qml/dispatcher.rb +61 -0
  110. data/lib/qml/engine.rb +54 -0
  111. data/lib/qml/error_converter.rb +15 -0
  112. data/lib/qml/errors.rb +26 -0
  113. data/lib/qml/geometry.rb +3 -0
  114. data/lib/qml/geometry/point.rb +5 -0
  115. data/lib/qml/geometry/rectangle.rb +5 -0
  116. data/lib/qml/geometry/size.rb +5 -0
  117. data/lib/qml/image_provider.rb +87 -0
  118. data/lib/qml/meta_object.rb +20 -0
  119. data/lib/qml/models.rb +1 -0
  120. data/lib/qml/name_helper.rb +12 -0
  121. data/lib/qml/platform.rb +15 -0
  122. data/lib/qml/plugin_loader.rb +46 -0
  123. data/lib/qml/plugins.rb +26 -0
  124. data/lib/qml/qml.rb +1 -0
  125. data/lib/qml/qt.rb +6 -0
  126. data/lib/qml/qt_classes.rb +9 -0
  127. data/lib/qml/qt_object_base.rb +108 -0
  128. data/lib/qml/reactive.rb +8 -0
  129. data/lib/qml/reactive/bindable.rb +79 -0
  130. data/lib/qml/reactive/chained_signal.rb +25 -0
  131. data/lib/qml/reactive/error.rb +5 -0
  132. data/lib/qml/reactive/object.rb +278 -0
  133. data/lib/qml/reactive/property.rb +19 -0
  134. data/lib/qml/reactive/signal.rb +116 -0
  135. data/lib/qml/reactive/signal_spy.rb +27 -0
  136. data/lib/qml/reactive/signals/map_signal.rb +21 -0
  137. data/lib/qml/reactive/signals/merge_signal.rb +21 -0
  138. data/lib/qml/reactive/signals/select_signal.rb +21 -0
  139. data/lib/qml/reactive/simple_property.rb +17 -0
  140. data/lib/qml/reactive/unbound_property.rb +42 -0
  141. data/lib/qml/reactive/unbound_signal.rb +51 -0
  142. data/lib/qml/root_path.rb +3 -0
  143. data/lib/qml/test_util.rb +1 -0
  144. data/lib/qml/test_util/object_life_checker.rb +17 -0
  145. data/lib/qml/version.rb +3 -0
  146. data/lib/qml/wrappable.rb +9 -0
  147. data/qml.gemspec +28 -0
  148. data/spec/assets/testobj.qml +5 -0
  149. data/spec/qml/.access_spec.rb.swp +0 -0
  150. data/spec/qml/access_spec.rb +162 -0
  151. data/spec/qml/application_spec.rb +43 -0
  152. data/spec/qml/component_spec.rb +44 -0
  153. data/spec/qml/context_spec.rb +43 -0
  154. data/spec/qml/conversion_spec.rb +59 -0
  155. data/spec/qml/data/array_model_spec.rb +215 -0
  156. data/spec/qml/dispatchable_spec.rb +26 -0
  157. data/spec/qml/dispatcher_spec.rb +48 -0
  158. data/spec/qml/geometry/point_spec.rb +4 -0
  159. data/spec/qml/geometry/rectangle_spec.rb +4 -0
  160. data/spec/qml/geometry/size_spec.rb +4 -0
  161. data/spec/qml/plugin_loader_spec.rb +33 -0
  162. data/spec/qml/qt_object_base_spec.rb +119 -0
  163. data/spec/qml/reactive/object_spec.rb +273 -0
  164. data/spec/qml/reactive/property_spec.rb +70 -0
  165. data/spec/qml/reactive/signal_spec.rb +191 -0
  166. data/spec/qml/reactive/signal_spy_spec.rb +26 -0
  167. data/spec/qml/test_object_spec.rb +186 -0
  168. data/spec/qml_spec.rb +7 -0
  169. data/spec/spec_helper.rb +5 -0
  170. metadata +321 -0
@@ -0,0 +1,32 @@
1
+ #pragma once
2
+ #include <QObject>
3
+ #include <QVariant>
4
+
5
+ namespace RubyQml {
6
+
7
+ class TestObject;
8
+ class TestObjectSubclass;
9
+ class OwnershipTest;
10
+ class ObjectLifeChecker;
11
+
12
+ class TestUtilPlugin : public QObject
13
+ {
14
+ Q_OBJECT
15
+ Q_PLUGIN_METADATA(IID "org.ruby-qml.RubyQml.TestObject")
16
+ public:
17
+ explicit TestUtilPlugin(QObject *parent = 0);
18
+ signals:
19
+
20
+ public slots:
21
+ QVariantHash metaObjects() { return mMetaObjects; }
22
+
23
+ RubyQml::TestObject *createTestObject();
24
+ RubyQml::TestObjectSubclass *createTestObjectSubclass();
25
+ RubyQml::OwnershipTest *createOwnershipTest();
26
+ RubyQml::ObjectLifeChecker *createObjectLifeChecker(QObject *target);
27
+
28
+ private:
29
+ QVariantHash mMetaObjects;
30
+ };
31
+
32
+ } // namespace RubyQml
@@ -0,0 +1,74 @@
1
+ #include "qmltyperegisterer.h"
2
+ #include "foreignmetaobject.h"
3
+ #include "accessobject.h"
4
+ #include <QtQml>
5
+
6
+ namespace RubyQml {
7
+
8
+ QmlTypeRegisterer::QmlTypeRegisterer(const SP<ForeignMetaObject> &metaObject, const std::function<void (void *)> &createFunc) :
9
+ mMetaObject(metaObject),
10
+ mCreateFunc(createFunc)
11
+ {
12
+ mFactoryArgs[0] = &ffi_type_pointer;
13
+ if (ffi_prep_cif(&mFactoryCif, FFI_DEFAULT_ABI, 1, &ffi_type_void, mFactoryArgs) != FFI_OK) {
14
+ throw std::runtime_error("failed to prepare FFI call interface");
15
+ }
16
+ mFactoryClosure = (ffi_closure *)ffi_closure_alloc(sizeof(ffi_closure), (void **)(&mFactoryFunc));
17
+ if (!mFactoryClosure) {
18
+ throw std::runtime_error("failed to allocate FFI closure");
19
+ }
20
+
21
+ auto callback = [](ffi_cif *cif, void *ret, void **args, void *data) {
22
+ Q_UNUSED(cif);
23
+ Q_UNUSED(ret);
24
+ auto self = (QmlTypeRegisterer *)(data);
25
+ self->mCreateFunc(*(void **)(args[0]));
26
+ };
27
+
28
+ if (ffi_prep_closure_loc(mFactoryClosure, &mFactoryCif, callback, this, (void *)mFactoryFunc) != FFI_OK) {
29
+ ffi_closure_free(mFactoryClosure);
30
+ throw std::runtime_error("failed to prepare FFI closure");
31
+ }
32
+ }
33
+
34
+ QmlTypeRegisterer::~QmlTypeRegisterer()
35
+ {
36
+ ffi_closure_free(mFactoryClosure);
37
+ }
38
+
39
+ void QmlTypeRegisterer::registerType(const char *uri, int versionMajor, int versionMinor, const char *qmlName)
40
+ {
41
+ QByteArray className;
42
+ className += mMetaObject->className();
43
+ className += "*";
44
+
45
+ QByteArray listName;
46
+ listName += "QQmlListProperty<";
47
+ listName += mMetaObject->className();
48
+ listName += ">";
49
+
50
+ QQmlPrivate::RegisterType type = {
51
+ 0,
52
+ qRegisterNormalizedMetaType<AccessWrapper *>(className),
53
+ qRegisterNormalizedMetaType<QQmlListProperty<AccessWrapper> >(listName),
54
+ sizeof(AccessWrapper), mFactoryFunc,
55
+ QString(),
56
+
57
+ uri, versionMajor, versionMinor, qmlName, mMetaObject.get(),
58
+
59
+ 0, 0,
60
+
61
+ QQmlPrivate::StaticCastSelector<AccessWrapper,QQmlParserStatus>::cast(),
62
+ QQmlPrivate::StaticCastSelector<AccessWrapper,QQmlPropertyValueSource>::cast(),
63
+ QQmlPrivate::StaticCastSelector<AccessWrapper,QQmlPropertyValueInterceptor>::cast(),
64
+
65
+ 0, 0,
66
+
67
+ 0,
68
+ 0
69
+ };
70
+
71
+ QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
72
+ }
73
+
74
+ } // namespace RubyQml
@@ -0,0 +1,30 @@
1
+ #pragma once
2
+ #include "common.h"
3
+ #include <ffi.h>
4
+ #include <functional>
5
+
6
+ namespace RubyQml {
7
+
8
+ class ForeignMetaObject;
9
+
10
+ class QmlTypeRegisterer
11
+ {
12
+ public:
13
+ using FactoryFunction = void (*)(void *);
14
+
15
+ QmlTypeRegisterer(const SP<ForeignMetaObject> &metaObject, const std::function<void(void *)> &createFunc);
16
+ ~QmlTypeRegisterer();
17
+
18
+ void registerType(const char *uri, int versionMajor, int versionMinor, const char *qmlName);
19
+
20
+ private:
21
+
22
+ SP<ForeignMetaObject> mMetaObject;
23
+ std::function<void (void *)> mCreateFunc;
24
+ ffi_type *mFactoryArgs[1];
25
+ ffi_cif mFactoryCif;
26
+ ffi_closure *mFactoryClosure = nullptr;
27
+ FactoryFunction mFactoryFunc = nullptr;
28
+ };
29
+
30
+ } // namespace RubyQml
@@ -0,0 +1,94 @@
1
+ #include "rubyclass.h"
2
+
3
+ namespace RubyQml {
4
+
5
+ RubyModule::RubyModule(VALUE moduleValue) :
6
+ RubyModule(RubyValue(moduleValue))
7
+ {
8
+ }
9
+
10
+ RubyModule::RubyModule(RubyValue moduleValue) :
11
+ mValue(moduleValue)
12
+ {
13
+ checkType();
14
+ }
15
+
16
+ RubyModule::RubyModule(const char *name)
17
+ {
18
+ protect([&] {
19
+ mValue = rb_define_module(name);
20
+ });
21
+ }
22
+
23
+ RubyModule::RubyModule(const RubyModule &under, const char *name)
24
+ {
25
+ protect([&] {
26
+ mValue = rb_define_module_under(under.toValue(), name);
27
+ });
28
+ }
29
+
30
+ RubyModule &RubyModule::operator=(const RubyModule &other)
31
+ {
32
+ mValue = other.mValue;
33
+ checkType();
34
+ return *this;
35
+ }
36
+
37
+ RubyModule RubyModule::fromPath(const char *path)
38
+ {
39
+ RubyValue ret;
40
+ protect([&] {
41
+ ret = rb_path2class(path);
42
+ });
43
+ return ret;
44
+ }
45
+
46
+ void RubyModule::aliasMethod(const char *newName, const char *originalName)
47
+ {
48
+ protect([&] {
49
+ rb_alias(mValue, rb_intern(newName), rb_intern(originalName));
50
+ });
51
+ }
52
+
53
+ void RubyModule::checkType()
54
+ {
55
+ if (!protect([&] { return rb_obj_is_kind_of(mValue, rb_cModule); })) {
56
+ throw std::logic_error("expected Module value");
57
+ }
58
+ }
59
+
60
+ RubyClass::RubyClass(RubyValue classValue) :
61
+ RubyModule(classValue)
62
+ {
63
+ checkType();
64
+ }
65
+
66
+ namespace {
67
+
68
+ RubyValue defineClass(const RubyModule &under, const char *name)
69
+ {
70
+ return protect([&] {
71
+ return rb_define_class_under(under.toValue(), name, rb_cObject);
72
+ });
73
+ }
74
+
75
+ }
76
+
77
+ RubyClass::RubyClass(const RubyModule &under, const char *name) :
78
+ RubyModule(defineClass(under, name))
79
+ {
80
+ }
81
+
82
+ RubyClass RubyClass::fromPath(const char *path)
83
+ {
84
+ return RubyClass(RubyModule::fromPath(path).toValue());
85
+ }
86
+
87
+ void RubyClass::checkType()
88
+ {
89
+ if (!toValue().isKindOf(rb_cClass)) {
90
+ throw std::logic_error("expected Class value");
91
+ }
92
+ }
93
+
94
+ } // namespace RubyQml
@@ -0,0 +1,234 @@
1
+ #pragma once
2
+ #include "functioninfo.h"
3
+ #include "rubyvalue.h"
4
+ #include <QDebug>
5
+ #include <memory>
6
+
7
+ namespace RubyQml {
8
+
9
+ enum class MethodAccess { Public, Protected, Private };
10
+ enum class MethodType { InstanceMethod, ModuleFunction };
11
+
12
+ class RubyModule
13
+ {
14
+ public:
15
+ RubyModule() = default;
16
+ RubyModule(VALUE moduleValue);
17
+ RubyModule(RubyValue moduleValue);
18
+ RubyModule(const char *name);
19
+ RubyModule(const RubyModule &under, const char *name);
20
+ RubyModule(const RubyModule &) = default;
21
+ RubyModule(RubyModule &&) = default;
22
+ RubyModule &operator=(const RubyModule &other);
23
+
24
+ static RubyModule fromPath(const char *path);
25
+
26
+ template <typename TFunction, TFunction function>
27
+ void defineMethod(MethodType type, MethodAccess access, const char *name, FunctionInfo<TFunction, function>)
28
+ {
29
+ using wrapper = FunctionWrapper<TFunction, function>;
30
+ auto func = (VALUE (*)(...))wrapper::apply;
31
+ auto argc = wrapper::argc - 1;
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
+ }
47
+ break;
48
+ case MethodType::ModuleFunction:
49
+ rb_define_module_function(mValue, name, func, argc);
50
+ break;
51
+ }
52
+ });
53
+ }
54
+
55
+ template <typename T>
56
+ void defineMethod(MethodAccess access, const char *name, T info)
57
+ {
58
+ defineMethod(MethodType::InstanceMethod, access, name, info);
59
+ }
60
+
61
+ template <typename T>
62
+ void defineModuleFunction(const char *name, T info)
63
+ {
64
+ defineMethod(MethodType::ModuleFunction, MethodAccess::Public, name, info);
65
+ }
66
+
67
+ template <typename T>
68
+ void defineMethod(const char *name, T info)
69
+ {
70
+ defineMethod(MethodAccess::Public, name, info);
71
+ }
72
+
73
+ void aliasMethod(const char *newName, const char *originalName);
74
+
75
+ RubyValue toValue() const { return mValue; }
76
+ operator RubyValue() const { return toValue(); }
77
+ operator VALUE() const { return toValue(); }
78
+
79
+ virtual void checkType();
80
+
81
+ private:
82
+ template <typename TFunction, TFunction function>
83
+ struct FunctionWrapper;
84
+
85
+ template <typename ... TArgs, RubyValue (*function)(TArgs...)>
86
+ struct FunctionWrapper<RubyValue (*)(TArgs...), function>
87
+ {
88
+ static constexpr size_t argc = sizeof...(TArgs);
89
+
90
+ static VALUE apply(typename std::conditional<true, VALUE, TArgs>::type... args)
91
+ {
92
+ RubyValue ret;
93
+ // use tuple to avoid gcc 4.8's bug (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=55914)
94
+ auto tuple = std::make_tuple(args...);
95
+ unprotect([&] {
96
+ ret = applyWithTuple(function, tuple);
97
+ });
98
+ return ret;
99
+ }
100
+ };
101
+
102
+ RubyValue mValue;
103
+ };
104
+
105
+ class RubyClass : public RubyModule
106
+ {
107
+ public:
108
+ RubyClass() = default;
109
+ RubyClass(RubyValue classValue);
110
+ RubyClass(const RubyModule &under, const char *name);
111
+
112
+ static RubyClass fromPath(const char *path);
113
+
114
+ void checkType() override;
115
+
116
+ template <typename ... Args>
117
+ RubyValue newInstance(Args ... args)
118
+ {
119
+ return toValue().send(RUBYQML_INTERN("new"), args...);
120
+ }
121
+ };
122
+
123
+
124
+ template <typename T>
125
+ class WrapperRubyClass : public RubyClass
126
+ {
127
+ public:
128
+ WrapperRubyClass(const RubyModule &under, const char *name) :
129
+ RubyClass(under, name)
130
+ {
131
+ if (mInstance) {
132
+ throw std::logic_error("class already defined");
133
+ }
134
+ mInstance.reset(new WrapperRubyClass(*this));
135
+
136
+ protect([&] {
137
+ rb_define_alloc_func(toValue(), &alloc);
138
+ });
139
+ }
140
+
141
+ T *unwrap(RubyValue value)
142
+ {
143
+ 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
+ });
149
+ T *ptr;
150
+ Data_Get_Struct(VALUE(value), T, ptr);
151
+ return ptr;
152
+ }
153
+
154
+ using RubyClass::defineMethod;
155
+
156
+ template <typename TMemberFunction, TMemberFunction memberFunction>
157
+ void defineMethod(MethodAccess access, const char *name, MemberFunctionInfo<TMemberFunction, memberFunction>)
158
+ {
159
+ using wrapper = MethodWrapper<TMemberFunction, memberFunction>;
160
+ defineMethod(access, name, RUBYQML_FUNCTION_INFO(&wrapper::apply));
161
+ }
162
+
163
+ template <typename TMemberFunction, TMemberFunction memberFunction>
164
+ void defineMethod(const char *name, MemberFunctionInfo<TMemberFunction, memberFunction> info)
165
+ {
166
+ defineMethod(MethodAccess::Public, name, info);
167
+ }
168
+
169
+ static WrapperRubyClass instance()
170
+ {
171
+ if (!mInstance) {
172
+ throw std::logic_error("class not yet defined");
173
+ }
174
+ return *mInstance;
175
+ }
176
+
177
+ private:
178
+
179
+ template <typename TMemberFunction, TMemberFunction memfn>
180
+ struct MethodWrapper;
181
+
182
+ template <typename ... TArgs, RubyValue (T::*memfn)(TArgs ...)>
183
+ struct MethodWrapper<RubyValue (T::*)(TArgs ...), memfn>
184
+ {
185
+ static RubyValue apply(RubyValue self, TArgs ... args)
186
+ {
187
+ return (instance().unwrap(self)->*memfn)(args ...);
188
+ }
189
+ };
190
+
191
+ template <typename ... TArgs, RubyValue (T::*memfn)(TArgs ...) const>
192
+ struct MethodWrapper<RubyValue (T::*)(TArgs ...) const, memfn>
193
+ {
194
+ static RubyValue apply(RubyValue self, TArgs... args)
195
+ {
196
+ return (instance().unwrap(self)->*memfn)(args ...);
197
+ }
198
+ };
199
+
200
+ static void mark(T *ptr) noexcept
201
+ {
202
+ ptr->gc_mark();
203
+ }
204
+
205
+ static void dealloc(T *ptr) noexcept
206
+ {
207
+ withoutGvl([&] {
208
+ ptr->~T();
209
+ });
210
+ ruby_xfree(ptr);
211
+ }
212
+
213
+ static VALUE alloc(VALUE klass) noexcept
214
+ {
215
+ auto ptr = ruby_xmalloc(sizeof(T));
216
+ auto self = Data_Wrap_Struct(klass, &mark, &dealloc, ptr);
217
+ new(ptr) T(self);
218
+ return self;
219
+ }
220
+
221
+ static std::unique_ptr<WrapperRubyClass> mInstance;
222
+ };
223
+
224
+ template <typename T>
225
+ std::unique_ptr<WrapperRubyClass<T>> WrapperRubyClass<T>::mInstance = nullptr;
226
+
227
+ template <typename T>
228
+ inline WrapperRubyClass<T> wrapperRubyClass()
229
+ {
230
+ return WrapperRubyClass<T>::instance();
231
+ }
232
+
233
+ } // namespace RubyQml
234
+