scarpe 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (251) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +7 -1
  3. data/CHANGELOG.md +36 -4
  4. data/Gemfile +2 -1
  5. data/Gemfile.lock +13 -3
  6. data/LICENSE.txt +7 -1
  7. data/README.md +77 -14
  8. data/Rakefile +67 -0
  9. data/examples/Edit_box_Styles.rb +8 -0
  10. data/examples/Kerning.rb +7 -0
  11. data/examples/border.rb +11 -0
  12. data/examples/check.rb +2 -0
  13. data/examples/download_and_show_image.rb +3 -0
  14. data/examples/flags/finland.rb +15 -0
  15. data/examples/flags/italy.rb +11 -0
  16. data/examples/flags/mauritius.rb +14 -0
  17. data/examples/font_family.rb +17 -0
  18. data/examples/font_shorthand.rb +9 -0
  19. data/examples/gen.rb +4 -0
  20. data/examples/legacy/not_checked/shoes-manual/append.rb +10 -0
  21. data/examples/legacy/not_checked/shoes-manual/background_change.rb +12 -0
  22. data/examples/legacy/not_checked/shoes-manual/background_pattern.rb +5 -0
  23. data/examples/legacy/not_checked/shoes-manual/basic_app.rb +8 -0
  24. data/examples/legacy/not_checked/shoes-manual/border.rb +9 -0
  25. data/examples/legacy/not_checked/shoes-manual/builtins/FONTS.rb +5 -0
  26. data/examples/legacy/not_checked/shoes-manual/builtins/ask.rb +2 -0
  27. data/examples/legacy/not_checked/shoes-manual/builtins/ask_color.rb +5 -0
  28. data/examples/legacy/not_checked/shoes-manual/builtins/ask_open_file.rb +5 -0
  29. data/examples/legacy/not_checked/shoes-manual/builtins/ask_save_folder.rb +2 -0
  30. data/examples/legacy/not_checked/shoes-manual/builtins/confirm.rb +4 -0
  31. data/examples/legacy/not_checked/shoes-manual/builtins/debug.rb +2 -0
  32. data/examples/legacy/not_checked/shoes-manual/builtins/info.rb +3 -0
  33. data/examples/legacy/not_checked/shoes-manual/button.rb +9 -0
  34. data/examples/legacy/not_checked/shoes-manual/clear.rb +7 -0
  35. data/examples/legacy/not_checked/shoes-manual/custom_header.rb +13 -0
  36. data/examples/legacy/not_checked/shoes-manual/displace.rb +14 -0
  37. data/examples/legacy/not_checked/shoes-manual/edit_box.rb +8 -0
  38. data/examples/legacy/not_checked/shoes-manual/fill_pattern.rb +5 -0
  39. data/examples/legacy/not_checked/shoes-manual/fonts.rb +7 -0
  40. data/examples/legacy/not_checked/shoes-manual/gutter.rb +6 -0
  41. data/examples/legacy/not_checked/shoes-manual/image_web.rb +4 -0
  42. data/examples/legacy/not_checked/shoes-manual/keypress.rb +7 -0
  43. data/examples/legacy/not_checked/shoes-manual/list_box.rb +10 -0
  44. data/examples/legacy/not_checked/shoes-manual/motion.rb +10 -0
  45. data/examples/legacy/not_checked/shoes-manual/mouse.rb +8 -0
  46. data/examples/legacy/not_checked/shoes-manual/move.rb +14 -0
  47. data/examples/legacy/not_checked/shoes-manual/nested_ovals.rb +8 -0
  48. data/examples/legacy/not_checked/shoes-manual/oval.rb +7 -0
  49. data/examples/legacy/not_checked/shoes-manual/ovals.rb +6 -0
  50. data/examples/legacy/not_checked/shoes-manual/ovals_image.rb +8 -0
  51. data/examples/legacy/not_checked/shoes-manual/prepend.rb +7 -0
  52. data/examples/legacy/not_checked/shoes-manual/progress_bar.rb +10 -0
  53. data/examples/legacy/not_checked/shoes-manual/radio.rb +18 -0
  54. data/examples/legacy/not_checked/shoes-manual/radio_alternative_1.rb +7 -0
  55. data/examples/legacy/not_checked/shoes-manual/radio_alternative_2.rb +9 -0
  56. data/examples/legacy/not_checked/shoes-manual/rotate_rectangle.rb +6 -0
  57. data/examples/legacy/not_checked/shoes-manual/shape.rb +11 -0
  58. data/examples/legacy/not_checked/shoes-manual/static/avatar.png +0 -0
  59. data/examples/legacy/not_checked/shoes-manual/stroke.rb +5 -0
  60. data/examples/legacy/not_checked/shoes-manual/style.rb +3 -0
  61. data/examples/legacy/not_checked/shoes-manual/style_alternative_1.rb +4 -0
  62. data/examples/legacy/not_checked/shoes-manual/style_alternative_2.rb +5 -0
  63. data/examples/legacy/not_checked/shoes-manual/style_length.rb +5 -0
  64. data/examples/legacy/not_checked/shoes-manual/timer.rb +6 -0
  65. data/examples/legacy/not_checked/shoes-manual/trigger_window.rb +8 -0
  66. data/examples/legacy/not_checked/shoes-manual/window_owner.rb +8 -0
  67. data/examples/legacy/working/shoes_manual/alert_button.rb +2 -0
  68. data/examples/legacy/working/shoes_manual/animate.rb +7 -0
  69. data/examples/legacy/working/shoes_manual/background_para.rb +4 -0
  70. data/examples/legacy/working/shoes_manual/button_alternative.rb +7 -0
  71. data/examples/legacy/working/shoes_manual/checkbox.rb +17 -0
  72. data/examples/legacy/working/shoes_manual/download.rb +12 -0
  73. data/examples/legacy/working/shoes_manual/edit_box.rb +6 -0
  74. data/examples/legacy/working/shoes_manual/editline.rb +7 -0
  75. data/examples/legacy/working/shoes_manual/fixed_height.rb +8 -0
  76. data/examples/legacy/working/shoes_manual/fixed_width.rb +12 -0
  77. data/examples/legacy/working/shoes_manual/image.rb +5 -0
  78. data/examples/legacy/working/shoes_manual/instance_variable_check.rb +10 -0
  79. data/examples/legacy/working/shoes_manual/message.rb +18 -0
  80. data/examples/legacy/working/shoes_manual/rectangle.rb +6 -0
  81. data/examples/legacy/working/shoes_manual/save_download.rb +12 -0
  82. data/examples/legacy/working/shoes_manual/self_check.rb +10 -0
  83. data/examples/legacy/working/shoes_manual/stack.rb +7 -0
  84. data/examples/legacy/working/shoes_manual/style_info.rb +8 -0
  85. data/examples/legacy/working/shoes_manual/utf8_support.rb +8 -0
  86. data/examples/legacy/working/shoes_manual/width.rb +4 -0
  87. data/examples/local_assets/multi_image.rb +5 -0
  88. data/examples/local_assets/small.png +0 -0
  89. data/examples/local_fonts.rb +3 -0
  90. data/examples/margin.rb +13 -0
  91. data/examples/margin_check.rb +27 -0
  92. data/examples/oval-with-kwargs.rb +3 -0
  93. data/examples/oval.rb +26 -0
  94. data/examples/para_font_styles.rb +17 -0
  95. data/examples/para_font_variant.rb +6 -0
  96. data/examples/para_fontweight.rb +13 -0
  97. data/examples/parse_xl_funnies.rb +3 -0
  98. data/examples/rect.rb +1 -1
  99. data/examples/scarpe_ext.rb +3 -0
  100. data/examples/shapes/star.rb +1 -3
  101. data/examples/spacing.rb +1 -1
  102. data/examples/span.rb +4 -2
  103. data/lacci/lacci.gemspec +2 -2
  104. data/lacci/lib/lacci/scarpe_cli.rb +0 -1
  105. data/lacci/lib/lacci/version.rb +1 -1
  106. data/lacci/lib/scarpe/niente/display_service.rb +5 -1
  107. data/lacci/lib/scarpe/niente/drawable.rb +2 -0
  108. data/lacci/lib/scarpe/niente/shoes_spec.rb +7 -1
  109. data/lacci/lib/scarpe/niente.rb +14 -2
  110. data/lacci/lib/shoes/app.rb +44 -50
  111. data/lacci/lib/shoes/constants.rb +23 -2
  112. data/lacci/lib/shoes/display_service.rb +43 -4
  113. data/lacci/lib/shoes/drawable.rb +309 -35
  114. data/lacci/lib/shoes/drawables/arc.rb +2 -24
  115. data/lacci/lib/shoes/drawables/arrow.rb +2 -22
  116. data/lacci/lib/shoes/drawables/border.rb +28 -0
  117. data/lacci/lib/shoes/drawables/button.rb +4 -20
  118. data/lacci/lib/shoes/drawables/check.rb +7 -3
  119. data/lacci/lib/shoes/drawables/document_root.rb +4 -4
  120. data/lacci/lib/shoes/drawables/edit_box.rb +6 -5
  121. data/lacci/lib/shoes/drawables/edit_line.rb +5 -4
  122. data/lacci/lib/shoes/drawables/flow.rb +3 -5
  123. data/lacci/lib/shoes/drawables/font_helper.rb +62 -0
  124. data/lacci/lib/shoes/drawables/image.rb +2 -2
  125. data/lacci/lib/shoes/drawables/line.rb +4 -7
  126. data/lacci/lib/shoes/drawables/link.rb +5 -8
  127. data/lacci/lib/shoes/drawables/list_box.rb +8 -5
  128. data/lacci/lib/shoes/drawables/oval.rb +48 -0
  129. data/lacci/lib/shoes/drawables/para.rb +106 -18
  130. data/lacci/lib/shoes/drawables/progress.rb +2 -1
  131. data/lacci/lib/shoes/drawables/radio.rb +5 -3
  132. data/lacci/lib/shoes/drawables/rect.rb +5 -4
  133. data/lacci/lib/shoes/drawables/shape.rb +2 -1
  134. data/lacci/lib/shoes/drawables/slot.rb +99 -8
  135. data/lacci/lib/shoes/drawables/stack.rb +6 -11
  136. data/lacci/lib/shoes/drawables/star.rb +8 -30
  137. data/lacci/lib/shoes/drawables/text_drawable.rb +93 -34
  138. data/lacci/lib/shoes/drawables/video.rb +3 -2
  139. data/lacci/lib/shoes/drawables/widget.rb +8 -3
  140. data/lacci/lib/shoes/drawables.rb +2 -1
  141. data/lacci/lib/shoes/errors.rb +13 -3
  142. data/lacci/lib/shoes/margin_helper.rb +79 -0
  143. data/lacci/lib/shoes.rb +4 -3
  144. data/lacci/test/.gitignore +1 -0
  145. data/lacci/test/test_draw_context.rb +167 -0
  146. data/lacci/test/test_font_helper.rb +57 -0
  147. data/lacci/test/test_helper.rb +31 -4
  148. data/lacci/test/test_lacci.rb +93 -6
  149. data/lacci/test/test_margin_helper.rb +82 -0
  150. data/lacci/test/test_niente_test_infra.rb +26 -0
  151. data/lacci/test/test_oval.rb +82 -0
  152. data/lacci/test/test_parenting.rb +140 -0
  153. data/lacci/test/test_text_drawables.rb +23 -0
  154. data/lib/scarpe/assets.rb +18 -0
  155. data/lib/scarpe/cats_cradle.rb +57 -98
  156. data/lib/scarpe/shoes_spec.rb +22 -43
  157. data/lib/scarpe/version.rb +1 -1
  158. data/lib/scarpe/wv/app.rb +1 -0
  159. data/lib/scarpe/wv/arc.rb +0 -4
  160. data/lib/scarpe/wv/border.rb +15 -0
  161. data/lib/scarpe/wv/control_interface.rb +2 -10
  162. data/lib/scarpe/wv/document_root.rb +2 -2
  163. data/lib/scarpe/wv/drawable.rb +6 -40
  164. data/lib/scarpe/wv/edit_box.rb +4 -1
  165. data/lib/scarpe/wv/edit_line.rb +5 -2
  166. data/lib/scarpe/wv/image.rb +2 -5
  167. data/lib/scarpe/wv/link.rb +4 -2
  168. data/lib/scarpe/wv/oval.rb +13 -0
  169. data/lib/scarpe/wv/para.rb +1 -0
  170. data/lib/scarpe/wv/scarpe_extensions.rb +8 -0
  171. data/lib/scarpe/wv/shape.rb +10 -5
  172. data/lib/scarpe/wv/text_drawable.rb +72 -14
  173. data/lib/scarpe/wv/web_wrangler.rb +33 -11
  174. data/lib/scarpe/wv/webview_local_display.rb +6 -2
  175. data/lib/scarpe/wv.rb +8 -1
  176. data/scarpe-components/Gemfile +4 -1
  177. data/scarpe-components/Gemfile.lock +2 -3
  178. data/scarpe-components/README.md +2 -2
  179. data/scarpe-components/assets/bootstrap-themes/bootstrap-cerulean.css +12229 -0
  180. data/scarpe-components/assets/bootstrap-themes/bootstrap-cosmo.css +11810 -0
  181. data/scarpe-components/assets/bootstrap-themes/bootstrap-cyborg.css +12210 -0
  182. data/scarpe-components/assets/bootstrap-themes/bootstrap-darkly.css +12153 -0
  183. data/scarpe-components/assets/bootstrap-themes/bootstrap-flatly.css +12126 -0
  184. data/scarpe-components/assets/bootstrap-themes/bootstrap-icons.min.css +5 -0
  185. data/scarpe-components/assets/bootstrap-themes/bootstrap-journal.css +12099 -0
  186. data/scarpe-components/assets/bootstrap-themes/bootstrap-litera.css +12211 -0
  187. data/scarpe-components/assets/bootstrap-themes/bootstrap-lumen.css +12369 -0
  188. data/scarpe-components/assets/bootstrap-themes/bootstrap-lux.css +11928 -0
  189. data/scarpe-components/assets/bootstrap-themes/bootstrap-materia.css +13184 -0
  190. data/scarpe-components/assets/bootstrap-themes/bootstrap-minty.css +12177 -0
  191. data/scarpe-components/assets/bootstrap-themes/bootstrap-morph.css +12750 -0
  192. data/scarpe-components/assets/bootstrap-themes/bootstrap-pulse.css +11890 -0
  193. data/scarpe-components/assets/bootstrap-themes/bootstrap-quartz.css +12622 -0
  194. data/scarpe-components/assets/bootstrap-themes/bootstrap-sandstone.css +12201 -0
  195. data/scarpe-components/assets/bootstrap-themes/bootstrap-simplex.css +12186 -0
  196. data/scarpe-components/assets/bootstrap-themes/bootstrap-sketchy.css +12451 -0
  197. data/scarpe-components/assets/bootstrap-themes/bootstrap-slate.css +12492 -0
  198. data/scarpe-components/assets/bootstrap-themes/bootstrap-solar.css +12149 -0
  199. data/scarpe-components/assets/bootstrap-themes/bootstrap-spacelab.css +12266 -0
  200. data/scarpe-components/assets/bootstrap-themes/bootstrap-superhero.css +12216 -0
  201. data/scarpe-components/assets/bootstrap-themes/bootstrap-united.css +12077 -0
  202. data/scarpe-components/assets/bootstrap-themes/bootstrap-vapor.css +12549 -0
  203. data/scarpe-components/assets/bootstrap-themes/bootstrap-yeti.css +12325 -0
  204. data/scarpe-components/assets/bootstrap-themes/bootstrap-zephyr.css +12283 -0
  205. data/scarpe-components/assets/bootstrap-themes/bootstrap.bundle.min.js +7 -0
  206. data/scarpe-components/lib/scarpe/components/asset_server.rb +219 -0
  207. data/scarpe-components/lib/scarpe/components/base64.rb +22 -0
  208. data/scarpe-components/lib/scarpe/components/calzini/{art_widgets.rb → art_drawables.rb} +42 -18
  209. data/scarpe-components/lib/scarpe/components/calzini/border.rb +38 -0
  210. data/scarpe-components/lib/scarpe/components/calzini/button.rb +6 -8
  211. data/scarpe-components/lib/scarpe/components/calzini/misc.rb +7 -17
  212. data/scarpe-components/lib/scarpe/components/calzini/para.rb +213 -11
  213. data/scarpe-components/lib/scarpe/components/calzini/slots.rb +14 -60
  214. data/scarpe-components/lib/scarpe/components/calzini.rb +88 -1
  215. data/scarpe-components/lib/scarpe/components/errors.rb +4 -0
  216. data/scarpe-components/lib/scarpe/components/html.rb +4 -1
  217. data/scarpe-components/lib/scarpe/components/minitest_export_reporter.rb +11 -3
  218. data/scarpe-components/lib/scarpe/components/minitest_result.rb +41 -0
  219. data/scarpe-components/lib/scarpe/components/print_logger.rb +17 -2
  220. data/scarpe-components/lib/scarpe/components/process_helpers.rb +37 -0
  221. data/scarpe-components/lib/scarpe/components/segmented_file_loader.rb +1 -1
  222. data/scarpe-components/lib/scarpe/components/tiranti.rb +42 -100
  223. data/scarpe-components/lib/scarpe/components/unit_test_helpers.rb +3 -1
  224. data/scarpe-components/lib/scarpe/components/version.rb +1 -1
  225. data/scarpe-components/test/assets/big-image.png +0 -0
  226. data/scarpe-components/test/assets/big-stylesheet.css +497 -0
  227. data/scarpe-components/test/assets/little-image.png +0 -0
  228. data/scarpe-components/test/assets/little-stylesheet.css +1 -0
  229. data/scarpe-components/test/calzini/test_calzini_art_drawables.rb +7 -7
  230. data/scarpe-components/test/calzini/test_calzini_button.rb +7 -5
  231. data/scarpe-components/test/calzini/test_calzini_misc.rb +9 -9
  232. data/scarpe-components/test/calzini/test_calzini_para.rb +6 -9
  233. data/scarpe-components/test/calzini/test_calzini_slots.rb +12 -57
  234. data/scarpe-components/test/calzini/test_calzini_text_drawables.rb +83 -18
  235. data/scarpe-components/test/calzini/test_various.rb +133 -0
  236. data/scarpe-components/test/test_asset_server.rb +72 -0
  237. data/scarpe-components/test/test_components.rb +31 -2
  238. data/scarpe-components/test/test_helper.rb +0 -1
  239. data/scarpe-components/test/test_minitest_result.rb +7 -0
  240. data/scarpe-components/test/test_segmented_app_files.rb +2 -0
  241. data/tasks/check_html_fixtures.rb +140 -0
  242. data/tasks/regenerate_html_fixtures.rb +104 -0
  243. data/templates/class_template_with_shapes.erb +0 -11
  244. metadata +180 -32
  245. data/lacci/lib/scarpe/niente/logger.rb +0 -29
  246. data/lacci/lib/shoes/drawables/span.rb +0 -27
  247. data/lacci/lib/shoes/spacing.rb +0 -9
  248. data/lib/scarpe/evented_assertions.rb +0 -121
  249. data/lib/scarpe/wv/span.rb +0 -44
  250. data/scarpe-components/lib/scarpe/components/calzini/text_widgets.rb +0 -65
  251. /data/examples/legacy/{not_checked → working}/shoes3-tests/editline/editline.rb +0 -0
