scarpe-wasm 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +7 -0
  2. data/CODE_OF_CONDUCT.md +84 -0
  3. data/Gemfile +13 -0
  4. data/LICENSE.txt +21 -0
  5. data/README.md +39 -0
  6. data/Rakefile +12 -0
  7. data/lib/scarpe/wasm/alert.rb +65 -0
  8. data/lib/scarpe/wasm/app.rb +107 -0
  9. data/lib/scarpe/wasm/arc.rb +54 -0
  10. data/lib/scarpe/wasm/background.rb +27 -0
  11. data/lib/scarpe/wasm/border.rb +24 -0
  12. data/lib/scarpe/wasm/button.rb +50 -0
  13. data/lib/scarpe/wasm/check.rb +29 -0
  14. data/lib/scarpe/wasm/control_interface.rb +147 -0
  15. data/lib/scarpe/wasm/control_interface_test.rb +234 -0
  16. data/lib/scarpe/wasm/dimensions.rb +22 -0
  17. data/lib/scarpe/wasm/document_root.rb +8 -0
  18. data/lib/scarpe/wasm/edit_box.rb +44 -0
  19. data/lib/scarpe/wasm/edit_line.rb +43 -0
  20. data/lib/scarpe/wasm/flow.rb +24 -0
  21. data/lib/scarpe/wasm/font.rb +36 -0
  22. data/lib/scarpe/wasm/html.rb +108 -0
  23. data/lib/scarpe/wasm/image.rb +41 -0
  24. data/lib/scarpe/wasm/line.rb +35 -0
  25. data/lib/scarpe/wasm/link.rb +29 -0
  26. data/lib/scarpe/wasm/list_box.rb +50 -0
  27. data/lib/scarpe/wasm/para.rb +90 -0
  28. data/lib/scarpe/wasm/radio.rb +34 -0
  29. data/lib/scarpe/wasm/shape.rb +68 -0
  30. data/lib/scarpe/wasm/slot.rb +81 -0
  31. data/lib/scarpe/wasm/spacing.rb +41 -0
  32. data/lib/scarpe/wasm/span.rb +66 -0
  33. data/lib/scarpe/wasm/stack.rb +24 -0
  34. data/lib/scarpe/wasm/star.rb +61 -0
  35. data/lib/scarpe/wasm/subscription_item.rb +50 -0
  36. data/lib/scarpe/wasm/text_widget.rb +30 -0
  37. data/lib/scarpe/wasm/version.rb +7 -0
  38. data/lib/scarpe/wasm/video.rb +42 -0
  39. data/lib/scarpe/wasm/wasm_calls.rb +118 -0
  40. data/lib/scarpe/wasm/wasm_local_display.rb +94 -0
  41. data/lib/scarpe/wasm/web_wrangler.rb +679 -0
  42. data/lib/scarpe/wasm/webview_relay_display.rb +220 -0
  43. data/lib/scarpe/wasm/widget.rb +228 -0
  44. data/lib/scarpe/wasm/wv_display_worker.rb +75 -0
  45. data/lib/scarpe/wasm.rb +46 -0
  46. data/scarpe-wasm.gemspec +39 -0
  47. data/sig/scarpe/wasm.rbs +6 -0
  48. metadata +92 -0
