scarpe 0.3.0 → 0.5.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 (297) hide show
  1. checksums.yaml +4 -4
  2. data/.cursor/rules/commit-style-preferences.mdc +72 -0
  3. data/.cursor/rules/component_context.mdc +82 -0
  4. data/.cursor/rules/debug-failed-tests.mdc +100 -0
  5. data/.cursor/rules/display_service_context.mdc +80 -0
  6. data/.cursor/rules/event_handling_context.mdc +100 -0
  7. data/.cursor/rules/git-pager-handling.mdc +64 -0
  8. data/.cursor/rules/lacci-context.mdc +52 -0
  9. data/.cursor/rules/scarpe_design_context.mdc +46 -0
  10. data/.cursor/rules/shoes_compatibility_context.mdc +75 -0
  11. data/.cursor/rules/timeout_context.mdc +78 -0
  12. data/.cursor/rules/update_lacci_and_wv.mdc +8 -0
  13. data/.cursor/rules/what_is_scarpe.mdc +22 -0
  14. data/.cursor/rules/writing-new-rules.mdc +73 -0
  15. data/CHANGELOG.md +46 -5
  16. data/CLAUDE.md +223 -0
  17. data/Gemfile +2 -2
  18. data/Gemfile.lock +85 -55
  19. data/LICENSE.txt +7 -1
  20. data/README.md +80 -20
  21. data/Rakefile +73 -14
  22. data/docs/SCARPE_FEATURES.md +38 -0
  23. data/docs/_config.yml +13 -0
  24. data/docs/calzini_components_and_updates.md +78 -0
  25. data/docs/display_service_separation.md +39 -0
  26. data/docs/documentation.md +43 -0
  27. data/docs/event_loops.md +66 -0
  28. data/docs/image.png +0 -0
  29. data/docs/index.md +118 -0
  30. data/docs/lacci.md +121 -0
  31. data/docs/scarpe_shoes_incompatibilities.md +71 -0
  32. data/docs/shoes_and_display_events.md +55 -0
  33. data/docs/shoes_implementations.md +79 -0
  34. data/docs/static/manual.md +5 -0
  35. data/docs/static/scarpe-logo.png +0 -0
  36. data/docs/timeouts_and_handlers.md +66 -0
  37. data/docs/web_archaeology.md +76 -0
  38. data/examples/Edit_box_Styles.rb +8 -0
  39. data/examples/Kerning.rb +7 -0
  40. data/examples/background_with_image.rb +14 -5
  41. data/examples/bloopsaphone/working/feepogram.rb +1 -1
  42. data/examples/bloopsaphone/working/le_dance_des_rubis.rb +135 -0
  43. data/examples/bloopsaphone/working/pixel_dreams_in_ruby.rb +131 -0
  44. data/examples/bloopsaphone/working/type_rebellion.rb +157 -0
  45. data/examples/border.rb +11 -0
  46. data/examples/check.rb +2 -0
  47. data/examples/download_and_show_image.rb +3 -0
  48. data/examples/flags/finland.rb +15 -0
  49. data/examples/flags/italy.rb +11 -0
  50. data/examples/flags/mauritius.rb +14 -0
  51. data/examples/font_family.rb +17 -0
  52. data/examples/font_shorthand.rb +9 -0
  53. data/examples/gen.rb +4 -0
  54. data/examples/internal_link_navigation.rb +19 -0
  55. data/examples/legacy/not_checked/shoes-manual/append.rb +10 -0
  56. data/examples/legacy/not_checked/shoes-manual/background_change.rb +12 -0
  57. data/examples/legacy/not_checked/shoes-manual/background_pattern.rb +5 -0
  58. data/examples/legacy/not_checked/shoes-manual/basic_app.rb +8 -0
  59. data/examples/legacy/not_checked/shoes-manual/border.rb +9 -0
  60. data/examples/legacy/not_checked/shoes-manual/builtins/FONTS.rb +5 -0
  61. data/examples/legacy/not_checked/shoes-manual/builtins/ask.rb +2 -0
  62. data/examples/legacy/not_checked/shoes-manual/builtins/ask_color.rb +5 -0
  63. data/examples/legacy/not_checked/shoes-manual/builtins/ask_open_file.rb +5 -0
  64. data/examples/legacy/not_checked/shoes-manual/builtins/ask_save_folder.rb +2 -0
  65. data/examples/legacy/not_checked/shoes-manual/builtins/confirm.rb +4 -0
  66. data/examples/legacy/not_checked/shoes-manual/builtins/debug.rb +2 -0
  67. data/examples/legacy/not_checked/shoes-manual/builtins/info.rb +3 -0
  68. data/examples/legacy/not_checked/shoes-manual/button.rb +9 -0
  69. data/examples/legacy/not_checked/shoes-manual/clear.rb +7 -0
  70. data/examples/legacy/not_checked/shoes-manual/custom_header.rb +13 -0
  71. data/examples/legacy/not_checked/shoes-manual/displace.rb +14 -0
  72. data/examples/legacy/not_checked/shoes-manual/edit_box.rb +8 -0
  73. data/examples/legacy/not_checked/shoes-manual/fill_pattern.rb +5 -0
  74. data/examples/legacy/not_checked/shoes-manual/fonts.rb +7 -0
  75. data/examples/legacy/not_checked/shoes-manual/gutter.rb +6 -0
  76. data/examples/legacy/not_checked/shoes-manual/image_web.rb +4 -0
  77. data/examples/legacy/not_checked/shoes-manual/keypress.rb +7 -0
  78. data/examples/legacy/not_checked/shoes-manual/list_box.rb +10 -0
  79. data/examples/legacy/not_checked/shoes-manual/motion.rb +10 -0
  80. data/examples/legacy/not_checked/shoes-manual/mouse.rb +8 -0
  81. data/examples/legacy/not_checked/shoes-manual/move.rb +14 -0
  82. data/examples/legacy/not_checked/shoes-manual/nested_ovals.rb +8 -0
  83. data/examples/legacy/not_checked/shoes-manual/oval.rb +7 -0
  84. data/examples/legacy/not_checked/shoes-manual/ovals.rb +6 -0
  85. data/examples/legacy/not_checked/shoes-manual/ovals_image.rb +8 -0
  86. data/examples/legacy/not_checked/shoes-manual/prepend.rb +7 -0
  87. data/examples/legacy/not_checked/shoes-manual/progress_bar.rb +10 -0
  88. data/examples/legacy/not_checked/shoes-manual/radio.rb +18 -0
  89. data/examples/legacy/not_checked/shoes-manual/radio_alternative_1.rb +7 -0
  90. data/examples/legacy/not_checked/shoes-manual/radio_alternative_2.rb +9 -0
  91. data/examples/legacy/not_checked/shoes-manual/rotate_rectangle.rb +6 -0
  92. data/examples/legacy/not_checked/shoes-manual/shape.rb +11 -0
  93. data/examples/legacy/not_checked/shoes-manual/static/avatar.png +0 -0
  94. data/examples/legacy/not_checked/shoes-manual/stroke.rb +5 -0
  95. data/examples/legacy/not_checked/shoes-manual/style.rb +3 -0
  96. data/examples/legacy/not_checked/shoes-manual/style_alternative_1.rb +4 -0
  97. data/examples/legacy/not_checked/shoes-manual/style_alternative_2.rb +5 -0
  98. data/examples/legacy/not_checked/shoes-manual/style_length.rb +5 -0
  99. data/examples/legacy/not_checked/shoes-manual/timer.rb +6 -0
  100. data/examples/legacy/not_checked/shoes-manual/trigger_window.rb +8 -0
  101. data/examples/legacy/not_checked/shoes-manual/window_owner.rb +8 -0
  102. data/examples/legacy/working/shoes_manual/alert_button.rb +2 -0
  103. data/examples/legacy/working/shoes_manual/animate.rb +7 -0
  104. data/examples/legacy/working/shoes_manual/background_para.rb +4 -0
  105. data/examples/legacy/working/shoes_manual/button_alternative.rb +7 -0
  106. data/examples/legacy/working/shoes_manual/checkbox.rb +17 -0
  107. data/examples/legacy/working/shoes_manual/download.rb +12 -0
  108. data/examples/legacy/working/shoes_manual/edit_box.rb +6 -0
  109. data/examples/legacy/working/shoes_manual/editline.rb +7 -0
  110. data/examples/legacy/working/shoes_manual/fixed_height.rb +8 -0
  111. data/examples/legacy/working/shoes_manual/fixed_width.rb +12 -0
  112. data/examples/legacy/working/shoes_manual/image.rb +5 -0
  113. data/examples/legacy/working/shoes_manual/instance_variable_check.rb +10 -0
  114. data/examples/legacy/working/shoes_manual/message.rb +18 -0
  115. data/examples/legacy/working/shoes_manual/rectangle.rb +6 -0
  116. data/examples/legacy/working/shoes_manual/save_download.rb +12 -0
  117. data/examples/legacy/working/shoes_manual/self_check.rb +10 -0
  118. data/examples/legacy/working/shoes_manual/stack.rb +7 -0
  119. data/examples/legacy/working/shoes_manual/style_info.rb +8 -0
  120. data/examples/legacy/working/shoes_manual/utf8_support.rb +8 -0
  121. data/examples/legacy/working/shoes_manual/width.rb +4 -0
  122. data/examples/local_assets/multi_image.rb +5 -0
  123. data/examples/local_assets/small.png +0 -0
  124. data/examples/local_fonts.rb +3 -0
  125. data/examples/margin.rb +13 -0
  126. data/examples/margin_check.rb +27 -0
  127. data/examples/oval-with-kwargs.rb +3 -0
  128. data/examples/oval.rb +26 -0
  129. data/examples/page_navigation_single_app.rb +42 -0
  130. data/examples/para_font_styles.rb +17 -0
  131. data/examples/para_font_variant.rb +6 -0
  132. data/examples/para_fontweight.rb +13 -0
  133. data/examples/parse_xl_funnies.rb +3 -0
  134. data/examples/rect.rb +1 -1
  135. data/examples/scarpe_ext.rb +3 -0
  136. data/examples/shapes/star.rb +1 -3
  137. data/examples/shoes_subclass_app.rb +25 -0
  138. data/examples/spacing.rb +1 -1
  139. data/examples/span.rb +4 -2
  140. data/examples/url_routing_example.rb +67 -0
  141. data/lacci/Gemfile +0 -2
  142. data/lacci/Gemfile.lock +4 -32
  143. data/lacci/lacci.gemspec +3 -3
  144. data/lacci/lib/lacci/scarpe_cli.rb +0 -1
  145. data/lacci/lib/lacci/version.rb +1 -1
  146. data/lacci/lib/scarpe/niente/app.rb +12 -1
  147. data/lacci/lib/scarpe/niente/display_service.rb +5 -1
  148. data/lacci/lib/scarpe/niente/drawable.rb +2 -0
  149. data/lacci/lib/scarpe/niente/shoes_spec.rb +10 -5
  150. data/lacci/lib/scarpe/niente.rb +15 -2
  151. data/lacci/lib/shoes/app.rb +204 -105
  152. data/lacci/lib/shoes/constants.rb +24 -2
  153. data/lacci/lib/shoes/display_service.rb +43 -4
  154. data/lacci/lib/shoes/drawable.rb +326 -36
  155. data/lacci/lib/shoes/drawables/arc.rb +4 -26
  156. data/lacci/lib/shoes/drawables/arrow.rb +3 -23
  157. data/lacci/lib/shoes/drawables/border.rb +28 -0
  158. data/lacci/lib/shoes/drawables/button.rb +5 -21
  159. data/lacci/lib/shoes/drawables/check.rb +7 -3
  160. data/lacci/lib/shoes/drawables/document_root.rb +4 -4
  161. data/lacci/lib/shoes/drawables/edit_box.rb +6 -5
  162. data/lacci/lib/shoes/drawables/edit_line.rb +5 -4
  163. data/lacci/lib/shoes/drawables/flow.rb +4 -6
  164. data/lacci/lib/shoes/drawables/font_helper.rb +62 -0
  165. data/lacci/lib/shoes/drawables/image.rb +2 -2
  166. data/lacci/lib/shoes/drawables/line.rb +3 -6
  167. data/lacci/lib/shoes/drawables/link.rb +16 -9
  168. data/lacci/lib/shoes/drawables/list_box.rb +8 -5
  169. data/lacci/lib/shoes/drawables/oval.rb +48 -0
  170. data/lacci/lib/shoes/drawables/para.rb +106 -18
  171. data/lacci/lib/shoes/drawables/progress.rb +2 -1
  172. data/lacci/lib/shoes/drawables/radio.rb +5 -3
  173. data/lacci/lib/shoes/drawables/rect.rb +7 -6
  174. data/lacci/lib/shoes/drawables/shape.rb +4 -3
  175. data/lacci/lib/shoes/drawables/slot.rb +102 -9
  176. data/lacci/lib/shoes/drawables/stack.rb +7 -12
  177. data/lacci/lib/shoes/drawables/star.rb +9 -31
  178. data/lacci/lib/shoes/drawables/text_drawable.rb +93 -34
  179. data/lacci/lib/shoes/drawables/video.rb +3 -2
  180. data/lacci/lib/shoes/drawables/widget.rb +9 -4
  181. data/lacci/lib/shoes/drawables.rb +2 -1
  182. data/lacci/lib/shoes/errors.rb +13 -3
  183. data/lacci/lib/shoes/margin_helper.rb +79 -0
  184. data/lacci/lib/shoes.rb +98 -20
  185. data/lacci/test/.gitignore +1 -0
  186. data/lacci/test/test_draw_context.rb +167 -0
  187. data/lacci/test/test_font_helper.rb +57 -0
  188. data/lacci/test/test_helper.rb +31 -4
  189. data/lacci/test/test_lacci.rb +93 -6
  190. data/lacci/test/test_margin_helper.rb +82 -0
  191. data/lacci/test/test_niente_test_infra.rb +40 -0
  192. data/lacci/test/test_oval.rb +82 -0
  193. data/lacci/test/test_parenting.rb +140 -0
  194. data/lacci/test/test_shoes_errors.rb +15 -13
  195. data/lacci/test/test_text_drawables.rb +23 -0
  196. data/lib/scarpe/assets.rb +19 -0
  197. data/lib/scarpe/cats_cradle.rb +57 -98
  198. data/lib/scarpe/shoes_spec.rb +24 -44
  199. data/lib/scarpe/version.rb +1 -1
  200. data/lib/scarpe/wv/app.rb +1 -0
  201. data/lib/scarpe/wv/arc.rb +0 -4
  202. data/lib/scarpe/wv/border.rb +15 -0
  203. data/lib/scarpe/wv/control_interface.rb +2 -10
  204. data/lib/scarpe/wv/document_root.rb +2 -2
  205. data/lib/scarpe/wv/drawable.rb +6 -40
  206. data/lib/scarpe/wv/edit_box.rb +4 -1
  207. data/lib/scarpe/wv/edit_line.rb +4 -1
  208. data/lib/scarpe/wv/image.rb +2 -5
  209. data/lib/scarpe/wv/link.rb +4 -2
  210. data/lib/scarpe/wv/oval.rb +13 -0
  211. data/lib/scarpe/wv/para.rb +1 -0
  212. data/lib/scarpe/wv/scarpe_extensions.rb +8 -0
  213. data/lib/scarpe/wv/shape.rb +10 -5
  214. data/lib/scarpe/wv/text_drawable.rb +72 -14
  215. data/lib/scarpe/wv/web_wrangler.rb +33 -11
  216. data/lib/scarpe/wv/webview_local_display.rb +6 -2
  217. data/lib/scarpe/wv.rb +16 -2
  218. data/scarpe-components/Gemfile +4 -3
  219. data/scarpe-components/Gemfile.lock +6 -37
  220. data/scarpe-components/README.md +2 -2
  221. data/scarpe-components/assets/bootstrap-themes/bootstrap-cerulean.css +12229 -0
  222. data/scarpe-components/assets/bootstrap-themes/bootstrap-cosmo.css +11810 -0
  223. data/scarpe-components/assets/bootstrap-themes/bootstrap-cyborg.css +12210 -0
  224. data/scarpe-components/assets/bootstrap-themes/bootstrap-darkly.css +12153 -0
  225. data/scarpe-components/assets/bootstrap-themes/bootstrap-flatly.css +12126 -0
  226. data/scarpe-components/assets/bootstrap-themes/bootstrap-icons.min.css +5 -0
  227. data/scarpe-components/assets/bootstrap-themes/bootstrap-journal.css +12099 -0
  228. data/scarpe-components/assets/bootstrap-themes/bootstrap-litera.css +12211 -0
  229. data/scarpe-components/assets/bootstrap-themes/bootstrap-lumen.css +12369 -0
  230. data/scarpe-components/assets/bootstrap-themes/bootstrap-lux.css +11928 -0
  231. data/scarpe-components/assets/bootstrap-themes/bootstrap-materia.css +13184 -0
  232. data/scarpe-components/assets/bootstrap-themes/bootstrap-minty.css +12177 -0
  233. data/scarpe-components/assets/bootstrap-themes/bootstrap-morph.css +12750 -0
  234. data/scarpe-components/assets/bootstrap-themes/bootstrap-pulse.css +11890 -0
  235. data/scarpe-components/assets/bootstrap-themes/bootstrap-quartz.css +12622 -0
  236. data/scarpe-components/assets/bootstrap-themes/bootstrap-sandstone.css +12201 -0
  237. data/scarpe-components/assets/bootstrap-themes/bootstrap-simplex.css +12186 -0
  238. data/scarpe-components/assets/bootstrap-themes/bootstrap-sketchy.css +12451 -0
  239. data/scarpe-components/assets/bootstrap-themes/bootstrap-slate.css +12492 -0
  240. data/scarpe-components/assets/bootstrap-themes/bootstrap-solar.css +12149 -0
  241. data/scarpe-components/assets/bootstrap-themes/bootstrap-spacelab.css +12266 -0
  242. data/scarpe-components/assets/bootstrap-themes/bootstrap-superhero.css +12216 -0
  243. data/scarpe-components/assets/bootstrap-themes/bootstrap-united.css +12077 -0
  244. data/scarpe-components/assets/bootstrap-themes/bootstrap-vapor.css +12549 -0
  245. data/scarpe-components/assets/bootstrap-themes/bootstrap-yeti.css +12325 -0
  246. data/scarpe-components/assets/bootstrap-themes/bootstrap-zephyr.css +12283 -0
  247. data/scarpe-components/assets/bootstrap-themes/bootstrap.bundle.min.js +7 -0
  248. data/scarpe-components/lib/scarpe/components/asset_server.rb +219 -0
  249. data/scarpe-components/lib/scarpe/components/base64.rb +22 -0
  250. data/scarpe-components/lib/scarpe/components/calzini/{art_widgets.rb → art_drawables.rb} +42 -18
  251. data/scarpe-components/lib/scarpe/components/calzini/border.rb +38 -0
  252. data/scarpe-components/lib/scarpe/components/calzini/button.rb +6 -8
  253. data/scarpe-components/lib/scarpe/components/calzini/misc.rb +14 -16
  254. data/scarpe-components/lib/scarpe/components/calzini/para.rb +218 -11
  255. data/scarpe-components/lib/scarpe/components/calzini/slots.rb +16 -60
  256. data/scarpe-components/lib/scarpe/components/calzini.rb +88 -1
  257. data/scarpe-components/lib/scarpe/components/errors.rb +4 -0
  258. data/scarpe-components/lib/scarpe/components/html.rb +4 -1
  259. data/scarpe-components/lib/scarpe/components/minitest_export_reporter.rb +11 -3
  260. data/scarpe-components/lib/scarpe/components/minitest_result.rb +41 -0
  261. data/scarpe-components/lib/scarpe/components/port_helpers.rb +30 -0
  262. data/scarpe-components/lib/scarpe/components/print_logger.rb +17 -2
  263. data/scarpe-components/lib/scarpe/components/process_helpers.rb +37 -0
  264. data/scarpe-components/lib/scarpe/components/segmented_file_loader.rb +1 -1
  265. data/scarpe-components/lib/scarpe/components/tiranti.rb +42 -100
  266. data/scarpe-components/lib/scarpe/components/unit_test_helpers.rb +3 -1
  267. data/scarpe-components/lib/scarpe/components/version.rb +1 -1
  268. data/scarpe-components/scarpe-components.gemspec +1 -1
  269. data/scarpe-components/test/assets/big-image.png +0 -0
  270. data/scarpe-components/test/assets/big-stylesheet.css +497 -0
  271. data/scarpe-components/test/assets/little-image.png +0 -0
  272. data/scarpe-components/test/assets/little-stylesheet.css +1 -0
  273. data/scarpe-components/test/calzini/test_calzini_art_drawables.rb +7 -7
  274. data/scarpe-components/test/calzini/test_calzini_button.rb +7 -5
  275. data/scarpe-components/test/calzini/test_calzini_misc.rb +9 -9
  276. data/scarpe-components/test/calzini/test_calzini_para.rb +6 -9
  277. data/scarpe-components/test/calzini/test_calzini_slots.rb +12 -57
  278. data/scarpe-components/test/calzini/test_calzini_text_drawables.rb +83 -18
  279. data/scarpe-components/test/calzini/test_various.rb +133 -0
  280. data/scarpe-components/test/test_asset_server.rb +72 -0
  281. data/scarpe-components/test/test_components.rb +31 -2
  282. data/scarpe-components/test/test_helper.rb +0 -1
  283. data/scarpe-components/test/test_minitest_result.rb +7 -0
  284. data/scarpe-components/test/test_port_helpers.rb +12 -0
  285. data/scarpe-components/test/test_segmented_app_files.rb +2 -0
  286. data/tasks/check_html_fixtures.rb +140 -0
  287. data/tasks/regenerate_html_fixtures.rb +104 -0
  288. data/templates/class_template_with_shapes.erb +0 -11
  289. metadata +225 -39
  290. data/.rubocop.yml +0 -88
  291. data/lacci/lib/scarpe/niente/logger.rb +0 -29
  292. data/lacci/lib/shoes/drawables/span.rb +0 -27
  293. data/lacci/lib/shoes/spacing.rb +0 -9
  294. data/lib/scarpe/evented_assertions.rb +0 -121
  295. data/lib/scarpe/wv/span.rb +0 -44
  296. data/scarpe-components/lib/scarpe/components/calzini/text_widgets.rb +0 -65
  297. /data/examples/legacy/{not_checked → working}/shoes3-tests/editline/editline.rb +0 -0
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "test_helper"
4
+
5
+ class TestNienteTestInfra < NienteTest
6
+ def test_app_fail_in_test
7
+ run_test_niente_code(<<~SHOES_APP, app_test_code: <<~SHOES_SPEC, expect_process_fail: true)
8
+ Shoes.app do
9
+ @b = button "OK"
10
+ raise "ERROR!"
11
+ end
12
+ SHOES_APP
13
+ assert_equal true, true
14
+ SHOES_SPEC
15
+ end
16
+
17
+ def test_app_fail_in_spec
18
+ run_test_niente_code(<<~SHOES_APP, app_test_code: <<~SHOES_SPEC, expect_minitest_exception: true)
19
+ Shoes.app do
20
+ @b = button "OK"
21
+ end
22
+ SHOES_APP
23
+ raise "ERROR!"
24
+ SHOES_SPEC
25
+ end
26
+
27
+ def test_multi_app_find
28
+ run_test_niente_code(<<~SHOES_APP, app_test_code: <<~SHOES_SPEC)
29
+ Shoes.app do
30
+ @b = button "OK"
31
+ end
32
+ Shoes.app do
33
+ @b2 = button "Nope"
34
+ end
35
+ SHOES_APP
36
+ assert_equal "OK", button("@b").text
37
+ assert_equal "Nope", button("@b2").text
38
+ SHOES_SPEC
39
+ end
40
+ end
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "test_helper"
4
+
5
+ class TestLacciOval < NienteTest
6
+ # For an oval, the args go left, top, radius, height
7
+ def test_simple_oval_values
8
+ run_test_niente_code(<<~SHOES_APP, app_test_code: <<~SHOES_SPEC)
9
+ Shoes.app do
10
+ oval 5, 10, 25 # circle with radius 25 with its upper-left point at 5, 10
11
+ end
12
+ SHOES_APP
13
+ ov = oval()
14
+ assert_equal 5, ov.left
15
+ assert_equal 10, ov.top
16
+ assert_equal 25, ov.radius
17
+ assert_equal 50, ov.width
18
+ assert_equal 50, ov.height
19
+ SHOES_SPEC
20
+ end
21
+
22
+ def test_oval_with_height
23
+ run_test_niente_code(<<~SHOES_APP, app_test_code: <<~SHOES_SPEC)
24
+ Shoes.app do
25
+ oval 5, 10, 25, 35 # oval with radius 25, 50 wide, 35 tall
26
+ end
27
+ SHOES_APP
28
+ ov = oval()
29
+ assert_equal 5, ov.left
30
+ assert_equal 10, ov.top
31
+ assert_equal 25, ov.radius
32
+ assert_equal 50, ov.width
33
+ assert_equal 35, ov.height
34
+ SHOES_SPEC
35
+ end
36
+
37
+ def test_simple_oval_keyword_values
38
+ run_test_niente_code(<<~SHOES_APP, app_test_code: <<~SHOES_SPEC)
39
+ Shoes.app do
40
+ oval left: 5, top: 10, radius: 25
41
+ end
42
+ SHOES_APP
43
+ ov = oval()
44
+ assert_equal 5, ov.left
45
+ assert_equal 10, ov.top
46
+ assert_equal 25, ov.radius
47
+ assert_equal 50, ov.height
48
+ assert_equal 50, ov.width
49
+ SHOES_SPEC
50
+ end
51
+
52
+ def test_oval_keywords_with_height_but_no_radius
53
+ run_test_niente_code(<<~SHOES_APP, app_test_code: <<~SHOES_SPEC)
54
+ Shoes.app do
55
+ oval left: 5, top: 10, height: 25
56
+ end
57
+ SHOES_APP
58
+ ov = oval()
59
+ assert_equal 5, ov.left
60
+ assert_equal 10, ov.top
61
+ assert_equal 12, ov.radius
62
+ assert_equal 25, ov.height
63
+ assert_equal 25, ov.width
64
+ SHOES_SPEC
65
+ end
66
+
67
+ def test_oval_strokewidth
68
+ run_test_niente_code(<<~SHOES_APP, app_test_code: <<~SHOES_SPEC)
69
+ Shoes.app do
70
+ strokewidth 3
71
+ oval 5, 10, 25
72
+ end
73
+ SHOES_APP
74
+ ov = oval()
75
+ assert_equal 5, ov.left
76
+ assert_equal 10, ov.top
77
+ assert_equal 25, ov.radius
78
+ assert_equal 3, ov.draw_context["strokewidth"]
79
+ # assert_equal 3, ov.strokewidth # This should work but doesn't yet, see issue #476
80
+ SHOES_SPEC
81
+ end
82
+ end
@@ -0,0 +1,140 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "test_helper"
4
+
5
+ class TestParenting < NienteTest
6
+ def test_simple_button
7
+ run_test_niente_code(<<~SHOES_APP, app_test_code: <<~SHOES_SPEC)
8
+ Shoes.app do
9
+ button "OK"
10
+ end
11
+ SHOES_APP
12
+ # Test that Lacci has set parents properly
13
+ doc_root = button().parent
14
+ assert_equal Shoes::DocumentRoot, doc_root.class
15
+ assert_equal [button().obj], doc_root.contents
16
+
17
+ # Test that Niente has set parents properly
18
+ assert_equal "DocumentRoot", button().display.parent.shoes_type
19
+ SHOES_SPEC
20
+ end
21
+
22
+ def test_button_in_stack
23
+ run_test_niente_code(<<~SHOES_APP, app_test_code: <<~SHOES_SPEC)
24
+ Shoes.app do
25
+ stack do
26
+ button "OK"
27
+ end
28
+ end
29
+ SHOES_APP
30
+ # Test that Lacci has set parents properly
31
+ assert_equal Shoes::DocumentRoot, stack().parent.class
32
+ assert_equal Shoes::Stack, button().parent.class
33
+ assert_equal [button().obj], stack().contents
34
+
35
+ # Test that Niente has set parents properly
36
+ assert_equal "DocumentRoot", stack().display.parent.shoes_type
37
+ assert_equal "Stack", button().display.parent.shoes_type
38
+ assert_equal [button().display], stack().display.children
39
+ SHOES_SPEC
40
+ end
41
+
42
+ # We had a bug with this. It wasn't setting @children properly.
43
+ def test_clear_with_no_contents
44
+ run_test_niente_code(<<~SHOES_APP, app_test_code: <<~SHOES_SPEC)
45
+ Shoes.app do
46
+ @s = stack do
47
+ end
48
+ button "Clear" do
49
+ @s.clear do
50
+ para "cleared"
51
+ end
52
+ end
53
+ end
54
+ SHOES_APP
55
+ button().trigger_click
56
+ assert_equal "cleared", para.text
57
+ SHOES_SPEC
58
+ end
59
+
60
+ def test_stack_clear
61
+ run_test_niente_code(<<~SHOES_APP, app_test_code: <<~SHOES_SPEC)
62
+ Shoes.app do
63
+ @s = stack do
64
+ @p = para "Here"
65
+ end
66
+ button "Clear" do
67
+ @s.clear
68
+ end
69
+ end
70
+ SHOES_APP
71
+ button.trigger_click
72
+ assert_equal [], stack.contents
73
+ SHOES_SPEC
74
+ end
75
+
76
+ def test_drawable_remove
77
+ run_test_niente_code(<<~SHOES_APP, app_test_code: <<~SHOES_SPEC)
78
+ Shoes.app do
79
+ @s = stack do
80
+ @p = para "Here"
81
+ end
82
+ button "Clear" do
83
+ @p.remove
84
+ end
85
+ end
86
+ SHOES_APP
87
+ p = para # grab it while it's still there
88
+ button.trigger_click
89
+ assert_equal [], stack.contents
90
+ assert_nil p.parent
91
+ SHOES_SPEC
92
+ end
93
+
94
+ # I don't think Shoes does this. We have to use Lacci-specific methods.
95
+ # It's still good to have a test for it.
96
+ def test_drawable_reparent
97
+ run_test_niente_code(<<~SHOES_APP, app_test_code: <<~SHOES_SPEC)
98
+ Shoes.app do
99
+ @s1 = stack do
100
+ @p = para "Move me"
101
+ end
102
+
103
+ @s2 = stack do
104
+ end
105
+
106
+ button "Move It!" do
107
+ @p.set_parent(@s2)
108
+ end
109
+ end
110
+ SHOES_APP
111
+ button.trigger_click
112
+
113
+ # Check parents in Lacci
114
+ assert_equal [], stack("@s1").contents
115
+ assert_equal stack("@s2").obj, para.parent
116
+ assert_equal [para.obj], stack("@s2").contents
117
+
118
+ # Check parents in Niente
119
+ assert_equal [], stack("@s1").display.children
120
+ assert_equal stack("@s2").display, para.display.parent
121
+ assert_equal [para.display], stack("@s2").display.children
122
+ SHOES_SPEC
123
+ end
124
+
125
+ def test_add_to_non_current_slot
126
+ run_test_niente_code(<<~SHOES_APP, app_test_code: <<~SHOES_SPEC)
127
+ Shoes.app do
128
+ @s = stack do
129
+ end
130
+ button "Add a Button" do
131
+ @ok_button = @s.button "OK"
132
+ end
133
+ end
134
+ SHOES_APP
135
+ button.trigger_click
136
+ assert_equal [button("@ok_button").obj], stack.contents
137
+ assert_equal stack.obj, button("@ok_button").parent
138
+ SHOES_SPEC
139
+ end
140
+ end
@@ -17,19 +17,21 @@ class TestShoesErrors < NienteTest
17
17
  SHOES_SPEC