@@ -1,76 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "scarpe/components/unit_test_helpers"
4
- require "scarpe/evented_assertions"
5
4
 
6
5
  require "fiber"
7
6
 
8
- module Scarpe::Test
9
- # We'd like something we can call Shoes drawable methods on, such as para.replace.
10
- # But we'd also like to be able to grab the corresponding display drawable and
11
- # call some of *those* methods.
12
- class CCProxy
13
- attr_reader :display
14
- attr_reader :obj
15
-
16
- def initialize(obj)
17
- @obj = obj
18
- # TODO: how to do this with Webview relay? Proxy object to send a message, maybe?
19
- @display = ::Shoes::DisplayService.display_service.query_display_drawable_for(obj.linkable_id)
20
- end
21
-
22
- def method_missing(method, ...)
23
- if @obj.respond_to?(method)
24
- self.singleton_class.define_method(method) do |*args, **kwargs, &block|
25
- @obj.send(method, *args, **kwargs, &block)
26
- end
27
- send(method, ...)
28
- else
29
- super # raise an exception
30
- end
31
- end
32
-
33
- def respond_to_missing?(method_name, include_private = false)
34
- @obj.respond_to_missing?(method_name, include_private)
35
- end
36
-
37
- def trigger(event_name, *args)
38
- name = "#{@obj.linkable_id}-#{event_name}"
39
- Scarpe::Webview::DisplayService.instance.app.handle_callback(name, *args)
40
- end
41
-
42
- [:click, :hover, :leave, :change].each do |ev|
43
- define_method "trigger_#{ev}" do |*args|
44
- trigger(ev, *args)
45
- end
46
- end
47
- end
48
-
49
- module DrawableFinders
50
- # What to do about TextDrawables? Link, code, em, strong?
51
- # Also, wait, what's up with span? What *is* that?
52
- Shoes::Drawable.drawable_classes.each do |drawable_class|
53
- finder_name = drawable_class.dsl_name
54
-
55
- define_method(finder_name) do |*args|
56
- app = Shoes::App.instance
57
-
58
- drawables = app.find_drawables_by(drawable_class, *args)
59
- raise Shoes::Errors::MultipleDrawablesFoundError, "Found more than one #{finder_name} matching #{args.inspect}!" if drawables.size > 1
60
- raise Shoes::Errors::NoDrawablesFoundError, "Found no #{finder_name} matching #{args.inspect}!" if drawables.empty?
61
-
62
- CCProxy.new(drawables[0])
63
- end
64
- end
65
- end
66
-
7
+ module Scarpe
67
8
  # This class defines the CatsCradle DSL. It also holds a "bag of fibers"
