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,34 @@
1
+ module QML
2
+
3
+ # {Dispatchable} provides a handy way for asynchronous (queued) method calls
4
+ # which actually processed later in the event loop.
5
+ # @see QML.later
6
+ module Dispatchable
7
+
8
+ class Proxy < BasicObject
9
+ def initialize(obj)
10
+ @obj = obj
11
+ end
12
+
13
+ # Actually enqueues the method call using {QML.later}.
14
+ def method_missing(name, *args, &block)
15
+ ::QML.later do
16
+ @obj.__send__(name, *args, &block)
17
+ end
18
+ end
19
+ end
20
+
21
+ # Returns a proxy object for calling a method asynchronously within the event loop.
22
+ # @return [Proxy]
23
+ # @example
24
+ # def on_button_clicked
25
+ # Thread.new do
26
+ # result = do_task
27
+ # later.set_result_to_ui(result)
28
+ # end
29
+ # end
30
+ def later
31
+ Proxy.new(self)
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,61 @@
1
+ require 'singleton'
2
+ require 'monitor'
3
+
4
+ module QML
5
+
6
+ class Dispatcher
7
+ include Singleton
8
+ include MonitorMixin
9
+
10
+ MAX_DURATION = 1/10.to_r
11
+
12
+ def initialize
13
+ @tasks = []
14
+ super
15
+ end
16
+
17
+ def add_task(&task)
18
+ synchronize do
19
+ @tasks << task
20
+ end
21
+ end
22
+
23
+ def empty?
24
+ synchronize do
25
+ @tasks.empty?
26
+ end
27
+ end
28
+
29
+ def run_tasks
30
+ synchronize do
31
+ start_time = Time.now
32
+ loop do
33
+ break if @tasks.empty?
34
+ break if start_time.to_r - Time.now.to_r > MAX_DURATION
35
+ task = @tasks.shift
36
+ task.call
37
+ end
38
+ end
39
+ end
40
+ end
41
+
42
+ # Runs a block asynchronously within the event loop.
43
+ #
44
+ # QML UI is not thread-safe and can only be accessed from the main thread.
45
+ # Use this method to set results of asynchronous tasks to UI.
46
+ # @example
47
+ # def on_button_clicked
48
+ # Thread.new do
49
+ # result = do_task
50
+ # QML.later do
51
+ # set_result_to_ui(result)
52
+ # end
53
+ # end
54
+ # end
55
+ # @see Dispatchable#later
56
+ # @see Dispatcher#add_task
57
+ def later(&block)
58
+ Dispatcher.instance.add_task(&block)
59
+ end
60
+ module_function :later
61
+ end
@@ -0,0 +1,54 @@
1
+ require 'qml/qt_classes'
2
+
3
+ module QML
4
+ # @!parse class Engine < QtObjectBase; end
5
+
6
+ # {Engine} provides a QML engine.
7
+ #
8
+ # @see http://qt-project.org/doc/qt-5/qqmlengine.html QQmlEngine (C++)
9
+ class Engine
10
+
11
+ # @return [Engine] the instance of {Engine}.
12
+ # @see QML.engine
13
+ def self.instance
14
+ Kernel.engine
15
+ end
16
+
17
+ # @note This method cannot be called because {Engine} is singleton.
18
+ def self.new
19
+ fail EngineError, "cannot create Engine instance manually"
20
+ end
21
+
22
+ def initialize
23
+ super()
24
+ @extension = Plugins.core.createEngineExtension(self)
25
+ end
26
+
27
+ # @return [Context] the root {Context} the {Engine}.
28
+ def context
29
+ @extension.rootContext
30
+ end
31
+
32
+ # Starts garbage collection on the {Engine}.
33
+ def collect_garbage
34
+ @extension.collect_garbage
35
+ end
36
+
37
+ # Adds an {ImageProvider} to the {Engine}.
38
+ # @param id [String]
39
+ # @param provider [ImageProvider]
40
+ # @return [ImageProvider]
41
+ # @see ImageProvider
42
+ def add_image_provider(id, provider)
43
+ @extension.add_image_provider(id, provider.qt_image_provider)
44
+ provider
45
+ end
46
+ end
47
+
48
+ # @return [Engine] the instance of {Engine}.
49
+ # @see Engine.instance
50
+ def engine
51
+ Kernel.engine
52
+ end
53
+ module_function :engine
54
+ end
@@ -0,0 +1,15 @@
1
+ module QML
2
+ module ErrorConverter
3
+
4
+ class << self
5
+ attr_reader :patterns
6
+
7
+ def add_pattern(cpp_classname, ruby_class)
8
+ @patterns ||= {}
9
+ @patterns[cpp_classname] = ruby_class
10
+ end
11
+ end
12
+
13
+ add_pattern 'RubyQml::QmlException', QMLError
14
+ end
15
+ end
@@ -0,0 +1,26 @@
1
+ module QML
2
+
3
+ class MethodError < StandardError; end
4
+ class SignalError < StandardError; end
5
+ class PropertyError < StandardError; end
6
+ class PluginError < StandardError; end
7
+ class QtObjectError < StandardError; end
8
+ class ConversionError < StandardError; end
9
+ class QMLError < StandardError; end
10
+ class AccessError < StandardError; end
11
+ class ApplicationError < StandardError; end
12
+ class EngineError < StandardError; end
13
+ class InvalidThreadError < StandardError; end
14
+ class UninitializedError < StandardError; end
15
+ class AlreadyInitializedError < StandardError; end
16
+
17
+ class CppError < StandardError
18
+ attr_reader :class_name, :raw_message
19
+
20
+ def initialize(classname, message)
21
+ super("<#{classname}> #{message}")
22
+ @class_name = classname
23
+ @raw_message = message
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,3 @@
1
+ require 'qml/geometry/point'
2
+ require 'qml/geometry/size'
3
+ require 'qml/geometry/rectangle'
@@ -0,0 +1,5 @@
1
+ module QML
2
+ module Geometry
3
+ class Point < Struct.new(:x, :y); end
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ module QML
2
+ module Geometry
3
+ class Rectangle < Struct.new(:x, :y, :width, :height); end
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ module QML
2
+ module Geometry
3
+ class Size < Struct.new(:width, :height); end
4
+ end
5
+ end
@@ -0,0 +1,87 @@
1
+ require 'qml/access'
2
+
3
+ module QML
4
+
5
+ # {ImageProvider} is used to provide images manually to QML.
6
+ #
7
+ # QML requests images to ImageProviders when you use "image:" URL scheme
8
+ # (like "image://my_image_provider/foo.png") in source specification of Image elements.
9
+ #
10
+ # @example
11
+ # class MyImageProvider < QML::ImageProvider
12
+ # def request(req)
13
+ # Thread.new do
14
+ # image_data = load_image_data()
15
+ # req.finish(image_data)
16
+ # end
17
+ # end
18
+ # end
19
+ # QML.engine.add_image_provider(MyImageProvider.new)
20
+ #
21
+ # @see Engine#add_image_provider
22
+ # @see http://qt-project.org/doc/qt-5/qquickimageprovider.html QQuickImageProvider (C++)
23
+ # @see http://qt-project.org/doc/qt-5/qml-qtquick-image.html Image (QML)
24
+
25
+ class ImageProvider
26
+
27
+ # {Request} represents a image request from QML.
28
+ # @see ImageProvider#request
29
+ class Request
30
+ # The image ID.
31
+ # If you requested "image://my_image_provider/foo/bar.png", the ID would be "foo/bar.png".
32
+ attr_reader :id
33
+
34
+ # Finishes the image request.
35
+ # @param data [String] The image file data
36
+ def finish(data)
37
+ fail ::TypeError, "data must be a String" unless data.is_a? ::String
38
+ QML.later do
39
+ @promise.set_data(data)
40
+ end
41
+ end
42
+
43
+ private
44
+
45
+ def initialize(id, promise)
46
+ @id = id;
47
+ @promise = promise
48
+ end
49
+ end
50
+
51
+ attr_reader :qt_image_provider
52
+
53
+ def initialize
54
+ @callback = Callback.new(self)
55
+ @qt_image_provider = Plugins.core.createImageProvider(@callback)
56
+ @qt_image_provider.prefer_managed false
57
+ end
58
+
59
+ # @abstract
60
+ # @param req [Request]
61
+ #
62
+ # Implement this method to handle image requests from QML.
63
+ #
64
+ # Call {Request#finish} to finish image loading.
65
+ # Image loading should be done asynchnorously because this method is called within the event loop.
66
+
67
+ def request(req)
68
+ fail ::NotImplementedError
69
+ end
70
+
71
+ private
72
+
73
+ class Callback
74
+ include QML::Access
75
+
76
+ def initialize(provider)
77
+ super()
78
+ @provider = provider
79
+ end
80
+
81
+ def request(id, promise)
82
+ promise.prefer_managed true
83
+ @provider.request(Request.new(id, promise))
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,20 @@
1
+ require 'qml/qml'
2
+ require 'qml/class_builder'
3
+
4
+ module QML
5
+ class MetaObject
6
+ alias_method :to_s, :name
7
+
8
+ def inspect
9
+ "<QML::MetaObject:#{self}>"
10
+ end
11
+
12
+ def build_class
13
+ @@classes ||= {}
14
+ klass = @@classes[name]
15
+ builder = ClassBuilder.new(self, klass)
16
+ builder.build
17
+ @@classes[name] = builder.klass
18
+ end
19
+ end
20
+ end
@@ -0,0 +1 @@
1
+ require 'qml/models/array_model'
@@ -0,0 +1,12 @@
1
+ module QML
2
+ module NameHelper
3
+ module_function
4
+
5
+ def to_underscore(sym)
6
+ sym.to_s.gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').gsub(/([a-z\d])([A-Z])/,'\1_\2').downcase.to_sym
7
+ end
8
+ def to_upper_underscore(sym)
9
+ to_underscore(sym).upcase
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,15 @@
1
+ module QML
2
+
3
+ module Platform
4
+ module_function
5
+
6
+ def windows?
7
+ !!(/cygwin|mswin|mingw|bccwin|wince|emx/ =~ RUBY_PLATFORM)
8
+ end
9
+
10
+ def mac?
11
+ !!(/darwin/ =~ RUBY_PLATFORM)
12
+ end
13
+ end
14
+
15
+ end
@@ -0,0 +1,46 @@
1
+ require 'pathname'
2
+ require 'qml/platform'
3
+
4
+ module QML
5
+ # {PluginLoader} loads Qt C++ plugins and enables you to use your Qt C++ codes from Ruby easily.
6
+ # @see http://qt-project.org/doc/qt-5/qpluginloader.html QPluginLoader (C++)
7
+ class PluginLoader
8
+
9
+ alias_method :initialize_orig, :initialize
10
+ private :initialize_orig
11
+
12
+ # @overload initialize(path)
13
+ # @param [String|Pathname] path the library path (may be platform-dependent).
14
+ # @example
15
+ # loader = QML::PluginLoader.new('path/to/libhoge.dylib')
16
+ # @overload initialize(dir, libname)
17
+ # @param [String|Pathname] dir the library directory.
18
+ # @param [String] libname the platform-independent library name.
19
+ # @example
20
+ # loader = QML::PluginLoader.new('path/to', 'hoge')
21
+ def initialize(path, libname = nil)
22
+ path = Pathname(path) + self.class.lib_filename(libname) if libname
23
+ initialize_orig(path.to_s)
24
+ end
25
+
26
+ # @!method instance
27
+ # Loads the plugin and returns the instance of the plugin.
28
+ # @return [QtObjectBase]
29
+
30
+ # @param [String] libname
31
+ # @return [String] platform-dependent library file name.
32
+ # @example
33
+ # # on Mac
34
+ # QML::PluginLoader.lib_filename("hoge") #=> "libhoge.dylib"
35
+ def self.lib_filename(libname)
36
+ case
37
+ when Platform::windows?
38
+ "#{libname}.dll"
39
+ when Platform::mac?
40
+ "lib#{libname}.dylib"
41
+ else
42
+ "lib#{libname}.so"
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,26 @@
1
+ require 'qml/plugin_loader'
2
+ require 'qml/root_path'
3
+ require 'pathname'
4
+
5
+ module QML
6
+ module Plugins
7
+
8
+ PATH = ROOT_PATH + 'ext/qml/plugins'
9
+
10
+ class << self
11
+ def core
12
+ @core ||= load('core')
13
+ end
14
+
15
+ def test_util
16
+ @test_util ||= load('testutil')
17
+ end
18
+
19
+ private
20
+
21
+ def load(name)
22
+ QML::PluginLoader.new(PATH + name, "rubyqml-#{name}").instance
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1 @@
1
+ require_relative '../../ext/qml/qml'
@@ -0,0 +1,6 @@
1
+ require 'qml/qt_classes'
2
+
3
+ module QML
4
+ # @!parse class Qt < QtObjectBase; end
5
+ class Qt; end
6
+ end