qml 0.0.1
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.
- checksums.yaml +7 -0
- data/.gitignore +46 -0
- data/.rspec +2 -0
- data/.travis.yml +15 -0
- data/.yardopts +4 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +351 -0
- data/Rakefile +6 -0
- data/examples/assets/fonts/fontawesome-webfont.ttf +0 -0
- data/examples/fizzbuzz/fizzbuzz.rb +43 -0
- data/examples/fizzbuzz/main.qml +38 -0
- data/examples/imageprovider/imageprovider.rb +57 -0
- data/examples/imageprovider/main.qml +51 -0
- data/examples/todo/main.qml +70 -0
- data/examples/todo/todo.rb +36 -0
- data/examples/twitter/main.qml +36 -0
- data/examples/twitter/twitter.rb +55 -0
- data/ext/qml/accessclass.cpp +71 -0
- data/ext/qml/accessclass.h +19 -0
- data/ext/qml/accessobject.cpp +30 -0
- data/ext/qml/accessobject.h +22 -0
- data/ext/qml/application.cpp +54 -0
- data/ext/qml/application.h +17 -0
- data/ext/qml/common.h +18 -0
- data/ext/qml/ext_accesssupport.cpp +77 -0
- data/ext/qml/ext_accesssupport.h +42 -0
- data/ext/qml/ext_gcmarker.cpp +39 -0
- data/ext/qml/ext_gcmarker.h +27 -0
- data/ext/qml/ext_kernel.cpp +62 -0
- data/ext/qml/ext_kernel.h +11 -0
- data/ext/qml/ext_metaobject.cpp +410 -0
- data/ext/qml/ext_metaobject.h +62 -0
- data/ext/qml/ext_pluginloader.cpp +55 -0
- data/ext/qml/ext_pluginloader.h +32 -0
- data/ext/qml/ext_pointer.cpp +134 -0
- data/ext/qml/ext_pointer.h +43 -0
- data/ext/qml/ext_testutil.cpp +42 -0
- data/ext/qml/ext_testutil.h +11 -0
- data/ext/qml/extconf.rb +84 -0
- data/ext/qml/foreignclass.cpp +72 -0
- data/ext/qml/foreignclass.h +88 -0
- data/ext/qml/foreignmetaobject.cpp +345 -0
- data/ext/qml/foreignmetaobject.h +46 -0
- data/ext/qml/foreignobject.cpp +22 -0
- data/ext/qml/foreignobject.h +21 -0
- data/ext/qml/functioninfo.h +16 -0
- data/ext/qml/init.cpp +69 -0
- data/ext/qml/listmodel.cpp +112 -0
- data/ext/qml/listmodel.h +43 -0
- data/ext/qml/markable.h +12 -0
- data/ext/qml/objectdata.cpp +26 -0
- data/ext/qml/objectdata.h +20 -0
- data/ext/qml/objectgc.cpp +69 -0
- data/ext/qml/objectgc.h +28 -0
- data/ext/qml/plugins/core/applicationextension.cpp +34 -0
- data/ext/qml/plugins/core/applicationextension.h +28 -0
- data/ext/qml/plugins/core/componentextension.cpp +41 -0
- data/ext/qml/plugins/core/componentextension.h +28 -0
- data/ext/qml/plugins/core/contextextension.cpp +39 -0
- data/ext/qml/plugins/core/contextextension.h +29 -0
- data/ext/qml/plugins/core/core.pro +29 -0
- data/ext/qml/plugins/core/coreplugin.cpp +87 -0
- data/ext/qml/plugins/core/coreplugin.h +49 -0
- data/ext/qml/plugins/core/engineextension.cpp +27 -0
- data/ext/qml/plugins/core/engineextension.h +28 -0
- data/ext/qml/plugins/core/imageprovider.cpp +38 -0
- data/ext/qml/plugins/core/imageprovider.h +18 -0
- data/ext/qml/plugins/core/imagerequestpromise.cpp +19 -0
- data/ext/qml/plugins/core/imagerequestpromise.h +21 -0
- data/ext/qml/plugins/core/qmlexception.cpp +11 -0
- data/ext/qml/plugins/core/qmlexception.h +17 -0
- data/ext/qml/plugins/testutil/objectlifechecker.cpp +17 -0
- data/ext/qml/plugins/testutil/objectlifechecker.h +24 -0
- data/ext/qml/plugins/testutil/ownershiptest.cpp +26 -0
- data/ext/qml/plugins/testutil/ownershiptest.h +30 -0
- data/ext/qml/plugins/testutil/testobject.cpp +6 -0
- data/ext/qml/plugins/testutil/testobject.h +108 -0
- data/ext/qml/plugins/testutil/testobjectsubclass.cpp +10 -0
- data/ext/qml/plugins/testutil/testobjectsubclass.h +19 -0
- data/ext/qml/plugins/testutil/testutil.pro +20 -0
- data/ext/qml/plugins/testutil/testutilplugin.cpp +47 -0
- data/ext/qml/plugins/testutil/testutilplugin.h +32 -0
- data/ext/qml/qmltyperegisterer.cpp +74 -0
- data/ext/qml/qmltyperegisterer.h +30 -0
- data/ext/qml/rubyclass.cpp +94 -0
- data/ext/qml/rubyclass.h +234 -0
- data/ext/qml/rubyvalue.cpp +690 -0
- data/ext/qml/rubyvalue.h +256 -0
- data/ext/qml/signalforwarder.cpp +66 -0
- data/ext/qml/signalforwarder.h +29 -0
- data/ext/qml/util.cpp +120 -0
- data/ext/qml/util.h +101 -0
- data/ext/qml/valuereference.cpp +50 -0
- data/ext/qml/valuereference.h +22 -0
- data/ext/qml/weakvaluereference.cpp +27 -0
- data/ext/qml/weakvaluereference.h +19 -0
- data/lib/qml.rb +41 -0
- data/lib/qml/access.rb +137 -0
- data/lib/qml/application.rb +139 -0
- data/lib/qml/class_builder.rb +126 -0
- data/lib/qml/component.rb +53 -0
- data/lib/qml/context.rb +71 -0
- data/lib/qml/data.rb +2 -0
- data/lib/qml/data/array_model.rb +103 -0
- data/lib/qml/data/error.rb +5 -0
- data/lib/qml/data/list_model.rb +146 -0
- data/lib/qml/dispatchable.rb +34 -0
- data/lib/qml/dispatcher.rb +61 -0
- data/lib/qml/engine.rb +54 -0
- data/lib/qml/error_converter.rb +15 -0
- data/lib/qml/errors.rb +26 -0
- data/lib/qml/geometry.rb +3 -0
- data/lib/qml/geometry/point.rb +5 -0
- data/lib/qml/geometry/rectangle.rb +5 -0
- data/lib/qml/geometry/size.rb +5 -0
- data/lib/qml/image_provider.rb +87 -0
- data/lib/qml/meta_object.rb +20 -0
- data/lib/qml/models.rb +1 -0
- data/lib/qml/name_helper.rb +12 -0
- data/lib/qml/platform.rb +15 -0
- data/lib/qml/plugin_loader.rb +46 -0
- data/lib/qml/plugins.rb +26 -0
- data/lib/qml/qml.rb +1 -0
- data/lib/qml/qt.rb +6 -0
- data/lib/qml/qt_classes.rb +9 -0
- data/lib/qml/qt_object_base.rb +108 -0
- data/lib/qml/reactive.rb +8 -0
- data/lib/qml/reactive/bindable.rb +79 -0
- data/lib/qml/reactive/chained_signal.rb +25 -0
- data/lib/qml/reactive/error.rb +5 -0
- data/lib/qml/reactive/object.rb +278 -0
- data/lib/qml/reactive/property.rb +19 -0
- data/lib/qml/reactive/signal.rb +116 -0
- data/lib/qml/reactive/signal_spy.rb +27 -0
- data/lib/qml/reactive/signals/map_signal.rb +21 -0
- data/lib/qml/reactive/signals/merge_signal.rb +21 -0
- data/lib/qml/reactive/signals/select_signal.rb +21 -0
- data/lib/qml/reactive/simple_property.rb +17 -0
- data/lib/qml/reactive/unbound_property.rb +42 -0
- data/lib/qml/reactive/unbound_signal.rb +51 -0
- data/lib/qml/root_path.rb +3 -0
- data/lib/qml/test_util.rb +1 -0
- data/lib/qml/test_util/object_life_checker.rb +17 -0
- data/lib/qml/version.rb +3 -0
- data/lib/qml/wrappable.rb +9 -0
- data/qml.gemspec +28 -0
- data/spec/assets/testobj.qml +5 -0
- data/spec/qml/.access_spec.rb.swp +0 -0
- data/spec/qml/access_spec.rb +162 -0
- data/spec/qml/application_spec.rb +43 -0
- data/spec/qml/component_spec.rb +44 -0
- data/spec/qml/context_spec.rb +43 -0
- data/spec/qml/conversion_spec.rb +59 -0
- data/spec/qml/data/array_model_spec.rb +215 -0
- data/spec/qml/dispatchable_spec.rb +26 -0
- data/spec/qml/dispatcher_spec.rb +48 -0
- data/spec/qml/geometry/point_spec.rb +4 -0
- data/spec/qml/geometry/rectangle_spec.rb +4 -0
- data/spec/qml/geometry/size_spec.rb +4 -0
- data/spec/qml/plugin_loader_spec.rb +33 -0
- data/spec/qml/qt_object_base_spec.rb +119 -0
- data/spec/qml/reactive/object_spec.rb +273 -0
- data/spec/qml/reactive/property_spec.rb +70 -0
- data/spec/qml/reactive/signal_spec.rb +191 -0
- data/spec/qml/reactive/signal_spy_spec.rb +26 -0
- data/spec/qml/test_object_spec.rb +186 -0
- data/spec/qml_spec.rb +7 -0
- data/spec/spec_helper.rb +5 -0
- 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
|
data/ext/qml/rubyclass.h
ADDED
|
@@ -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
|
+
|