68
9
  # with promises for when they should next resume.
69
10
  class CCInstance
70
11
  include Shoes::Log
71
- include Scarpe::Test::EventedAssertions
72
12
  include Scarpe::Test::Helpers
73
- include Scarpe::Test::DrawableFinders
74
13
 
75
14
  def self.instance
76
15
  @instance ||= CCInstance.new
@@ -79,18 +18,19 @@ module Scarpe::Test
79
18
  def initialize
80
19
  log_init("CatsCradle")
81
20
 
82
- evented_assertions_initialize
83
-
84
21
  @waiting_fibers = []
85
22
  @event_promises = {}
23
+ @shutdown = false
86
24
 
87
25
  @manager_fiber = Fiber.new do
26
+ Fiber[:catscradle] = true
27
+
88
28
  loop do
89
29
  # A fiber can run briefly and then exit. It can run and then block on an API call.
90
30
  # These fibers return promises to indicate to CatsCradle when they can run again.
91
31
  # A fiber that is no longer #alive? is assumed to be successfully finished.
92
32
  @waiting_fibers.each do |fiber_data|
93
- next unless fiber_data[:promise].fulfilled?
33
+ next if !fiber_data[:promise].fulfilled? || !fiber_data[:fiber].alive? || @shutdown
94
34
 
