scarpe 0.2.2 → 0.3.0

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.
Files changed (223) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +1 -0
  3. data/CHANGELOG.md +16 -2
  4. data/Gemfile.lock +7 -3
  5. data/README.md +24 -8
  6. data/Rakefile +1 -1
  7. data/examples/animate.rb +20 -0
  8. data/examples/arrow.rb +10 -0
  9. data/examples/btn_tooltip.rb +7 -0
  10. data/examples/button_style_changed.rb +7 -0
  11. data/examples/button_styles_default.rb +6 -0
  12. data/examples/gen.rb +8 -8
  13. data/examples/highlander.rb +3 -3
  14. data/examples/legacy/README.md +6 -0
  15. data/examples/legacy/not_checked/shoes-contrib/basic/shoes-notes.rb +1 -1
  16. data/examples/legacy/not_checked/simple/anim-shapes.rb +1 -1
  17. data/examples/legacy/not_checked/speedometer_app.rb +55 -0
  18. data/examples/legacy/working/simple/image-icon.rb +3 -0
  19. data/examples/legacy/{not_checked → working}/simple/image.rb +1 -1
  20. data/examples/list_box_choose.rb +17 -0
  21. data/examples/local_assets/local_file_server.rb +82 -0
  22. data/examples/local_assets/sample.gif +0 -0
  23. data/examples/local_assets/sample.mp4 +0 -0
  24. data/examples/local_fonts.rb +2 -2
  25. data/examples/local_images.rb +2 -3
  26. data/examples/para/para_text.rb +14 -0
  27. data/examples/progress.rb +31 -0
  28. data/examples/radio/radio_groups.rb +2 -2
  29. data/examples/rect.rb +4 -0
  30. data/examples/rotate_shapes.rb +17 -0
  31. data/examples/simpler-menu.rb +21 -0
  32. data/exe/scarpe +2 -1
  33. data/lacci/Gemfile +2 -0
  34. data/lacci/Gemfile.lock +8 -1
  35. data/lacci/lacci.gemspec +1 -1
  36. data/lacci/lib/lacci/scarpe_cli.rb +2 -1
  37. data/lacci/lib/lacci/scarpe_core.rb +2 -1
  38. data/lacci/lib/lacci/version.rb +1 -1
  39. data/lacci/lib/scarpe/niente/app.rb +23 -0
  40. data/lacci/lib/scarpe/niente/display_service.rb +62 -0
  41. data/lacci/lib/scarpe/niente/drawable.rb +57 -0
  42. data/lacci/lib/scarpe/niente/logger.rb +29 -0
  43. data/lacci/lib/scarpe/niente/shoes_spec.rb +87 -0
  44. data/lacci/lib/scarpe/niente.rb +20 -0
  45. data/lacci/lib/shoes/app.rb +88 -43
  46. data/lacci/lib/shoes/background.rb +2 -2
  47. data/lacci/lib/shoes/border.rb +2 -2
  48. data/lacci/lib/shoes/builtins.rb +63 -0
  49. data/lacci/lib/shoes/changelog.rb +52 -0
  50. data/lacci/lib/shoes/colors.rb +3 -1
  51. data/lacci/lib/shoes/constants.rb +19 -1
  52. data/lacci/lib/shoes/display_service.rb +39 -16
  53. data/lacci/lib/shoes/download.rb +2 -2
  54. data/lacci/lib/shoes/drawable.rb +380 -0
  55. data/lacci/lib/shoes/drawables/arc.rb +49 -0
  56. data/lacci/lib/shoes/drawables/arrow.rb +41 -0
  57. data/lacci/lib/shoes/drawables/button.rb +73 -0
  58. data/lacci/lib/shoes/{widgets → drawables}/check.rb +5 -4
  59. data/lacci/lib/shoes/{widgets → drawables}/document_root.rb +3 -3
  60. data/lacci/lib/shoes/{widgets → drawables}/edit_box.rb +6 -6
  61. data/lacci/lib/shoes/{widgets → drawables}/edit_line.rb +6 -6
  62. data/lacci/lib/shoes/{widgets → drawables}/flow.rb +6 -6
  63. data/lacci/lib/shoes/{widgets → drawables}/image.rb +6 -6
  64. data/lacci/lib/shoes/{widgets → drawables}/line.rb +7 -5
  65. data/lacci/lib/shoes/drawables/link.rb +34 -0
  66. data/lacci/lib/shoes/drawables/list_box.rb +56 -0
  67. data/lacci/lib/shoes/drawables/para.rb +118 -0
  68. data/lacci/lib/shoes/drawables/progress.rb +14 -0
  69. data/lacci/lib/shoes/drawables/radio.rb +33 -0
  70. data/lacci/lib/shoes/drawables/rect.rb +17 -0
  71. data/lacci/lib/shoes/{widgets → drawables}/shape.rb +6 -7
  72. data/lacci/lib/shoes/{widgets → drawables}/slot.rb +32 -20
  73. data/lacci/lib/shoes/{widgets → drawables}/span.rb +8 -7
  74. data/lacci/lib/shoes/{widgets → drawables}/stack.rb +6 -4
  75. data/lacci/lib/shoes/drawables/star.rb +50 -0
  76. data/lacci/lib/shoes/drawables/subscription_item.rb +93 -0
  77. data/lacci/lib/shoes/drawables/text_drawable.rb +63 -0
  78. data/lacci/lib/shoes/drawables/video.rb +16 -0
  79. data/lacci/lib/shoes/drawables/widget.rb +69 -0
  80. data/lacci/lib/shoes/drawables.rb +31 -0
  81. data/lacci/lib/shoes/errors.rb +28 -0
  82. data/lacci/lib/shoes/log.rb +2 -2
  83. data/lacci/lib/shoes/ruby_extensions.rb +15 -0
  84. data/lacci/lib/shoes/spacing.rb +2 -2
  85. data/lacci/lib/shoes-spec.rb +93 -0
  86. data/lacci/lib/shoes.rb +27 -7
  87. data/lacci/test/test_helper.rb +54 -0
  88. data/lacci/test/test_lacci.rb +12 -3
  89. data/lacci/test/test_shoes_errors.rb +49 -0
  90. data/lib/scarpe/cats_cradle.rb +81 -59
  91. data/lib/scarpe/errors.rb +77 -0
  92. data/lib/scarpe/evented_assertions.rb +50 -17
  93. data/lib/scarpe/shoes_spec.rb +181 -0
  94. data/lib/scarpe/version.rb +2 -2
  95. data/lib/scarpe/wv/app.rb +20 -20
  96. data/lib/scarpe/wv/arc.rb +4 -47
  97. data/lib/scarpe/wv/arrow.rb +9 -0
  98. data/lib/scarpe/wv/button.rb +7 -35
  99. data/lib/scarpe/wv/check.rb +3 -5
  100. data/lib/scarpe/wv/control_interface.rb +18 -20
  101. data/lib/scarpe/wv/document_root.rb +81 -4
  102. data/lib/scarpe/wv/{widget.rb → drawable.rb} +66 -43
  103. data/lib/scarpe/wv/edit_box.rb +4 -17
  104. data/lib/scarpe/wv/edit_line.rb +4 -18
  105. data/lib/scarpe/wv/flow.rb +2 -18
  106. data/lib/scarpe/wv/image.rb +8 -28
  107. data/lib/scarpe/wv/line.rb +3 -25
  108. data/lib/scarpe/wv/link.rb +3 -16
  109. data/lib/scarpe/wv/list_box.rb +6 -29
  110. data/lib/scarpe/wv/para.rb +11 -30
  111. data/lib/scarpe/wv/progress.rb +19 -0
  112. data/lib/scarpe/wv/radio.rb +9 -10
  113. data/lib/scarpe/wv/rect.rb +13 -0
  114. data/lib/scarpe/wv/shape.rb +3 -8
  115. data/lib/scarpe/wv/slot.rb +8 -25
  116. data/lib/scarpe/wv/span.rb +3 -27
  117. data/lib/scarpe/wv/stack.rb +2 -18
  118. data/lib/scarpe/wv/star.rb +3 -53
  119. data/lib/scarpe/wv/subscription_item.rb +38 -4
  120. data/lib/scarpe/wv/text_drawable.rb +32 -0
  121. data/lib/scarpe/wv/video.rb +15 -15
  122. data/lib/scarpe/wv/web_wrangler.rb +299 -329
  123. data/lib/scarpe/wv/webview_local_display.rb +48 -33
  124. data/lib/scarpe/wv/webview_relay_display.rb +12 -12
  125. data/lib/scarpe/wv/webview_relay_util.rb +7 -10
  126. data/lib/scarpe/wv/wv_display_worker.rb +2 -2
  127. data/lib/scarpe/wv.rb +45 -12
  128. data/lib/scarpe/wv_local.rb +1 -1
  129. data/lib/scarpe/wv_relay.rb +1 -1
  130. data/lib/scarpe.rb +1 -0
  131. data/logger/debug_web_wrangler.json +1 -1
  132. data/logger/scarpe_wv_test.json +1 -1
  133. data/scarpe-components/Gemfile.lock +86 -0
  134. data/scarpe-components/lib/scarpe/components/base64.rb +3 -7
  135. data/scarpe-components/lib/scarpe/components/calzini/alert.rb +49 -0
  136. data/scarpe-components/lib/scarpe/components/calzini/art_widgets.rb +203 -0
  137. data/scarpe-components/lib/scarpe/components/calzini/button.rb +39 -0
  138. data/scarpe-components/lib/scarpe/components/calzini/misc.rb +146 -0
  139. data/scarpe-components/lib/scarpe/components/calzini/para.rb +35 -0
  140. data/scarpe-components/lib/scarpe/components/calzini/slots.rb +155 -0
  141. data/scarpe-components/lib/scarpe/components/calzini/text_widgets.rb +65 -0
  142. data/scarpe-components/lib/scarpe/components/calzini.rb +149 -0
  143. data/scarpe-components/lib/scarpe/components/errors.rb +20 -0
  144. data/scarpe-components/lib/scarpe/components/file_helpers.rb +1 -0
  145. data/scarpe-components/lib/scarpe/components/html.rb +131 -0
  146. data/scarpe-components/lib/scarpe/components/minitest_export_reporter.rb +75 -0
  147. data/scarpe-components/lib/scarpe/components/minitest_import_runnable.rb +98 -0
  148. data/scarpe-components/lib/scarpe/components/minitest_result.rb +86 -0
  149. data/scarpe-components/lib/scarpe/components/modular_logger.rb +5 -5
  150. data/scarpe-components/lib/scarpe/components/print_logger.rb +9 -5
  151. data/scarpe-components/lib/scarpe/components/promises.rb +14 -14
  152. data/scarpe-components/lib/scarpe/components/segmented_file_loader.rb +36 -17
  153. data/scarpe-components/lib/scarpe/components/string_helpers.rb +10 -0
  154. data/scarpe-components/lib/scarpe/components/tiranti.rb +225 -0
  155. data/scarpe-components/lib/scarpe/components/unit_test_helpers.rb +45 -5
  156. data/scarpe-components/lib/scarpe/components/version.rb +2 -2
  157. data/scarpe-components/test/calzini/test_calzini_alert.rb +30 -0
  158. data/scarpe-components/test/calzini/test_calzini_art_drawables.rb +105 -0
  159. data/scarpe-components/test/calzini/test_calzini_button.rb +52 -0
  160. data/scarpe-components/test/calzini/test_calzini_misc.rb +115 -0
  161. data/scarpe-components/test/calzini/test_calzini_para.rb +37 -0
  162. data/scarpe-components/test/calzini/test_calzini_slots.rb +130 -0
  163. data/scarpe-components/test/calzini/test_calzini_text_drawables.rb +41 -0
  164. data/scarpe-components/test/mtr_data/exception.json +1 -0
  165. data/scarpe-components/test/mtr_data/fail_with_message.json +1 -0
  166. data/scarpe-components/test/mtr_data/skipped_no_message.json +1 -0
  167. data/scarpe-components/test/mtr_data/skipped_w_msg.json +1 -0
  168. data/scarpe-components/test/mtr_data/succeed_2_asserts.json +1 -0
  169. data/scarpe-components/test/test_dimensions.rb +26 -0
  170. data/scarpe-components/test/test_helper.rb +20 -0
  171. data/scarpe-components/test/test_html.rb +65 -0
  172. data/scarpe-components/test/test_minitest_result.rb +61 -0
  173. data/scarpe-components/test/test_promises.rb +5 -4
  174. data/scarpe-components/test/test_segmented_app_files.rb +8 -6
  175. data/scarpegen.rb +14 -14
  176. data/sig/scarpe.rbs +1 -1
  177. data/templates/basic_class_template.erb +13 -14
  178. data/templates/class_template_with_event_bind.erb +4 -4
  179. data/templates/class_template_with_shapes.erb +8 -17
  180. data/templates/example_template.erb +1 -1
  181. data/templates/module_template.erb +4 -4
  182. data/templates/webview_template.erb +3 -2
  183. metadata +113 -55
  184. data/examples/legacy/not_checked/shoes-contrib/elements/image-icon.rb +0 -3
  185. data/lacci/lib/shoes/widget.rb +0 -218
  186. data/lacci/lib/shoes/widgets/alert.rb +0 -19
  187. data/lacci/lib/shoes/widgets/arc.rb +0 -51
  188. data/lacci/lib/shoes/widgets/button.rb +0 -35
  189. data/lacci/lib/shoes/widgets/font.rb +0 -14
  190. data/lacci/lib/shoes/widgets/link.rb +0 -25
  191. data/lacci/lib/shoes/widgets/list_box.rb +0 -25
  192. data/lacci/lib/shoes/widgets/para.rb +0 -68
  193. data/lacci/lib/shoes/widgets/radio.rb +0 -35
  194. data/lacci/lib/shoes/widgets/star.rb +0 -44
  195. data/lacci/lib/shoes/widgets/subscription_item.rb +0 -60
  196. data/lacci/lib/shoes/widgets/text_widget.rb +0 -51
  197. data/lacci/lib/shoes/widgets/video.rb +0 -15
  198. data/lacci/lib/shoes/widgets.rb +0 -29
  199. data/lib/scarpe/wv/alert.rb +0 -66
  200. data/lib/scarpe/wv/background.rb +0 -27
  201. data/lib/scarpe/wv/border.rb +0 -24
  202. data/lib/scarpe/wv/control_interface_test.rb +0 -238
  203. data/lib/scarpe/wv/dimensions.rb +0 -22
  204. data/lib/scarpe/wv/font.rb +0 -36
  205. data/lib/scarpe/wv/html.rb +0 -108
  206. data/lib/scarpe/wv/spacing.rb +0 -41
  207. data/lib/scarpe/wv/text_widget.rb +0 -30
  208. /data/examples/legacy/not_checked/{expert → shoes-contrib/basic}/definr.rb +0 -0
  209. /data/examples/legacy/not_checked/{expert → shoes-contrib/basic}/funnies.rb +0 -0
  210. /data/examples/legacy/not_checked/shoes-contrib/{elements → basic}/list_box-select-class.rb +0 -0
  211. /data/examples/legacy/{not_checked/shoes-contrib/basic → working/simple}/basic-edit-box.rb +0 -0
  212. /data/examples/legacy/{not_checked/shoes-contrib/elements → working/simple}/basic-fps.rb +0 -0
  213. /data/examples/legacy/{not_checked/shoes-contrib/elements → working/simple}/border-cat.rb +0 -0
  214. /data/examples/legacy/{not_checked/shoes-contrib/elements → working/simple}/check-mate.rb +0 -0
  215. /data/examples/legacy/{not_checked/shoes-contrib/manipulation → working/simple}/clear-slot.rb +0 -0
  216. /data/examples/legacy/{not_checked/shoes-contrib/basic → working/simple}/clock.rb +0 -0
  217. /data/examples/legacy/{not_checked/shoes-contrib/basic → working/simple}/gradient-shoes.rb +0 -0
  218. /data/examples/legacy/{not_checked/shoes-contrib/basic → working/simple}/list_box-shape-report.rb +0 -0
  219. /data/examples/legacy/{not_checked/shoes-contrib/elements → working/simple}/list_box.rb +0 -0
  220. /data/examples/legacy/{not_checked/shoes-contrib/elements → working/simple}/phat-button.rb +0 -0
  221. /data/examples/legacy/{not_checked/shoes-contrib → working}/simple/simple-calc.rb +0 -0
  222. /data/examples/legacy/{not_checked/shoes-contrib/position → working/simple}/stack-width.rb +0 -0
  223. /data/examples/legacy/{not_checked/shoes-contrib/elements → working/simple}/width-introspec.rb +0 -0