@@ -0,0 +1,220 @@
1
+ # # frozen_string_literal: true
2
+
3
+ # require "socket"
4
+ # require "rbconfig"
5
+
6
+ # class Scarpe
7
+ # # An error occurred which would normally be handled by shutting down the app
8
+ # class AppShutdownError < Scarpe::Error; end
9
+
10
+ # # WVRelayUtil defines the datagram format for the sockets that connect a parent
11
+ # # Shoes application with a child display server.
12
+ # #
13
+ # # The class including this module should also include Shoes::Log so that it can
14
+ # # be used.
15
+ # module WVRelayUtil
16
+ # # Checks whether the internal socket is ready to be read from.
17
+ # # If timeout is greater than 0, this will block for up to that long.
18
+ # #
19
+ # # @param timeout [Float] the longest to wait for more input to read
20
+ # # @return [Boolean] whether the socket has data ready for reading
21
+ # def ready_to_read?(timeout = 0.0)
22
+ # r, _, e = IO.select [@from], [], [@from, @to].uniq, timeout
23
+
24
+ # # On timeout, select returns nil instead of arrays.
25
+ # return if r.nil?
26
+
27
+ # unless e.empty?
28
+ # raise "#{@i_am}: Got error on connection(s) from IO.select! Dying!"
29
+ # end
30
+
31
+ # !r.empty?
32
+ # end
33
+
34
+ # # Send bytes on the internal socket to the opposite side.
35
+ # #
36
+ # # @param contents [String] data to send
37
+ # # @return [void]
38
+ # def send_datagram(contents)
39
+ # str_data = JSON.dump contents
40
+ # dgram_str = (str_data.length.to_s + "a" + str_data).encode(Encoding::BINARY)
41
+ # to_write = dgram_str.bytesize
42
+ # written = 0
43
+
44
+ # until written == to_write
45
+ # count = @to.write(dgram_str.byteslice(written..-1))
46
+ # if count.nil? || count == 0
47
+ # raise "Something was wrong in send_datagram! Write returned #{count.inspect}!"
48
+ # end
49
+
50
+ # written += count
51
+ # end
52
+
53
+ # nil
54
+ # end
55
+
56
+ # # Read data from the internal socket. Read until a whole datagram
57
+ # # has been received and then return it.
58
+ # #
59
+ # # @return [String] the received datagram
60
+ # def receive_datagram
61
+ # @readbuf ||= String.new.encode(Encoding::BINARY)
62
+ # to_read = nil
63
+
64
+ # loop do
65
+ # # Have we read a packet length already, sitting in @readbuf?
66
+ # a_idx = @readbuf.index("a")
67
+ # if a_idx
68
+ # to_read = @readbuf[0..a_idx].to_i
69
+ # @readbuf = @readbuf[(a_idx + 1)..-1]
70
+ # break
71
+ # end
72
+
73
+ # # If not, read more bytes
74
+ # new_bytes = @from.read(10)
75
+ # if new_bytes.nil?
76
+ # # This is perfectly normal, if the connection closed
77
+ # raise AppShutdownError, "Got an unexpected EOF reading datagram! " +
78
+ # "Did the #{@i_am == :child ? "parent" : "child"} process die?"
79
+ # end
80
+ # @readbuf << new_bytes
81
+ # end
82
+
83
+ # loop do
84
+ # if @readbuf.bytesize >= to_read
85
+ # out = @readbuf.byteslice(0, to_read)
86
+ # @readbuf = @readbuf.byteslice(to_read, -1)
87
+ # return out
88
+ # end
89
+
90
+ # new_bytes = @from.read(to_read - @readbuf.bytesize)
91
+ # @readbuf << new_bytes
92
+ # end
93
+ # rescue
94
+ # raise AppShutdownError, "Got exception #{$!.class} when receiving datagram... #{$!.inspect}"
95
+ # end
96
+
97
+ # # Read a datagram from the internal buffer and then dispatch it to the
98
+ # # appropriate handler.
99
+ # def respond_to_datagram
100
+ # message = receive_datagram
101
+ # m_data = JSON.parse(message)
102
+
103
+ # if m_data["type"] == "event"
104
+ # kwargs_hash = {}
105
+ # m_data["kwargs"].each { |k, v| kwargs_hash[k.to_sym] = v }
106
+ # send_shoes_event(
107
+ # *m_data["args"],
108
+ # event_name: m_data["kwargs"]["event_name"],
109
+ # target: m_data["kwargs"]["event_target"],
110
+ # **kwargs_hash,
111
+ # )
112
+ # elsif m_data["type"] == "create"
113
+ # raise "Parent process should never receive :create datagram!" if @i_am == :parent
114
+
115
+ # @wv_display.create_display_widget_for(m_data["class_name"], m_data["id"], m_data["properties"])
116
+ # elsif m_data["type"] == "destroy"
117
+ # if @i_am == :parent
118
+ # @shutdown = true
119
+ # else
120
+ # @log.info("Shutting down...")
121
+ # exit 0
122
+ # end
123
+ # else
124
+ # @log.error("Unrecognized datagram type:event: #{m_data.inspect}!")
125
+ # end
126
+ # end
127
+
128
+ # # Loop for up to `t` seconds, reading data and waiting.
129
+ # #
130
+ # # @param t [Float] the number of seconds to loop for
131
+ # def event_loop_for(t = 1.5)
132
+ # t_start = Time.now
133
+ # delay_time = t
134
+
135
+ # while Time.now - t_start < delay_time
136
+ # if ready_to_read?(0.1)
137
+ # respond_to_datagram
138
+ # else
139
+ # sleep 0.1
140
+ # end
141
+ # end
142
+ # end
143
+ # end
144
+
145
+ # # This display service creates a child process and sends events
146
+ # # back and forth, but creates no widgets of its own. The child
147
+ # # process will spawn a worker with its own WebviewDisplayService
148
+ # # where the real Webview exists. By splitting the Webview
149
+ # # process from the Shoes widgets, it can be easier to return
150
+ # # control to Webview's event handler promptly. Also, the Ruby
151
+ # # process could run background threads if it wanted, and
152
+ # # otherwise behave like a process ***not*** containing Webview.
153
+ # class WVRelayDisplayService < Shoes::DisplayService
154
+ # include Shoes::Log
155
+ # include WVRelayUtil # Needs Shoes::Log
156
+
157
+ # attr_accessor :shutdown
158
+
159
+ # # Create a Webview Relay Display Service
160
+ # def initialize
161
+ # super()
162
+ # log_init("WV::RelayDisplayService")
163
+
164
+ # @event_subs = []
165
+ # @shutdown = false
166
+ # @i_am = :parent
167
+
168
+ # server = TCPServer.new("127.0.0.1", 0)
169
+ # port = server.addr[1]
170
+
171
+ # @pid = spawn(RbConfig.ruby, File.join(__dir__, "wv_display_worker.rb"), port.to_s)
172
+ # @from = @to = server.accept
173
+
174
+ # # Subscribe to all event notifications and relay them to the worker
175
+ # @event_subs << bind_shoes_event(event_name: :any, target: :any) do |*args, **kwargs|
176
+ # unless kwargs[:relayed]
177
+ # kwargs[:relayed] = true
178
+ # send_datagram({ type: :event, args:, kwargs: })
179
+ # end
180
+
181
+ # # Forward the run event to the child process before doing this
182
+ # if event_name == "run"
183
+ # run_event_loop
184
+ # end
185
+ # rescue AppShutdownError
186
+ # @shutdown = true
187
+ # @log.info("Attempting to shut down...")
188
+ # self.destroy
189
+ # end
190
+ # end
191
+
192
+ # # Run, sending and responding to datagrams continuously.
193
+ # def run_event_loop
194
+ # until @shutdown
195
+ # respond_to_datagram while ready_to_read?
196
+ # sleep 0.1
197
+ # end
198
+ # rescue AppShutdownError
199
+ # @shutdown = true
200
+ # @log.info("Attempting to shut down...")
201
+ # self.destroy
202
+ # end
203
+
204
+ # # This method sends a message to the worker process to create a widget. No actual
205
+ # # widget is created or registered with the display service.
206
+ # def create_display_widget_for(widget_class_name, widget_id, properties)
207
+ # send_datagram({ type: :create, class_name: widget_class_name, id: widget_id, properties: })
208
+ # # Don't need to return anything. It wouldn't be used anyway.
209
+ # end
210
+
211
+ # # Tell the worker process to quit, and set a flag telling the event loop to shut down.
212
+ # def destroy
213
+ # unless @shutdown
214
+ # send_datagram({ type: :destroy })
215
+ # end
216
+ # @shutdown = true
217
+ # (@events_subs || []).each { |unsub_id| DisplayService.unsub_from_events(unsub_id) }
218
+ # end
219
+ # end
220
+ # end
@@ -0,0 +1,228 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Scarpe
4
+ # The WASMWidget parent class helps connect a WASM widget with
5
+ # its Shoes equivalent, render itself to the WASM DOM, handle
6
+ # Javascript events and generally keep things working in WASM.
7
+ class WASMWidget < Shoes::Linkable
8
+ include Shoes::Log
9
+
10
+ class << self
11
+ # Return the corresponding WASM class for a particular Shoes class name
12
+ def display_class_for(scarpe_class_name)
13
+ scarpe_class = Shoes.const_get(scarpe_class_name)
14
+ unless scarpe_class.ancestors.include?(Shoes::Linkable)
15
+ raise "Scarpe WASM can only get display classes for Shoes " +
16
+ "linkable widgets, not #{scarpe_class_name.inspect}!"
17
+ end
18
+
19
+ klass = Scarpe.const_get("WASM" + scarpe_class_name.split("::")[-1])
20
+ if klass.nil?
21
+ raise "Couldn't find corresponding Scarpe WASM class for #{scarpe_class_name.inspect}!"
22
+ end
23
+
24
+ klass
25
+ end
26
+ end
27
+
28
+ # The Shoes ID corresponding to the Shoes widget for this WASM widget
29
+ attr_reader :shoes_linkable_id
30
+
31
+ # The WASMWidget parent of this widget
32
+ attr_reader :parent
33
+
34
+ # An array of WASMWidget children (possibly empty) of this widget
35
+ attr_reader :children
36
+
37
+ # Set instance variables for the display properties of this widget. Bind Shoes
38
+ # events for changes of parent widget and changes of property values.
39
+ def initialize(properties)
40
+ log_init("WASM::Widget")
41
+
42
+ # Call method, which looks up the parent
43
+ @shoes_linkable_id = properties["shoes_linkable_id"] || properties[:shoes_linkable_id]
44
+ unless @shoes_linkable_id
45
+ raise "Could not find property shoes_linkable_id in #{properties.inspect}!"
46
+ end
47
+
48
+ # Set the display properties
49
+ properties.each do |k, v|
50
+ next if k == "shoes_linkable_id"
51
+
52
+ instance_variable_set("@" + k.to_s, v)
53
+ end
54
+
55
+ # The parent field is *almost* simple enough that a typed display property would handle it.
56
+ bind_shoes_event(event_name: "parent", target: shoes_linkable_id) do |new_parent_id|
57
+ display_parent = WASMDisplayService.instance.query_display_widget_for(new_parent_id)
58
+ if @parent != display_parent
59
+ set_parent(display_parent)
60
+ end
61
+ end
62
+
63
+ # When Shoes widgets change properties, we get a change notification here
64
+ bind_shoes_event(event_name: "prop_change", target: shoes_linkable_id) do |prop_changes|
65
+ prop_changes.each do |k, v|
66
+ instance_variable_set("@" + k, v)
67
+ end
68
+ properties_changed(prop_changes)
69
+ end
70
+
71
+ bind_shoes_event(event_name: "destroy", target: shoes_linkable_id) do
72
+ destroy_self
73
+ end
74
+
75
+ super(linkable_id: @shoes_linkable_id)
76
+ end
77
+
78
+ # Properties_changed will be called automatically when properties change.
79
+ # The widget should delete any changes from the Hash that it knows how
80
+ # to incrementally handle, and pass the rest to super. If any changes
81
+ # go entirely un-handled, a full redraw will be scheduled.
82
+ # This exists to be overridden by children watching for changes.
83
+ #
84
+ # @param changes [Hash] a Hash of new values for properties that have changed
85
+ def properties_changed(changes)
86
+ needs_update! unless changes.empty?
87
+ end
88
+
89
+ # Give this widget a new parent, including managing the appropriate child lists for parent widgets.
90
+ def set_parent(new_parent)
91
+ @parent&.remove_child(self)
92
+ new_parent&.add_child(self)
93
+ @parent = new_parent
94
+ end
95
+
96
+ # A shorter inspect text for prettier irb output
97
+ def inspect
98
+ "#<#{self.class}:#{self.object_id} @shoes_linkable_id=#{@shoes_linkable_id} @parent=#{@parent.inspect} @children=#{@children.inspect}>"
99
+ end
100
+
101
+ protected
102
+
103
+ # Do not call directly, use set_parent
104
+ def remove_child(child)
105
+ @children ||= []
106
+ unless @children.include?(child)
107
+ @log.error("remove_child: no such child(#{child.inspect}) for"\
108
+ " parent(#{parent.inspect})!")
109
+ end
110
+ @children.delete(child)
111
+ end
112
+
113
+ # Do not call directly, use set_parent
114
+ def add_child(child)
115
+ @children ||= []
116
+ @children << child
117
+
118
+ # If we add a child, we should redraw ourselves
119
+ needs_update!
120
+ end
121
+
122
+ # Convert an [r, g, b, a] array to an HTML hex color code
123
+ # Arrays support alpha. HTML hex does not. So premultiply.
124
+ def rgb_to_hex(color)
125
+ return color if color.nil?
126
+
127
+ r, g, b, a = *color
128
+ if r.is_a?(Float)
129
+ a ||= 1.0
130
+ r_float = r * a
131
+ g_float = g * a
132
+ b_float = b * a
133
+ else
134
+ a ||= 255
135
+ a_float = (a / 255.0)
136
+ r_float = (r.to_f / 255.0) * a_float
137
+ g_float = (g.to_f / 255.0) * a_float
138
+ b_float = (b.to_f / 255.0) * a_float
139
+ end
140
+
141
+ r_int = (r_float * 255.0).to_i.clamp(0, 255)
142
+ g_int = (g_float * 255.0).to_i.clamp(0, 255)
143
+ b_int = (b_float * 255.0).to_i.clamp(0, 255)
144
+
145
+ "#%0.2X%0.2X%0.2X" % [r_int, g_int, b_int]
146
+ end
147
+
148
+ public
149
+
150
+ # This gets a mini-WASM for just this element and its children, if any.
151
+ # It is normally called by the widget itself to do its DOM management.
152
+ #
153
+ # @return [Scarpe::WebWrangler::ElementWrangler] a DOM object manager
154
+ def html_element
155
+ @elt_wrangler ||= Scarpe::WebWrangler::ElementWrangler.new(html_id)
156
+ end
157
+
158
+ # Return a promise that guarantees all currently-requested changes have completed
159
+ #
160
+ # @return [Scarpe::Promise] a promise that will be fulfilled when all pending changes have finished
161
+ def promise_update
162
+ html_element.promise_update
163
+ end
164
+
165
+ # Get the object's HTML ID
166
+ #
167
+ # @return [String] the HTML ID
168
+ def html_id
169
+ object_id.to_s
170
+ end
171
+
172
+ # to_html is intended to get the HTML DOM rendering of this object and its children.
173
+ # Calling it should be side-effect-free and NOT update the WASM.
174
+ #
175
+ # @return [String] the rendered HTML
176
+ def to_html
177
+ @children ||= []
178
+ child_markup = @children.map(&:to_html).join
179
+ if respond_to?(:element)
180
+ element { child_markup }
181
+ else
182
+ child_markup
183
+ end
184
+ end
185
+
186
+ # This binds a Scarpe JS callback, handled via a single dispatch point in the app
187
+ #
188
+ # @param event [String] the Scarpe widget event name
189
+ # @yield the block to call when the event occurs
190
+ def bind(event, &block)
191
+ raise("Widget has no linkable_id! #{inspect}") unless linkable_id
192
+
193
+ WASMDisplayService.instance.app.bind("#{linkable_id}-#{event}", &block)
194
+ end
195
+
196
+ # Removes the element from both the Ruby Widget tree and the HTML DOM.
197
+ # Return a promise for when that HTML change will be visible.
198
+ #
199
+ # @return [Scarpe::Promise] a promise that is fulfilled when the HTML change is complete
200
+ def destroy_self
201
+ @parent&.remove_child(self)
202
+ html_element.remove
203
+ end
204
+
205
+ # Request a full redraw of all widgets.
206
+ #
207
+ # It's really hard to do dirty-tracking here because the redraws are fully asynchronous.
208
+ # And so we can't easily cancel one "in flight," and we can't easily pick up the latest
209
+ # changes... And we probably don't want to, because we may be halfway through a batch.
210
+ #
211
+ # @return [void]
212
+ def needs_update!
213
+ WASMDisplayService.instance.app.request_redraw!
214
+ end
215
+
216
+ # Generate JS code to trigger a specific event name on this widget with the supplies arguments.
217
+ #
218
+ # @param handler_function_name [String] the event name - @see #bind
219
+ # @param args [Array] additional arguments that will be passed to the event in the generated JS
220
+ # @return [String] the generated JS code
221
+ def handler_js_code(handler_function_name, *args)
222
+ raise("Widget has no linkable_id! #{inspect}") unless linkable_id
223
+
224
+ js_args = ["'#{linkable_id}-#{handler_function_name}'", *args].join(", ")
225
+ "scarpeHandler(#{js_args})"
226
+ end
227
+ end
228
+ end
@@ -0,0 +1,75 @@
1
+ # #!/usr/bin/env ruby
2
+ # # frozen_string_literal: true
3
+
4
+ # require "socket"
5
+
6
+ # # Wherever this file is installed, locate Scarpe relative to it. This could be an installed gem or a dev repo.
7
+ # SCARPE_DIR = File.join(__dir__, "../..")
8
+
9
+ # $LOAD_PATH.prepend(SCARPE_DIR)
10
+ # require "scarpe"
11
+ # require "scarpe/wv_local"
12
+
13
+ # # This script exists to create a WebviewDisplayService that can be operated remotely over a socket.
14
+
15
+ # if ARGV.length != 1
16
+ # $stderr.puts("Usage: wv_display_worker.rb tcp_port_num")
17
+ # exit(-1)
18
+ # end
19
+
20
+ # # This is the implementation of a freestanding Scarpe Webview display server,
21
+ # # which connects via sockets and sends events and properties back and forth
22
+ # # with a display-less Shoes app. The interface is designed to allow fork-based
23
+ # # usage, where a parent process could create a paired sockets and start the
24
+ # # child server. It can also be used via TCP sockets or similar, where a single
25
+ # # socket is both input and output.
26
+ # class WebviewContainedService < Shoes::Linkable
27
+ # include Shoes::Log
28
+ # include Scarpe::WVRelayUtil # Needs Shoes::Log
29
+
30
+ # attr_reader :log
31
+
32
+ # # Create a new DisplayService.
33
+ # #
34
+ # # @param from [Socket] a readable socket to get input from the Shoes process
35
+ # # @param to [Socket] a writable socket on which to send output to the Shoes process
36
+ # def initialize(from, to)
37
+ # super()
38
+ # log_init("WV::DisplayWorker")
39
+
40
+ # @i_am = :child
41
+ # @event_subs = []
42
+ # @wv_display = Scarpe::WebviewDisplayService.new
43
+
44
+ # @from = from
45
+ # @to = to
46
+
47
+ # @init_done = false
48
+
49
+ # # Wait to register our periodic_code until the wrangler exists
50
+ # @event_subs << bind_shoes_event(event_name: "init") do
51
+ # @wv_display.wrangler.periodic_code("datagramProcessor", 0.1) do
52
+ # respond_to_datagram while ready_to_read?(0.0)
53
+ # end
54
+ # @init_done = true
55
+ # end
56
+
57
+ # # Subscribe to all event notifications and relay them to the opposite side
58
+ # @event_subs << bind_shoes_event(event_name: :any, target: :any) do |*args, **kwargs|
59
+ # unless kwargs[:relayed] || kwargs["relayed"]
60
+ # kwargs[:relayed] = true
61
+ # send_datagram({ type: :event, args:, kwargs: })
62
+ # end
63
+ # end
64
+
65
+ # # Run for 2.5 seconds to let the app be created and "run" to get called.
66
+ # # Once that happens, Webview will take over the event loop.
67
+ # event_loop_for(2.5)
68
+ # end
69
+ # end
70
+
71
+ # s = TCPSocket.new("localhost", ARGV[0].to_i)
72
+
73
+ # SERVICE = WebviewContainedService.new(s, s)
74
+
75
+ # SERVICE.log.info("Finished event loop. Exiting!")
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Scarpe WASM Display Services
4
+
5
+ require_relative "wasm/wasm_version"
6
+
7
+ require_relative "wasm/wasm_calls"
8
+ require_relative "wasm/web_wrangler"
9
+ require_relative "wasm/control_interface"
10
+
11
+ require_relative "wasm/widget"
12
+ require_relative "wasm/wasm_local_display"
13
+
14
+ require_relative "wasm/dimensions"
15
+ require_relative "wasm/html"
16
+
17
+ require_relative "wasm/spacing"
18
+ require_relative "wasm/star"
19
+ require_relative "wasm/radio"
20
+ require_relative "wasm/background"
21
+ require_relative "wasm/border"
22
+
23
+ require_relative "wasm/arc"
24
+ require_relative "wasm/font"
25
+
26
+ require_relative "wasm/app"
27
+ require_relative "wasm/para"
28
+ require_relative "wasm/slot"
29
+ require_relative "wasm/stack"
30
+ require_relative "wasm/flow"
31
+ require_relative "wasm/document_root"
32
+ require_relative "wasm/subscription_item"
33
+ require_relative "wasm/button"
34
+ require_relative "wasm/image"
35
+ require_relative "wasm/edit_box"
36
+ require_relative "wasm/edit_line"
37
+ require_relative "wasm/list_box"
38
+ require_relative "wasm/alert"
39
+ require_relative "wasm/span"
40
+ require_relative "wasm/shape"
41
+
42
+ require_relative "wasm/text_widget"
43
+ require_relative "wasm/link"
44
+ require_relative "wasm/line"
45
+ require_relative "wasm/video"
46
+ require_relative "wasm/check"
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/scarpe/wasm/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "scarpe-wasm"
7
+ spec.version = Scarpe::Wasm::VERSION
8
+ spec.authors = ["Giovanni Borgh", "Noah Gibbs", "Scarpe Team"]
9
+ spec.email = ["the.codefolio.guy@gmail.com"]
10
+
11
+ spec.summary = "A WASM display library for Scarpe."
12
+ #spec.description = "TODO: Write a longer description or delete this line."
13
+ spec.homepage = "https://github.com/scarpe-team/scarpe-wasm"
14
+ spec.license = "MIT"
15
+ spec.required_ruby_version = ">= 3.2.0"
16
+
17
+ #spec.metadata["allowed_push_host"] = "TODO: Set to your gem server 'https://example.com'"
18
+
19
+ spec.metadata["homepage_uri"] = spec.homepage
20
+ #spec.metadata["source_code_uri"] = "TODO: Put your gem's public repo URL here."
21
+ #spec.metadata["changelog_uri"] = "TODO: Put your gem's CHANGELOG.md URL here."
22
+
23
+ # Specify which files should be added to the gem when it is released.
24
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
25
+ spec.files = Dir.chdir(__dir__) do
26
+ `git ls-files -z`.split("\x0").reject do |f|
27
+ (File.expand_path(f) == __FILE__) || f.start_with?(*%w[bin/ test/ spec/ features/ .git .circleci appveyor])
28
+ end
29
+ end
30
+ spec.bindir = "exe"
31
+ spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
32
+ spec.require_paths = ["lib"]
33
+
34
+ # Uncomment to register a new dependency of your gem
35
+ # spec.add_dependency "example-gem", "~> 1.0"
36
+
37
+ # For more information and examples about making a new gem, check out our
38
+ # guide at: https://bundler.io/guides/creating_gem.html
39
+ end
@@ -0,0 +1,6 @@
1
+ module Scarpe
2
+ module Wasm
3
+ VERSION: String
4
+ # See the writing guide of rbs: https://github.com/ruby/rbs#guides
5
+ end
6
+ end