95
35
  @log.debug("Resuming fiber with value #{fiber_data[:promise].returned_value.inspect}")
96
36
  result = fiber_data[:fiber].transfer fiber_data[:promise].returned_value
@@ -117,6 +57,17 @@ module Scarpe::Test
117
57
  end
118
58
  end
119
59
 
60
+ private
61
+
62
+ def cc_fiber(&block)
63
+ Fiber.new do
64
+ Fiber[:catscradle] = true
65
+ CCInstance.instance.instance_eval(&block)
66
+ end
67
+ end
68
+
69
+ public
70
+
120
71
  # If we add "every" events, that's likely to complicate timing and event_promise handling.
121
72
  EVENT_TYPES = [:init, :next_heartbeat, :next_redraw, :every_heartbeat, :every_redraw]
122
73
 
@@ -140,9 +91,16 @@ module Scarpe::Test
140
91
  p = @event_promises.delete(:every_heartbeat)
141
92
  p&.fulfilled!
142
93
 
94
+ # Reschedule on_every_heartbeat fibers for next heartbeat, too.
95
+ # This fiber won't be called again by a heartbeat, though it may
96
+ # continue if it waits on another promise.
97
+ @waiting_fibers.select { |f| f[:on_event] == :every_heartbeat }.each do |f|
98
+ on_event(:every_heartbeat, &f[:block])
99
+ end
100
+
143
101
  # Give every ready fiber a chance to run once.