18
18
  end
19
19
 
20
- def test_too_many_instances_error
21
- run_test_niente_code(<<~SHOES_APP, app_test_code: <<~SHOES_SPEC)
22
- $ruby_main = self
23
- Shoes.app do
24
- end
25
- SHOES_APP
26
- assert_raises Shoes::Errors::TooManyInstancesError do
27
- $ruby_main.instance_eval do
28
- Shoes.app {}
29
- end
30
- end
31
- SHOES_SPEC
32
- end
20
+ # Niente can no longer test the TooManyInstancesError because it now
21
+ # supports multiple Shoes apps.
22
+ #def test_too_many_instances_error
23
+ # run_test_niente_code(<<~SHOES_APP, app_test_code: <<~SHOES_SPEC)
24
+ # $ruby_main = self
25
+ # Shoes.app do
26
+ # end
27
+ # SHOES_APP
28
+ # assert_raises Shoes::Errors::TooManyInstancesError do
29
+ # $ruby_main.instance_eval do
30
+ # Shoes.app {}
31
+ # end
32
+ # end
33
+ # SHOES_SPEC
34
+ #end
33
35
 
34
36
  def test_drawables_found_errors
35
37
  run_test_niente_code(<<~SHOES_APP, app_test_code: <<~SHOES_SPEC)
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "test_helper"
4
+
5
+ class TestTextDrawables < NienteTest
6
+ def test_simple_button
7
+ run_test_niente_code(<<~'SHOES_APP', app_test_code: <<~'SHOES_SPEC')
8
+ Shoes.app do
9
+ para "These are ", em("emphatically"), " ", strong("strongly"), " text drawables!"
10
+ end
11
+ SHOES_APP
12
+ assert_equal "These are emphatically strongly text drawables!", para.text
13
+
14
+ # Test that Lacci has set parents properly
15
+ assert_equal Shoes::DocumentRoot, para.parent.class
16
+ assert_equal [Shoes::Para], para.parent.contents.map(&:class)
17
+
18
+ # Test that Niente has set parents properly
19
+ assert_equal "DocumentRoot", para().display.parent.shoes_type
20
+ assert_equal ["Para"], document_root.display.children.map(&:shoes_type), "Doc root should have only para as a child!"
21
+ SHOES_SPEC
22
+ end
23
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "scarpe/components/asset_server"
4
+
5
+ module Scarpe::Webview
6
+ def self.asset_server
7
+ return @asset_server if @asset_server
8
+
9
+ # A Scarpe Webview application can have only a single Shoes::App instance.
10
+ @asset_server = Scarpe::Components::AssetServer.new app_dir: Shoes.APPS[0].dir
11
+
12
+ # at_exit doesn't work reliably under webview. Give this a try.
13
+ ::Scarpe::Webview::DisplayService.instance.control_interface.on_event(:shutdown) do
14
+ @asset_server&.kill_server
15
+ end
16
+
17
+ @asset_server
18
+ end
19
+ end
@@ -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