@@ -1,238 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # The ControlInterface doesn't, by default, include much of a test framework.
4
- # But writing a test framework in heredocs in test_helper.rb seems bad.
5
- # So we write a test framework here, but don't include it by default.
6
- # A running shoes app won't normally include it, but unit tests will.
7
-
8
- require "json"
9
-
10
- require "scarpe/components/unit_test_helpers"
11
- require "scarpe/evented_assertions"
12
-
13
- class Scarpe
14
- DEFAULT_ASSERTION_TIMEOUT = 1.0
15
-
16
- class ControlInterface
17
- include Scarpe::Test::EventedAssertions
18
- include Scarpe::Test::Helpers
19
-
20
- def timed_out?
21
- @did_time_out
22
- end
23
-
24
- def die_after(time)
25
- t_start = Time.now
26
- @die_after = [t_start, time]
27
-
28
- wrangler.periodic_code("scarpeTestTimeout") do |*_args|
29
- t_delta = (Time.now - t_start).to_f
30
- if t_delta > time
31
- @did_time_out = true
32
- @log.warn("die_after - timed out after #{t_delta.inspect} (threshold: #{time.inspect})")
33
- return_results(false, "Timed out!")
34
- app.destroy
35
- end
36
- end
37
- end
38
-
39
- # This is returned alongside the actual results automatically
40
- def test_metadata
41
- data = {}
42
- if @die_after
43
- t_delta = (Time.now - @die_after[0]).to_f
44
- data["die_after"] = {
45
- t_start: @die_after[0].to_s,
46
- threshold: @die_after[1],
47
- passed: t_delta,
48
- }
49
- end
50
- data
51
- end
52
-
53
- # Need to be able to query widgets in test code
54
-
55
- def all_wv_widgets
56
- known = [doc_root]
57
- to_check = [doc_root]
58
-
59
- until to_check.empty?
60
- next_layer = to_check.flat_map(&:children)
61
- known += next_layer
62
- to_check = next_layer
63
- end
64
-
65
- # I don't *think* we'll ever have widget trees that merge back together, but just in case we'll de-dup
66
- known.uniq
67
- end
68
-
69
- # Shoes doesn't name widgets. We aren't guaranteed that the Shoes widgets are even in the same
70
- # process, since we have the Relay display service for Webview. So mostly we can look by
71
- # display service class.
72
- def find_wv_widgets(*specifiers)
73
- widgets = all_wv_widgets
74
-
75
- specifiers.each do |spec|
76
- if spec.is_a?(Class)
77
- widgets.select! { |w| spec === w }
78
- else
79
- raise "I don't know how to search for widgets by #{spec.inspect}!"
80
- end
81
- end
82
-
83
- widgets
84
- end
85
-
86
- # We want an assertions library, but one that runs inside the spawned
87
- # Webview sub-process.
88
-
89
- # Note that we do *not* extract this assertions library to use elsewhere
90
- # because it's very focused on evented assertions that start and stop
91
- # over a period of time. Instantaneous procedural asserts don't want to
92
- # use this API.
93
-
94
- def return_when_assertions_done
95
- assertions_may_exist
96
-
97
- wrangler.periodic_code("scarpeReturnWhenAssertionsDone") do |*_args|
98
- if @assertions_pending.empty?
99
- success = @assertions_failed.empty?
100
- return_results success, "Assertions #{success ? "succeeded" : "failed"}", assertion_data_as_a_struct
101
- app.destroy
102
- end
103
- end
104
- end
105
-
106
- def assertions_may_exist
107
- @assertions_pending ||= {}
108
- @assertions_failed ||= {}
109
- @assertions_passed ||= 0
110
- @assertion_counter ||= 0
111
- end
112
-
113
- def start_assertion(code)
114
- assertions_may_exist
115
-
116
- this_assertion = @assertion_counter
117
- @assertion_counter += 1
118
-
119
- @assertions_pending[this_assertion] = {
120
- id: this_assertion,
121
- code: code,
122
- }
123
-
124
- this_assertion
125
- end
126
-
127
- def pass_assertion(id)
128
- @assertions_pending.delete(id)
129
- @assertions_passed += 1
130
- end
131
-
132
- def fail_assertion(id, fail_message)
133
- item = @assertions_pending.delete(id)
134
- item[:fail_message] = fail_message
135
- @assertions_failed[id] = item
136
- end
137
-
138
- def assertions_pending?
139
- !@assertions_pending.empty?
140
- end
141
-
142
- def assertion_data_as_a_struct
143
- {
144
- still_pending: @assertions_pending.size,
145
- succeeded: @assertions_passed,
146
- failed: @assertions_failed.size,
147
- failures: @assertions_failed.values.map { |item| [item[:code], item[:failure_reason]] },
148
- }
149
- end
150
-
151
- # Create a promise to do a JS assertion, normally after other ops have finished.
152
- def assert_js(js_code, wait_for: [], timeout: DEFAULT_ASSERTION_TIMEOUT)
153
- id = start_assertion(js_code)
154
-
155
- # this isn't a TestPromise, so it doesn't have the additional DSL entries
156
- promise = wrangler.eval_js_async(js_code, wait_for: wait_for, timeout: timeout)
157
- promise.on_rejected do
158
- fail_assertion(id, "JS Eval failed: #{promise.reason.inspect}")
159
- end
160
- promise.on_fulfilled do
161
- ret_val = promise.returned_value
162
- if ret_val
163
- pass_assertion(id)
164
- else
165
- fail_assertion(id, "Expected true JS value: #{ret_val.inspect}")
166
- end
167
- end
168
-
169
- # So we wrap it in a no-op TestPromise, to get the DSL entries.
170
- TestPromise.new(iface: self, wait_for: [promise]).to_execute {}
171
- end
172
-
173
- def assert(value, msg = nil)
174
- id = start_assertion("#{caller[0]}: #{msg || "Value should be true!"}")
175
-
176
- if value
177
- pass_assertion(id)
178
- else
179
- fail_assertion(id, "Expected true Ruby value: #{value.inspect}")
180
- end
181
- end
182
-
183
- def assert_equal(val1, val2, msg = nil)
184
- assert val1 == val2, (msg || "Expected #{val2.inspect} to equal #{val1.inspect}!")
185
- end
186
-
187
- # How do we signal an error?
188
- def with_js_value(js_code, wait_for: [], timeout: DEFAULT_ASSERTION_TIMEOUT, &block)
189
- raise "Must give a block to with_js_value!" unless block
190
-
191
- js_promise = wrangler.eval_js_async(js_code, wait_for: wait_for, timeout: timeout)
192
- ruby_promise = TestPromise.new(iface: self, wait_for: [js_promise])
193
- ruby_promise.to_execute(&block)
194
- ruby_promise
195
- end
196
-
197
- def with_js_dom_html(wait_for: [], timeout: DEFAULT_ASSERTION_TIMEOUT, &block)
198
- with_js_value("document.getElementById('wrapper-wvroot').innerHTML", wait_for: wait_for, timeout: timeout, &block)
199
- end
200
-
201
- def fully_updated(wait_for: [])
202
- wrangler.promise_dom_fully_updated
203
- end
204
- end
205
-
206
- # A {Scarpe::Promise} but with helper functions for Webview testing.
207
- class TestPromise < Scarpe::Promise
208
- def initialize(iface:, state: nil, wait_for: [], &scheduler)
209
- @iface = iface
210
- super(state: state, parents: wait_for, &scheduler)
211
- end
212
-
213
- def inspect
214
- "<#TestPromise::#{object_id} state=#{state.inspect} parents=#{parents.inspect} value=#{returned_value.inspect} reason=#{reason.inspect}>"
215
- end
216
-
217
- # This method expects to wait for the parent TestPromise and then run a block of Ruby that returns
218
- # another promise. This is useful for wrapping Promises like those from replace() that don't have
219
- # the test DSL built in. The block will execute when this outer promise is scheduled -- so we don't do
220
- # a replace() too early, for instance. And then the outer promise will fulfill when the inner one does.
221
- def then_ruby_promise(wait_for: [], &block)
222
- ruby_wrapper_promise = TestPromise.new iface: @iface, wait_for: ([self] + wait_for)
223
-
224
- ruby_wrapper_promise.on_scheduled do
225
- inner_ruby_promise = block.call
226
- inner_ruby_promise.on_fulfilled { ruby_wrapper_promise.fulfilled!(inner_ruby_promise.returned_value) }
227
- end
228
- end
229
-
230
- def then_with_js_value(js_code, wait_for: [], timeout: DEFAULT_ASSERTION_TIMEOUT, &block)
231
- @iface.with_js_value(js_code, wait_for: (wait_for + [self]), timeout:, &block)
232
- end
233
-
234
- def then_with_js_dom_html(wait_for: [], timeout: DEFAULT_ASSERTION_TIMEOUT, &block)
235
- @iface.with_js_dom_html(wait_for: (wait_for + [self]), timeout:, &block)
236
- end
237
- end
238
- end
@@ -1,22 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class Scarpe
4
- class Dimensions
5
- class << self
6
- def length(value)
7
- case value
8
- when Integer
9
- if value < 0
10
- "calc(100% - #{value.abs}px)"
11
- else
12
- "#{value}px"
13
- end
14
- when Float
15
- "#{value * 100}%"
16
- else
17
- value
18
- end
19
- end
20
- end
21
- end
22
- end
@@ -1,36 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "scarpe/components/base64"
4
-
5
- class Scarpe
6
- class WebviewFont < WebviewWidget
7
- include Components::Base64
8
- attr_accessor :font
9
-
10
- def initialize(properties)
11
- @font = properties[:font]
12
- super
13
- end
14
-
15
- def font_name
16
- File.basename(@font, ".*")
17
- end
18
-
19
- def element
20
- HTML.render do |h|
21
- h.link(href: @font, rel: "stylesheet")
22
- h.style do
23
- <<~CSS
24
- @font-face {
25
- font-family: #{font_name};
26
- src: url("data:font/truetype;base64,#{encode_file_to_base64(@font)}") format('truetype');
27
- }
28
- * {
29
- font-family: #{font_name};
30
- }
31
- CSS
32
- end
33
- end
34
- end
35
- end
36
- end
@@ -1,108 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class Scarpe
4
- class HTML
5
- CONTENT_TAGS = [:div, :p, :button, :ul, :li, :textarea, :a, :video, :strong, :style, :em, :code, :u, :line, :span, :svg].freeze
6
- VOID_TAGS = [:input, :img, :polygon, :source, :link, :path].freeze
7
-
8
- TAGS = (CONTENT_TAGS + VOID_TAGS).freeze
9
-
10
- class << self
11
- def render(&block)
12
- new(&block).value
13
- end
14
- end
15
-
16
- def initialize(&block)
17
- @buffer = ""
18
- block.call(self)
19
- end
20
-
21
- def value
22
- @buffer
23
- end
24
-
25
- def respond_to_missing?(name, include_all = false)
26
- TAGS.include?(name) || super(name, include_all)
27
- end
28
-
29
- def p(*args, &block)
30
- method_missing(:p, *args, &block)
31
- end
32
-
33
- def option(**attrs, &block)
34
- tag(:option, **attrs, &block)
35
- end
36
-
37
- def tag(name, **attrs, &block)
38
- if VOID_TAGS.include?(name)
39
- raise ArgumentError, "void tag #{name} cannot have content" if block_given?
40
-
41
- @buffer += "<#{name}#{render_attributes(attrs)} />"
42
- else
43
- @buffer += "<#{name}#{render_attributes(attrs)}>"
44
-
45
- if block_given?
46
- result = block.call(self)
47
- else
48
- result = attrs[:content]
49
- @buffer += result if result.is_a?(String)
50
- end
51
- @buffer += result if result.is_a?(String)
52
-
53
- @buffer += "</#{name}>"
54
- end
55
-
56
- nil
57
- end
58
-
59
- def select(**attrs, &block)
60
- tag(:select, **attrs, &block)
61
- end
62
-
63
- def method_missing(name, *args, &block)
64
- raise NoMethodError, "no method #{name} for #{self.class.name}" unless TAGS.include?(name)
65
-
66
- if VOID_TAGS.include?(name)
67
- raise ArgumentError, "void tag #{name} cannot have content" if block_given?
68
-
69
- @buffer += "<#{name}#{render_attributes(*args)} />"
70
- else
71
- @buffer += "<#{name}#{render_attributes(*args)}>"
72
-
73
- if block_given?
74
- result = block.call(self)
75
- else
76
- result = args.first
77
- @buffer += result if result.is_a?(String)
78
- end
79
- @buffer += result if result.is_a?(String)
80
-
81
- @buffer += "</#{name}>"
82
- end
83
-
84
- nil
85
- end
86
-
87
- private
88
-
89
- def render_attributes(attributes = {})
90
- return "" if attributes.empty?
91
-
92
- attributes[:style] = render_style(attributes[:style]) if attributes[:style]
93
- attributes.compact!
94
-
95
- return if attributes.empty?
96
-
97
- result = attributes.map { |k, v| "#{k}=\"#{v}\"" }.join(" ")
98
- " #{result}"
99
- end
100
-
101
- def render_style(style)
102
- return style unless style.is_a?(Hash)
103
- return if style.empty?
104
-
105
- style.map { |k, v| "#{k}:#{v}" }.join(";")
106
- end
107
- end
108
- end
@@ -1,41 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class Scarpe
4
- module WebviewSpacing
5
- SPACING_DIRECTIONS = [:left, :right, :top, :bottom]
6
-
7
- def style
8
- styles = defined?(super) ? super : {}
9
-
10
- extract_spacing_styles_for(:margin, styles, @margin)
11
- extract_spacing_styles_for(:padding, styles, @padding)
12
-
13
- styles
14
- end
15
-
16
- def extract_spacing_styles_for(attribute, styles, values)
17
- values ||= spacing_values_from_options(attribute)
18
-
19
- case values
20
- when Hash
21
- values.each do |direction, value|
22
- styles["#{attribute}-#{direction}"] = Dimensions.length(value)
23
- end
24
- when Array
25
- SPACING_DIRECTIONS.zip(values).to_h.compact.each do |direction, value|
26
- styles["#{attribute}-#{direction}"] = Dimensions.length(value)
27
- end
28
- else
29
- styles[attribute] = Dimensions.length(values)
30
- end
31
-
32
- styles.compact!
33
- end
34
-
35
- def spacing_values_from_options(attribute)
36
- SPACING_DIRECTIONS.map do |direction|
37
- @options.delete("#{attribute}_#{direction}".to_sym)
38
- end
39
- end
40
- end
41
- end
@@ -1,30 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class Scarpe
4
- class WebviewTextWidget < Scarpe::WebviewWidget
5
- end
6
-
7
- class << self
8
- def default_wv_text_widget_with(element)
9
- webview_class_name = "Webview#{element.capitalize}"
10
- webview_widget_class = Class.new(Scarpe::WebviewTextWidget) do
11
- def initialize(properties)
12
- class_name = self.class.name.split("::")[-1]
13
- @html_tag = class_name.delete_prefix("Webview").downcase
14
- super
15
- end
16
-
17
- def element
18
- HTML.render do |h|
19
- h.send(@html_tag) { @content.to_s }
20
- end
21
- end
22
- end
23
- Scarpe.const_set webview_class_name, webview_widget_class
24
- end
25
- end
26
- end
27
-
28
- Scarpe.default_wv_text_widget_with(:code)
29
- Scarpe.default_wv_text_widget_with(:em)
30
- Scarpe.default_wv_text_widget_with(:strong)