144
- @manager_fiber.resume
145
- end
102
+ @manager_fiber.resume unless @shutdown
103
+ end unless @shutdown
146
104
  end
147
105
 
148
106
  @control_interface.on_event(:every_redraw) do
@@ -153,42 +111,38 @@ module Scarpe::Test
153
111
  p = @event_promises.delete(:every_redraw)
154
112
  p&.fulfilled!
155
113
 
114
+ # Reschedule on_every_redraw fibers for next redraw, too.
115
+ @waiting_fibers.select { |f| f[:on_event] == :every_redraw }.each do |f|
116
+ on_event(:every_redraw, &f[:block])
117
+ end
118
+
156
119
  # Give every ready fiber a chance to run once.
157
- @manager_fiber.resume
158
- end
120
+ @manager_fiber.resume unless @shutdown
121
+ end unless @shutdown
159
122
  end
160
123
  end
161
124
 
125
+ def fiber_start
126
+ @manager_fiber.resume unless @shutdown
127
+ end
128
+
162
129
  def event_promise(event)
163
130
  @event_promises[event] ||= ::Scarpe::Promise.new
164
131
  end
165
132
 
166
133
  def on_event(event, &block)
167
134
  raise Scarpe::UnknownEventTypeError, "Unknown event type: #{event.inspect}!" unless EVENT_TYPES.include?(event)
135
+ return if @shutdown
168
136
 
169
- f = Fiber.new do
170
- CCInstance.instance.instance_eval(&block)
171
- end
172
- @waiting_fibers << { promise: event_promise(event), fiber: f }
137
+ @waiting_fibers << { promise: event_promise(event), fiber: cc_fiber(&block), on_event: event, block: }
173
138
  end
174
139
 
175
- def proxy_for(shoes_drawable)
176
- CCProxy.new(shoes_drawable)
177
- end
140
+ def active_fiber(&block)
141
+ return if @shutdown
178
142
 
179
- def die_after(time)
180
- t_start = Time.now
181
- @die_after = [t_start, time]
182
-
183
- @wrangler.periodic_code("scarpeTestTimeout") do |*_args|
184
- t_delta = (Time.now - t_start).to_f
185
- if t_delta > time
186
- @did_time_out = true
187
- @log.warn("die_after - timed out after #{t_delta.inspect} (threshold: #{time.inspect})")
188
- return_results(false, "Timed out!")
189
- ::Shoes::DisplayService.dispatch_event("destroy", nil)
190
- end
191
- end
143
+ p = ::Scarpe::Promise.new
144
+ p.fulfilled!
145
+ @waiting_fibers << { promise: p, fiber: cc_fiber(&block), on_event: nil, block: }
192
146
  end
193
147
 
194
148
  def wait(promise)
@@ -198,6 +152,12 @@ module Scarpe::Test
198
152
  @manager_fiber.transfer(promise)
199
153
  end
200
154
 
155
+ def yield
156
+ p = ::Scarpe::Promise.new
157
+ p.fulfilled!
158
+ @manager_fiber.transfer(p)
159
+ end
160
+
201
161
  # This returns a promise, which can be waited on using wait()
202
162
  def fully_updated
203
163
  @wrangler.promise_dom_fully_updated
@@ -218,13 +178,12 @@ module Scarpe::Test
218
178
  @wrangler.eval_js_async(js_code, timeout:)
219
179
  end
220
180
 
221
- def test_finished(return_results: true)
222
- return_assertion_data if return_results
223
-
224
- ::Shoes::DisplayService.dispatch_event("destroy", nil)
225
- end
181
+ def shut_down_shoes_code
182
+ if @shutdown
183
+ exit 0
184
+ end
226
185
 
227
- def test_finished_no_results
186
+ @shutdown = true
228
187
  ::Shoes::DisplayService.dispatch_event("destroy", nil)
229
188
  end
230
189
  end
@@ -232,8 +191,8 @@ module Scarpe::Test
232
191
  # "Cat's Cradle" is a children's game where they interlace string between
233
192
  # their fingers to make beautiful complicated shapes. The interlacing
234
193
  # of fibers made it a good name for a prototype.
235
-
236
- # An attempt at an experimental Fiber-based testing system to deal with
194
+ #
195
+ # An attempt at an experimental Fiber-based control-flow system to deal with
237
196
  # Shoes, Display and JS all at the same time.
238
197
  #
239
198
  # In general, we'll use Fiber.transfer to bounce control back and forth
@@ -243,7 +202,7 @@ module Scarpe::Test
243
202
  #
244
203
  # Ruby Fiber basic docs: https://ruby-doc.org/core-3.0.0/Fiber.html
245
204
  #
246
- # This module is mixed into a test object if we're running CatsCradle-based tests
205
+ # This module is mixed into an object to coordinate fibers app-wide.
247
206
  module CatsCradle
248
207
  attr_reader :cc_instance
249
208
 
@@ -26,38 +26,26 @@ module Scarpe::Test
26
26
  class_name ||= ENV["SHOES_MINITEST_CLASS_NAME"] || "TestShoesSpecCode"
27
27
  test_name ||= ENV["SHOES_MINITEST_METHOD_NAME"] || "test_shoes_spec"
28
28
 
29
- require_relative "cats_cradle"
30
-
31
- # We want Minitest assertions available in the test code.
32
- # But this will normally run in a subprocess. So we need
33
- # to run Minitest tests and then export the results.
34
-
35
- # We create a test object based on CatsCradle, which will
36
- # run the test as straight-line code, wait for appropriate
37
- # events and generally make things well-behaved. But the
38
- # test DSL isn't CatsCradle. It's based on Minitest and
39
- # ShoesSpecTest (see below).
40
- #
41
- # Note that that means that using CatsCradle to "bounce"
42
- # control back and forth for evented tricks isn't really
43
- # an option. We may need to revisit all of this later...
44
- test_obj = Object.new
45
- class << test_obj
46
- include Scarpe::Test::CatsCradle
47
- end
48
- Scarpe::ShoesSpecTest.test_obj = test_obj
49
- test_obj.instance_eval do
29
+ Scarpe::CCInstance.include Scarpe::ShoesSpecTest
30
+
31
+ Scarpe::CCInstance.instance.instance_eval do
50
32
  event_init
51
33
 
52
- on_heartbeat do
34
+ t_timeout = ENV["SCARPE_SSPEC_TIMEOUT"] || "30"
35
+ timeout(t_timeout.to_f) unless t_timeout.downcase == "none"
36
+
37
+ on_event(:next_heartbeat) do
53
38
  Minitest.run ARGV
54
39
 
55
- test_finished_no_results
56
- Scarpe::ShoesSpecTest.test_obj = nil
40
+ wait_after = ENV["SCARPE_SSPEC_TIMEOUT_WAIT_AFTER_TEST"]
41
+ if !(wait_after && wait_after.downcase != "n" && wait_after.downcase != "no")
42
+ shut_down_shoes_code
43
+ end
57
44
  end
58
45
  end
59
46
 
60
- test_class = Class.new(Scarpe::ShoesSpecTest)
47
+ test_class = Class.new(Minitest::Test)
48
+ test_class.include Scarpe::ShoesSpecTest
61
49
  Object.const_set(Scarpe::Components::StringHelpers.camelize(class_name), test_class)
62
50
  test_name = "test_" + test_name unless test_name.start_with?("test_")
63
51
  test_class.define_method(test_name) do
@@ -66,7 +54,6 @@ module Scarpe::Test
66
54
  end
67
55
  end
68
56
 
69
- # This is based on the CatsCradle proxies initially, but will diverge over time
70
57
  class Scarpe::ShoesSpecProxy
71
58
  attr_reader :obj
72
59
  attr_reader :linkable_id
@@ -113,12 +100,9 @@ end
113
100
 
114
101
  # When running ShoesSpec tests, we create a parent class for all of them
115
102
  # with the appropriate convenience methods and accessors.
116
- class Scarpe::ShoesSpecTest < Minitest::Test
103
+ module Scarpe::ShoesSpecTest
117
104
  include Scarpe::Test::HTMLAssertions
118
105
 
119
- class << self
120
- attr_accessor :test_obj
121
- end
122
106
  Shoes::Drawable.drawable_classes.each do |drawable_class|
123
107
  finder_name = drawable_class.dsl_name
124
108
 
@@ -141,7 +125,7 @@ class Scarpe::ShoesSpecTest < Minitest::Test
141
125
  end
142
126
 
143
127
  def catscradle_dsl(&block)
144
- Scarpe::Test::CCInstance.instance.instance_eval(&block)
128
+ Scarpe::CCInstance.instance.instance_eval(&block)
145
129
  end
146
130
 
147
131
  def dom_html
@@ -151,30 +135,25 @@ class Scarpe::ShoesSpecTest < Minitest::Test
151
135
  end
152
136
  end
153
137
 
154
- # This isn't working. Neither is calling die_after. Are the other fibers not
155
- # running or something like that? Should run a test from the command line
156
- # and see what's happening... Or check logfiles?
157
- def timeout(t_timeout = 5.0, exit_code: -1)
138
+ # A timeout won't cause an error by itself. If you want an error, make sure
139
+ # to check for a minimum number of assertions or otherwise look for progress.
140
+ def timeout(t_timeout = 5.0)
158
141
  catscradle_dsl do
159
142
  t0 = Time.now
160
143
  on_event(:every_heartbeat) do
161
144
  if Time.now - t0 >= t_timeout
162
- if exit_code == 0
163
- @log.info "Timed out after #{t_timeout} seconds!"
164
- else
165
- @log.error "Timed out after #{t_timeout} seconds!"
166
- end
167
- exit exit_code
145
+ @log.info "Timed out after #{t_timeout} seconds!"
146
+ shut_down_shoes_code
168
147
  end
169
148
  end
170
149
  end
171
150
  end
172
151
 
173
- def exit_on_first_heartbeat(exit_code: 0)
152
+ def exit_on_first_heartbeat
174
153
  catscradle_dsl do
175
154
  on_event(:next_heartbeat) do
176
155
  @log.info "Exiting on first heartbeat (exit code #{exit_code})"
177
- exit exit_code
156
+ exit 0
178
157
  end
179
158
  end
180
159
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Scarpe
4
- VERSION = "0.3.0"
4
+ VERSION = "0.4.0"
5
5
  end
data/lib/scarpe/wv/app.rb CHANGED
@@ -55,6 +55,7 @@ module Scarpe::Webview
55
55
  end
56
56
 
57
57
  def run
58
+ # This is run before the Webview event loop is up and running
58
59
  @control_interface.dispatch_event(:init)
59
60
 
60
61
  @view.empty_page = empty_page_element
data/lib/scarpe/wv/arc.rb CHANGED
@@ -2,10 +2,6 @@
2
2
 
3
3
  module Scarpe::Webview
4
4
  class Arc < Drawable
5
- def initialize(properties)
6
- super(properties)
7
- end
8
-
9
5
  def element
10
6
  render("arc")
11
7
  end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Scarpe::Webview
4
+ class Border < Drawable
5
+
6
+ def initialize(properties)
7
+ super(properties)
8
+ end
9
+
10
+ # If the drawable is intended to be overridable, add element and style to Calzini instead
11
+ def element
12
+ render('border')
13
+ end
14
+ end
15
+ end
@@ -1,15 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # The ControlInterface is used for testing. It's a way to register interest
4
- # in important events like redraw, init and shutdown, and to configure a
5
- # Shoes app for testing. Note that no part of the Scarpe framework should
6
- # ever *depend* on ControlInterface. It's for testing, not normal operation.
7
- # If no ControlInterface were ever created or called, Scarpe apps should run
8
- # fine with no modifications.
9
- #
10
- # And if you depend on this from the framework, I'll add a check-mode that
11
- # never dispatches any events to any handlers. Do NOT test me on this.
12
-
3
+ # The ControlInterface is used to coordinate events. It's a way to register interest
4
+ # in important events like redraw, init and shutdown. It's used extensively for testing.
13
5
  module Scarpe::Webview
14
6
  class ControlInterface
15
7
  include Shoes::Log
@@ -16,12 +16,12 @@ module Scarpe::Webview
16
16
  when "font"
17
17
  @fonts << args[0]
18
18
  # Can't just create font_updater and alert_updater on initialize - not everything is set up
19
- @font_updater ||= Scarpe::Webview::WebWrangler::ElementWrangler.new("root-fonts")
19
+ @font_updater ||= Scarpe::Webview::WebWrangler::ElementWrangler.new(html_id: "root-fonts")
20
20
  @font_updater.inner_html = font_contents
21
21
  when "alert"
22
22
  bind_ok_event
23
23
  @alerts << args[0]
24
- @alert_updater ||= Scarpe::Webview::WebWrangler::ElementWrangler.new("root-alerts")
24
+ @alert_updater ||= Scarpe::Webview::WebWrangler::ElementWrangler.new(html_id: "root-alerts")
25
25
  @alert_updater.inner_html = alert_contents
26
26
  else
27
27
  raise Scarpe::UnknownBuiltinCommandError, "Unexpected builtin command: #{cmd_name.inspect}!"
@@ -42,7 +42,6 @@ module Scarpe::Webview
42
42
 
43
43
  @shoes_style_names = properties.keys.map(&:to_s) - ["shoes_linkable_id"]
44
44
 
45
- # Call method, which looks up the parent
46
45
  @shoes_linkable_id = properties["shoes_linkable_id"] || properties[:shoes_linkable_id]
47
46
  unless @shoes_linkable_id
48
47
  raise Scarpe::MissingAttributeError, "Could not find property shoes_linkable_id in #{properties.inspect}!"
@@ -58,6 +57,8 @@ module Scarpe::Webview
58
57
  # Must call this before bind
59
58
  super(linkable_id: @shoes_linkable_id)
60
59
 
60
+ # This will only be used if moving a drawable from one parent to another.
61
+ # Shoes doesn't normally do that.
61
62
  bind_shoes_event(event_name: "parent", target: shoes_linkable_id) do |new_parent_id|
62
63
  display_parent = DisplayService.instance.query_display_drawable_for(new_parent_id)
63
64
  if @parent != display_parent
@@ -101,9 +102,9 @@ module Scarpe::Webview
101
102
  if hidden
102
103
  html_element.set_style("display", "none")
103
104
  else
104
- new_style = style # Get current display CSS property, which may vary by subclass
105
- disp = new_style[:display]
106
- html_element.set_style("display", disp || "block")
105
+ # With Calzini we can't easily tell what the display property should be.
106
+ # Could be flex or inline, not only block or none. Re-render this drawable.
107
+ needs_update!
107
108
  end
108
109
  end
109
110
 
@@ -143,41 +144,6 @@ module Scarpe::Webview
143
144
  needs_update!
144
145
  end
145
146
 
146
- # Convert an [r, g, b, a] array to an HTML hex color code
147
- # Arrays support alpha. HTML hex does not. So premultiply.
148
- def rgb_to_hex(color)
149
- return color if color.nil?
150
-
151
- r, g, b, a = *color
152
- if r.is_a?(Float)
153
- a ||= 1.0
154
- r_float = r * a
155
- g_float = g * a
156
- b_float = b * a
157
- else
158
- a ||= 255
159
- a_float = (a / 255.0)
160
- r_float = (r.to_f / 255.0) * a_float
161
- g_float = (g.to_f / 255.0) * a_float
162
- b_float = (b.to_f / 255.0) * a_float
163
- end
164
-
165
- r_int = (r_float * 255.0).to_i.clamp(0, 255)
166
- g_int = (g_float * 255.0).to_i.clamp(0, 255)
167
- b_int = (b_float * 255.0).to_i.clamp(0, 255)
168
-
169
- "#%0.2X%0.2X%0.2X" % [r_int, g_int, b_int]
170
- end
171
-
172
- # CSS styles
173
- def style
174
- styles = {}
175
- if @hidden
176
- styles[:display] = "none"
177
- end
178
- styles
179
- end
180
-
181
147
  public
182
148
 
183
149
  # This gets an accessor for just this element's HTML ID.
@@ -187,7 +153,7 @@ module Scarpe::Webview
187
153
  #
188
154
  # @return [Scarpe::WebWrangler::ElementWrangler] a DOM object manager
189
155
  def html_element
190
- @elt_wrangler ||= Scarpe::Webview::WebWrangler::ElementWrangler.new(html_id)
156
+ @elt_wrangler ||= Scarpe::Webview::WebWrangler::ElementWrangler.new(html_id:)
191
157
  end
192
158
 
193
159
  # Return a promise that guarantees all currently-requested changes have completed
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Scarpe::Webview
4
4
  class EditBox < Drawable
5
- attr_reader :text, :height, :width
5
+ attr_reader :text, :height, :width, :tooltip , :font
6
6
 
7
7
  def initialize(properties)
8
8
  super
@@ -11,6 +11,9 @@ module Scarpe::Webview
11
11
  bind("change") do |new_text|
12
12
  send_self_event(new_text, event_name: "change")
13
13
  end
14
+ bind("hover") do
15
+ send_self_event(event_name: "hover")
16
+ end
14
17
  end
15
18
 
16
19
  def properties_changed(changes)
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Scarpe::Webview
4
4
  class EditLine < Drawable
5
- attr_reader :text, :width
5
+ attr_reader :text, :width, :stroke, :font, :tooltip
6
6
 
7
7
  def initialize(properties)
8
8
  super
@@ -11,8 +11,11 @@ module Scarpe::Webview
11
11
  bind("change") do |new_text|
12
12
  send_self_event(new_text, event_name: "change")
13
13
  end
14
+ bind("hover") do |new_text|
15
+ send_self_event(new_text, event_name: "hover")
16
+ end
14
17
  end
15
-
18
+
16
19
  def properties_changed(changes)
17
20
  t = changes.delete("text")
18
21
  if t
@@ -1,16 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "scarpe/components/base64"
4
-
5
3
  module Scarpe::Webview
6
4
  class Image < Drawable
7
- include Scarpe::Components::Base64
8
-
9
5
  def initialize(properties)
10
6
  super
11
7
 
12
8
  unless valid_url?(@url)
13
- @url = "data:image/png;base64,#{encode_file_to_base64(@url)}"
9
+ # It's assumed to be a file path.
10
+ @url = Scarpe::Webview.asset_server.asset_url(File.expand_path @url)
14
11
  end
15
12
  end
16
13
 
@@ -10,8 +10,10 @@ module Scarpe::Webview
10
10
  end
11
11
  end
12
12
 
13
- def element
14
- render "link"
13
+ def to_calzini_hash
14
+ h = super
15
+ h[:tag] = "a"
16
+ h
15
17
  end
16
18
  end
17
19
  end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Scarpe::Webview
4
+ class Oval < Drawable
5
+ def initialize(properties)
6
+ super(properties)
7
+ end
8
+
9
+ def element(&block)
10
+ render("oval", &block)
11
+ end
12
+ end
13
+ end
@@ -61,6 +61,7 @@ module Scarpe::Webview
61
61
  private
62
62
 
63
63
  def child_markup
64
+ # The children should be only text strings or TextDrawables.
64
65
  items_to_display_children(@text_items).map do |child|
65
66
  if child.respond_to?(:to_html)
66
67
  child.to_html
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This may or may not stay. It's basically an example extension. It can be done
4
+ # better, and there's no reason it should be specific to button.
5
+ Shoes::Button.shoes_style :html_class, feature: :html
6
+
7
+ # We have a number of real Scarpe extensions that need to be properly marked as such
8
+ # and moved in here. Padding is a great example, as is html_attributes.
@@ -2,13 +2,16 @@
2
2
 
3
3
  module Scarpe::Webview
4
4
  class Shape < Drawable
5
+ # Shape is the only (?) remaining drawable that doesn't use Calzini.
6
+ # It's also kind of broken - it doesn't do what a Shoes Shape is
7
+ # supposed to do yet. This can really use a rework at some point.
5
8
  def to_html
6
9
  @children ||= []
7
10
  child_markup = @children.map(&:to_html).join
8
11
 
9
12
  color = @draw_context["fill"] || "black"
10
13
  self_markup = HTML.render do |h|
11
- h.div(id: html_id, style: style) do
14
+ h.div(id: html_id, style: shape_style) do
12
15
  h.svg(width: "400", height: "500") do
13
16
  h.path(d: path_from_shape_commands, style: "fill:#{color};stroke-width:2;")
14
17
  end
@@ -22,7 +25,7 @@ module Scarpe::Webview
22
25
  def element(&block)
23
26
  color = @draw_context["fill"] || "black"
24
27
  HTML.render do |h|
25
- h.div(id: html_id, style: style) do
28
+ h.div(id: html_id, style: shape_style) do
26
29
  h.svg(width: "400", height: "500") do
27
30
  h.path(d: path_from_shape_commands, style: "fill:#{color};stroke-width:2;")
28
31
  end
@@ -55,11 +58,13 @@ module Scarpe::Webview
55
58
 
56
59
  protected
57
60
 
58
- def style
59
- super.merge({
61
+ def shape_style
62
+ s = {
60
63
  width: "400",
61
64
  height: "900",
62
- })
65
+ }
66
+ s[:display] = "none" if @hidden
67
+ s
63
68
  end
64
69
  end
65
70
  end