scarpe 0.1.0 → 0.2.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 (530) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +80 -9
  3. data/.ruby-version +1 -0
  4. data/.vscode/extensions.json +5 -0
  5. data/.yardopts +3 -0
  6. data/CHANGELOG.md +14 -0
  7. data/CONTRIBUTING.md +20 -0
  8. data/Gemfile +14 -2
  9. data/README.md +138 -18
  10. data/Rakefile +2 -3
  11. data/dev.yml +7 -0
  12. data/docs/static/PKGBUILD +47 -0
  13. data/docs/static/Shoes.icns +0 -0
  14. data/docs/static/avatar.png +0 -0
  15. data/docs/static/code_highlighter.js +188 -0
  16. data/docs/static/code_highlighter_ruby.js +26 -0
  17. data/docs/static/icon-debug.png +0 -0
  18. data/docs/static/icon-error.png +0 -0
  19. data/docs/static/icon-info.png +0 -0
  20. data/docs/static/icon-warn.png +0 -0
  21. data/docs/static/listbox_button1.png +0 -0
  22. data/docs/static/listbox_button2.png +0 -0
  23. data/docs/static/man-app.png +0 -0
  24. data/docs/static/man-builds.png +0 -0
  25. data/docs/static/man-builds1.png +0 -0
  26. data/docs/static/man-editor-notepad.png +0 -0
  27. data/docs/static/man-editor-osx.png +0 -0
  28. data/docs/static/man-ele-background.png +0 -0
  29. data/docs/static/man-ele-border.png +0 -0
  30. data/docs/static/man-ele-button.png +0 -0
  31. data/docs/static/man-ele-check.png +0 -0
  32. data/docs/static/man-ele-editbox.png +0 -0
  33. data/docs/static/man-ele-editline.png +0 -0
  34. data/docs/static/man-ele-image.png +0 -0
  35. data/docs/static/man-ele-listbox.png +0 -0
  36. data/docs/static/man-ele-progress.png +0 -0
  37. data/docs/static/man-ele-radio.png +0 -0
  38. data/docs/static/man-ele-shape.png +0 -0
  39. data/docs/static/man-ele-textblock.png +0 -0
  40. data/docs/static/man-ele-video.png +0 -0
  41. data/docs/static/man-intro-dmg.png +0 -0
  42. data/docs/static/man-intro-exe.png +0 -0
  43. data/docs/static/man-look-tiger.png +0 -0
  44. data/docs/static/man-look-ubuntu.png +0 -0
  45. data/docs/static/man-look-vista.png +0 -0
  46. data/docs/static/man-run-osx.png +0 -0
  47. data/docs/static/man-run-vista.png +0 -0
  48. data/docs/static/man-run-xp.png +0 -0
  49. data/docs/static/man-shot1.png +0 -0
  50. data/docs/static/manual-en.txt +3529 -0
  51. data/docs/static/manual-ja.txt +2829 -0
  52. data/docs/static/manual.css +171 -0
  53. data/docs/static/manual.md +3528 -0
  54. data/docs/static/menu-corner1.png +0 -0
  55. data/docs/static/menu-corner2.png +0 -0
  56. data/docs/static/menu-gray.png +0 -0
  57. data/docs/static/menu-left.png +0 -0
  58. data/docs/static/menu-right.png +0 -0
  59. data/docs/static/menu-top.png +0 -0
  60. data/docs/static/shoes-dmg.jpg +0 -0
  61. data/docs/static/shoes-icon-blue.png +0 -0
  62. data/docs/static/shoes-icon.png +0 -0
  63. data/docs/static/shoes-manual-apps.gif +0 -0
  64. data/docs/static/shoes_main_window.png +0 -0
  65. data/docs/static/stripe.png +0 -0
  66. data/docs/static/stubs/blank.exe +0 -0
  67. data/docs/static/stubs/blank.hfz +0 -0
  68. data/docs/static/stubs/blank.run +375 -0
  69. data/docs/static/stubs/cocoa-install +0 -0
  70. data/docs/static/stubs/sh-install +49 -0
  71. data/docs/static/stubs/shoes-stub-inject.exe +0 -0
  72. data/docs/static/stubs/shoes-stub.exe +0 -0
  73. data/docs/static/tutor-back.png +0 -0
  74. data/examples/bloopsaphone/working/1901_by_Aanand_Prasad.rb +478 -0
  75. data/examples/bloopsaphone/working/b1.rb +64 -0
  76. data/examples/bloopsaphone/working/b2.rb +36 -0
  77. data/examples/bloopsaphone/working/bloops_test.rb +41 -0
  78. data/examples/bloopsaphone/working/bloopsaphone_theme_song_by_why.rb +31 -0
  79. data/examples/bloopsaphone/working/feepogram.rb +67 -0
  80. data/examples/bloopsaphone/working/simpsons_theme_song_by_why.rb +14 -0
  81. data/examples/bloopsaphone/working/tune_cheeky_drat.rb +210 -0
  82. data/examples/button.rb +6 -5
  83. data/examples/button_alert.rb +6 -0
  84. data/examples/button_go_away.rb +6 -0
  85. data/examples/button_with_position_and_size.rb +7 -0
  86. data/examples/coffee.rb +14 -0
  87. data/examples/download.rb +5 -0
  88. data/examples/edit_box.rb +10 -0
  89. data/examples/edit_line.rb +8 -0
  90. data/examples/fill.rb +25 -0
  91. data/examples/flow.rb +11 -0
  92. data/examples/fonts.rb +6 -0
  93. data/examples/gen.rb +140 -0
  94. data/examples/hello_world.rb +2 -4
  95. data/examples/highlander.rb +87 -0
  96. data/examples/image/clickable_image.rb +5 -0
  97. data/examples/{image.rb → image/image.rb} +2 -4
  98. data/examples/image/image_size.rb +7 -0
  99. data/examples/image/image_with_position_and_size.rb +3 -0
  100. data/examples/info.rb +9 -0
  101. data/examples/legacy/not_checked/expert/colours.rb +105 -0
  102. data/examples/legacy/not_checked/expert/curve-animation.rb +31 -0
  103. data/examples/legacy/not_checked/expert/curve-control-point.rb +51 -0
  104. data/examples/legacy/not_checked/expert/custom-list-box.rb +53 -0
  105. data/examples/legacy/not_checked/expert/definr.rb +23 -0
  106. data/examples/legacy/not_checked/expert/funnies.rb +56 -0
  107. data/examples/legacy/not_checked/expert/minesweeper.rb +267 -0
  108. data/examples/legacy/not_checked/expert/othello.rb +318 -0
  109. data/examples/legacy/not_checked/expert/pong.rb +62 -0
  110. data/examples/legacy/not_checked/expert/tankspank.rb +385 -0
  111. data/examples/legacy/not_checked/expert/tooltips.rb +45 -0
  112. data/examples/legacy/not_checked/expert/url.rb +37 -0
  113. data/examples/legacy/not_checked/expert/video-player.rb +256 -0
  114. data/examples/legacy/not_checked/good/_why-stories.rb +44 -0
  115. data/examples/legacy/not_checked/good/_why-stories.yaml +387 -0
  116. data/examples/legacy/not_checked/good/arc.rb +37 -0
  117. data/examples/legacy/not_checked/good/cardflip.rb +141 -0
  118. data/examples/legacy/not_checked/good/clock.rb +51 -0
  119. data/examples/legacy/not_checked/good/console.rb +21 -0
  120. data/examples/legacy/not_checked/good/follow.rb +26 -0
  121. data/examples/legacy/not_checked/good/image-rotate.rb +14 -0
  122. data/examples/legacy/not_checked/good/paris.svg +7236 -0
  123. data/examples/legacy/not_checked/good/path-animation.rb +46 -0
  124. data/examples/legacy/not_checked/good/plots.rb +100 -0
  125. data/examples/legacy/not_checked/good/reminder.rb +174 -0
  126. data/examples/legacy/not_checked/good/svgview.rb +113 -0
  127. data/examples/legacy/not_checked/good/vjot.rb +56 -0
  128. data/examples/legacy/not_checked/shoes-contrib/.gitignore +2 -0
  129. data/examples/legacy/not_checked/shoes-contrib/README.md +34 -0
  130. data/examples/legacy/not_checked/shoes-contrib/animation/animate-ovals.rb +21 -0
  131. data/examples/legacy/not_checked/shoes-contrib/animation/flowers.rb +59 -0
  132. data/examples/legacy/not_checked/shoes-contrib/animation/happy-trails.rb +31 -0
  133. data/examples/legacy/not_checked/shoes-contrib/animation/mice-satellites.rb +27 -0
  134. data/examples/legacy/not_checked/shoes-contrib/animation/oval-motion.rb +12 -0
  135. data/examples/legacy/not_checked/shoes-contrib/animation/pink-bubbles.rb +34 -0
  136. data/examples/legacy/not_checked/shoes-contrib/animation/pulsate.rb +18 -0
  137. data/examples/legacy/not_checked/shoes-contrib/animation/rotating-star.rb +18 -0
  138. data/examples/legacy/not_checked/shoes-contrib/app/download-and-save.rb +11 -0
  139. data/examples/legacy/not_checked/shoes-contrib/app/download.rb +10 -0
  140. data/examples/legacy/not_checked/shoes-contrib/app/get-google.rb +11 -0
  141. data/examples/legacy/not_checked/shoes-contrib/app/mouse-detection.rb +7 -0
  142. data/examples/legacy/not_checked/shoes-contrib/app/resizeable-false.rb +6 -0
  143. data/examples/legacy/not_checked/shoes-contrib/art/bubble-bullseye.rb +23 -0
  144. data/examples/legacy/not_checked/shoes-contrib/art/faded.rb +17 -0
  145. data/examples/legacy/not_checked/shoes-contrib/art/fill-oval.rb +5 -0
  146. data/examples/legacy/not_checked/shoes-contrib/art/mask.rb +15 -0
  147. data/examples/legacy/not_checked/shoes-contrib/art/oval-gradient.rb +6 -0
  148. data/examples/legacy/not_checked/shoes-contrib/art/star-gradient.rb +4 -0
  149. data/examples/legacy/not_checked/shoes-contrib/basic/basic-edit-box.rb +8 -0
  150. data/examples/legacy/not_checked/shoes-contrib/basic/basic-new-window.rb +8 -0
  151. data/examples/legacy/not_checked/shoes-contrib/basic/basic-oval-image.rb +8 -0
  152. data/examples/legacy/not_checked/shoes-contrib/basic/basic-oval-shape.rb +8 -0
  153. data/examples/legacy/not_checked/shoes-contrib/basic/basic-oval.rb +6 -0
  154. data/examples/legacy/not_checked/shoes-contrib/basic/class-book.rb +43 -0
  155. data/examples/legacy/not_checked/shoes-contrib/basic/class-book.yaml +387 -0
  156. data/examples/legacy/not_checked/shoes-contrib/basic/clock.rb +6 -0
  157. data/examples/legacy/not_checked/shoes-contrib/basic/edit-stack +14 -0
  158. data/examples/legacy/not_checked/shoes-contrib/basic/gradient-shoes.rb +7 -0
  159. data/examples/legacy/not_checked/shoes-contrib/basic/list_box-shape-report.rb +19 -0
  160. data/examples/legacy/not_checked/shoes-contrib/basic/rect-arrow.rb +7 -0
  161. data/examples/legacy/not_checked/shoes-contrib/basic/scribble.rb +8 -0
  162. data/examples/legacy/not_checked/shoes-contrib/basic/search.rb +32 -0
  163. data/examples/legacy/not_checked/shoes-contrib/basic/shoes-notes.rb +16 -0
  164. data/examples/legacy/not_checked/shoes-contrib/basic/url-shoes-subclassing.rb +24 -0
  165. data/examples/legacy/not_checked/shoes-contrib/browser.rb +21 -0
  166. data/examples/legacy/not_checked/shoes-contrib/elements/background-column.rb +3 -0
  167. data/examples/legacy/not_checked/shoes-contrib/elements/background.rb +4 -0
  168. data/examples/legacy/not_checked/shoes-contrib/elements/basic-fps.rb +6 -0
  169. data/examples/legacy/not_checked/shoes-contrib/elements/border-cat.rb +6 -0
  170. data/examples/legacy/not_checked/shoes-contrib/elements/button-block.rb +8 -0
  171. data/examples/legacy/not_checked/shoes-contrib/elements/check-mate.rb +15 -0
  172. data/examples/legacy/not_checked/shoes-contrib/elements/common-styles.rb +13 -0
  173. data/examples/legacy/not_checked/shoes-contrib/elements/displace-animation.rb +13 -0
  174. data/examples/legacy/not_checked/shoes-contrib/elements/edit_box-character-count.rb +7 -0
  175. data/examples/legacy/not_checked/shoes-contrib/elements/edit_line-character-count.rb +7 -0
  176. data/examples/legacy/not_checked/shoes-contrib/elements/image-icon.rb +3 -0
  177. data/examples/legacy/not_checked/shoes-contrib/elements/list_box-select-class.rb +13 -0
  178. data/examples/legacy/not_checked/shoes-contrib/elements/list_box.rb +6 -0
  179. data/examples/legacy/not_checked/shoes-contrib/elements/move-flow-animate.rb +13 -0
  180. data/examples/legacy/not_checked/shoes-contrib/elements/phat-button.rb +7 -0
  181. data/examples/legacy/not_checked/shoes-contrib/elements/popup.rb +7 -0
  182. data/examples/legacy/not_checked/shoes-contrib/elements/progress-bar.rb +10 -0
  183. data/examples/legacy/not_checked/shoes-contrib/elements/radio-dreamcast-favs.rb +17 -0
  184. data/examples/legacy/not_checked/shoes-contrib/elements/timer.rb +6 -0
  185. data/examples/legacy/not_checked/shoes-contrib/elements/width-introspec.rb +8 -0
  186. data/examples/legacy/not_checked/shoes-contrib/events/background-hover.rb +11 -0
  187. data/examples/legacy/not_checked/shoes-contrib/events/motion-detect.rb +9 -0
  188. data/examples/legacy/not_checked/shoes-contrib/events/pressed-key.rb +6 -0
  189. data/examples/legacy/not_checked/shoes-contrib/expert/expert-funnies.rb +51 -0
  190. data/examples/legacy/not_checked/shoes-contrib/expert/expert-irb.rb +112 -0
  191. data/examples/legacy/not_checked/shoes-contrib/expert/expert-othello.rb +319 -0
  192. data/examples/legacy/not_checked/shoes-contrib/good/good-arc.rb +37 -0
  193. data/examples/legacy/not_checked/shoes-contrib/good/good-clock.rb +51 -0
  194. data/examples/legacy/not_checked/shoes-contrib/good/good-follow.rb +26 -0
  195. data/examples/legacy/not_checked/shoes-contrib/good/good-reminder.rb +174 -0
  196. data/examples/legacy/not_checked/shoes-contrib/good/good-vjot.rb +56 -0
  197. data/examples/legacy/not_checked/shoes-contrib/kernel/ask.rb +4 -0
  198. data/examples/legacy/not_checked/shoes-contrib/kernel/ask_color.rb +4 -0
  199. data/examples/legacy/not_checked/shoes-contrib/kernel/ask_open_file.rb +4 -0
  200. data/examples/legacy/not_checked/shoes-contrib/kernel/ask_save_file.rb +7 -0
  201. data/examples/legacy/not_checked/shoes-contrib/kernel/confirm.rb +3 -0
  202. data/examples/legacy/not_checked/shoes-contrib/kernel/debug.rb +4 -0
  203. data/examples/legacy/not_checked/shoes-contrib/kernel/exit.rb +5 -0
  204. data/examples/legacy/not_checked/shoes-contrib/kernel/font.rb +5 -0
  205. data/examples/legacy/not_checked/shoes-contrib/kernel/fonts.rb +3 -0
  206. data/examples/legacy/not_checked/shoes-contrib/manipulation/append-slot.rb +9 -0
  207. data/examples/legacy/not_checked/shoes-contrib/manipulation/clear-slot.rb +6 -0
  208. data/examples/legacy/not_checked/shoes-contrib/manipulation/prepend-slot.rb +6 -0
  209. data/examples/legacy/not_checked/shoes-contrib/manipulation/roll.rb +17 -0
  210. data/examples/legacy/not_checked/shoes-contrib/position/gutter-margin.rb +5 -0
  211. data/examples/legacy/not_checked/shoes-contrib/position/stack-width.rb +3 -0
  212. data/examples/legacy/not_checked/shoes-contrib/simple/simple-accordion.rb +75 -0
  213. data/examples/legacy/not_checked/shoes-contrib/simple/simple-anim-shapes.rb +17 -0
  214. data/examples/legacy/not_checked/shoes-contrib/simple/simple-anim-text.rb +13 -0
  215. data/examples/legacy/not_checked/shoes-contrib/simple/simple-arc.rb +23 -0
  216. data/examples/legacy/not_checked/shoes-contrib/simple/simple-bounce.rb +24 -0
  217. data/examples/legacy/not_checked/shoes-contrib/simple/simple-calc.rb +70 -0
  218. data/examples/legacy/not_checked/shoes-contrib/simple/simple-chipmunk.rb +26 -0
  219. data/examples/legacy/not_checked/shoes-contrib/simple/simple-control-sizes.rb +24 -0
  220. data/examples/legacy/not_checked/shoes-contrib/simple/simple-curve.rb +26 -0
  221. data/examples/legacy/not_checked/shoes-contrib/simple/simple-dialogs.rb +29 -0
  222. data/examples/legacy/not_checked/shoes-contrib/simple/simple-downloader.rb +27 -0
  223. data/examples/legacy/not_checked/shoes-contrib/simple/simple-draw.rb +13 -0
  224. data/examples/legacy/not_checked/shoes-contrib/simple/simple-editor.rb +28 -0
  225. data/examples/legacy/not_checked/shoes-contrib/simple/simple-form.rb +28 -0
  226. data/examples/legacy/not_checked/shoes-contrib/simple/simple-form.shy +0 -0
  227. data/examples/legacy/not_checked/shoes-contrib/simple/simple-mask.rb +21 -0
  228. data/examples/legacy/not_checked/shoes-contrib/simple/simple-menu.rb +31 -0
  229. data/examples/legacy/not_checked/shoes-contrib/simple/simple-menu1.rb +35 -0
  230. data/examples/legacy/not_checked/shoes-contrib/simple/simple-rubygems.rb +29 -0
  231. data/examples/legacy/not_checked/shoes-contrib/simple/simple-slide.rb +45 -0
  232. data/examples/legacy/not_checked/shoes-contrib/simple/simple-sphere.rb +28 -0
  233. data/examples/legacy/not_checked/shoes-contrib/simple/simple-sqlite3.rb +13 -0
  234. data/examples/legacy/not_checked/shoes-contrib/simple/simple-timer.rb +13 -0
  235. data/examples/legacy/not_checked/shoes-contrib/simple/simple-video.rb +13 -0
  236. data/examples/legacy/not_checked/shoes-contrib/styles/alignment.rb +4 -0
  237. data/examples/legacy/not_checked/shoes-contrib/styles/attachment.rb +5 -0
  238. data/examples/legacy/not_checked/shoes-contrib/styles/emphasis.rb +3 -0
  239. data/examples/legacy/not_checked/shoes-contrib/styles/gradient-angle.rb +3 -0
  240. data/examples/legacy/not_checked/shoes-contrib/styles/para-methods.rb +5 -0
  241. data/examples/legacy/not_checked/shoes-contrib/styles/para-red-underlined.rb +3 -0
  242. data/examples/legacy/not_checked/shoes-contrib/styles/para-style-method.rb +4 -0
  243. data/examples/legacy/not_checked/shoes-dep-samples/expert-game-of-life.rb +243 -0
  244. data/examples/legacy/not_checked/shoes-dep-samples/expert-othello.rb +319 -0
  245. data/examples/legacy/not_checked/shoes-dep-samples/good-clock.rb +51 -0
  246. data/examples/legacy/not_checked/shoes-dep-samples/good-follow.rb +26 -0
  247. data/examples/legacy/not_checked/shoes-dep-samples/good-reminder.rb +174 -0
  248. data/examples/legacy/not_checked/shoes-dep-samples/good-vjot.rb +56 -0
  249. data/examples/legacy/not_checked/shoes-dep-samples/simple-accordion.rb +75 -0
  250. data/examples/legacy/not_checked/shoes-dep-samples/simple-anim-shapes.rb +17 -0
  251. data/examples/legacy/not_checked/shoes-dep-samples/simple-anim-text.rb +13 -0
  252. data/examples/legacy/not_checked/shoes-dep-samples/simple-arc.rb +23 -0
  253. data/examples/legacy/not_checked/shoes-dep-samples/simple-bounce.rb +24 -0
  254. data/examples/legacy/not_checked/shoes-dep-samples/simple-calc.rb +70 -0
  255. data/examples/legacy/not_checked/shoes-dep-samples/simple-chipmunk.rb +26 -0
  256. data/examples/legacy/not_checked/shoes-dep-samples/simple-control-sizes.rb +24 -0
  257. data/examples/legacy/not_checked/shoes-dep-samples/simple-curve.rb +26 -0
  258. data/examples/legacy/not_checked/shoes-dep-samples/simple-dialogs.rb +29 -0
  259. data/examples/legacy/not_checked/shoes-dep-samples/simple-draw.rb +13 -0
  260. data/examples/legacy/not_checked/shoes-dep-samples/simple-editor.rb +28 -0
  261. data/examples/legacy/not_checked/shoes-dep-samples/simple-form.rb +28 -0
  262. data/examples/legacy/not_checked/shoes-dep-samples/simple-form.shy +0 -0
  263. data/examples/legacy/not_checked/shoes-dep-samples/simple-mask.rb +21 -0
  264. data/examples/legacy/not_checked/shoes-dep-samples/simple-menu.rb +31 -0
  265. data/examples/legacy/not_checked/shoes-dep-samples/simple-menu1.rb +35 -0
  266. data/examples/legacy/not_checked/shoes-dep-samples/simple-rubygems.rb +29 -0
  267. data/examples/legacy/not_checked/shoes-dep-samples/simple-slide.rb +45 -0
  268. data/examples/legacy/not_checked/shoes-dep-samples/simple-sphere.rb +28 -0
  269. data/examples/legacy/not_checked/shoes-dep-samples/simple-sqlite3.rb +13 -0
  270. data/examples/legacy/not_checked/shoes-dep-samples/simple-timer.rb +13 -0
  271. data/examples/legacy/not_checked/shoes-dep-samples/simple-video.rb +13 -0
  272. data/examples/legacy/not_checked/shoes3-tests/AnemicCinema1926marcelDuchampCut.mp4 +0 -0
  273. data/examples/legacy/not_checked/shoes3-tests/button/button.rb +53 -0
  274. data/examples/legacy/not_checked/shoes3-tests/cache/cache.rb +41 -0
  275. data/examples/legacy/not_checked/shoes3-tests/combo/combo.rb +24 -0
  276. data/examples/legacy/not_checked/shoes3-tests/curl/bare.rb +34 -0
  277. data/examples/legacy/not_checked/shoes3-tests/curl/downloader.rb +40 -0
  278. data/examples/legacy/not_checked/shoes3-tests/curl/m1.rb +11 -0
  279. data/examples/legacy/not_checked/shoes3-tests/curl/m2.rb +12 -0
  280. data/examples/legacy/not_checked/shoes3-tests/curl/m3.rb +11 -0
  281. data/examples/legacy/not_checked/shoes3-tests/curl/m4.rb +5 -0
  282. data/examples/legacy/not_checked/shoes3-tests/curl/typ.rb +30 -0
  283. data/examples/legacy/not_checked/shoes3-tests/cursor/c1.rb +21 -0
  284. data/examples/legacy/not_checked/shoes3-tests/decoration.rb +14 -0
  285. data/examples/legacy/not_checked/shoes3-tests/dialogs/ask.rb +6 -0
  286. data/examples/legacy/not_checked/shoes3-tests/dialogs/confirm.rb +6 -0
  287. data/examples/legacy/not_checked/shoes3-tests/editbox/editbox.rb +36 -0
  288. data/examples/legacy/not_checked/shoes3-tests/editline/editline.rb +27 -0
  289. data/examples/legacy/not_checked/shoes3-tests/events/button.rb +32 -0
  290. data/examples/legacy/not_checked/shoes3-tests/events/button.yaml +40 -0
  291. data/examples/legacy/not_checked/shoes3-tests/events/capture.rb +57 -0
  292. data/examples/legacy/not_checked/shoes3-tests/events/chipmunk.yaml +47 -0
  293. data/examples/legacy/not_checked/shoes3-tests/events/event0.rb +8 -0
  294. data/examples/legacy/not_checked/shoes3-tests/events/event1.rb +51 -0
  295. data/examples/legacy/not_checked/shoes3-tests/events/event1.yaml +26 -0
  296. data/examples/legacy/not_checked/shoes3-tests/events/event2.rb +46 -0
  297. data/examples/legacy/not_checked/shoes3-tests/events/event3.rb +44 -0
  298. data/examples/legacy/not_checked/shoes3-tests/events/event4.rb +65 -0
  299. data/examples/legacy/not_checked/shoes3-tests/events/event5.rb +17 -0
  300. data/examples/legacy/not_checked/shoes3-tests/events/event6.rb +51 -0
  301. data/examples/legacy/not_checked/shoes3-tests/events/replay.rb +60 -0
  302. data/examples/legacy/not_checked/shoes3-tests/gapp/fullscreen.rb +38 -0
  303. data/examples/legacy/not_checked/shoes3-tests/gapp/icon.rb +56 -0
  304. data/examples/legacy/not_checked/shoes3-tests/gapp/mon1.rb +46 -0
  305. data/examples/legacy/not_checked/shoes3-tests/gapp/settings1.rb +22 -0
  306. data/examples/legacy/not_checked/shoes3-tests/gapp/title1.rb +34 -0
  307. data/examples/legacy/not_checked/shoes3-tests/indian.m4a +0 -0
  308. data/examples/legacy/not_checked/shoes3-tests/menus/event.rb +33 -0
  309. data/examples/legacy/not_checked/shoes3-tests/menus/menu1.rb +8 -0
  310. data/examples/legacy/not_checked/shoes3-tests/menus/menu2.rb +25 -0
  311. data/examples/legacy/not_checked/shoes3-tests/menus/menu3.rb +103 -0
  312. data/examples/legacy/not_checked/shoes3-tests/menus/menu4.rb +41 -0
  313. data/examples/legacy/not_checked/shoes3-tests/menus/tests.txt +42 -0
  314. data/examples/legacy/not_checked/shoes3-tests/opacity.rb +13 -0
  315. data/examples/legacy/not_checked/shoes3-tests/plot/^IRX.R +5219 -0
  316. data/examples/legacy/not_checked/shoes3-tests/plot/^SPX +5219 -0
  317. data/examples/legacy/not_checked/shoes3-tests/plot/cstest.rb +51 -0
  318. data/examples/legacy/not_checked/shoes3-tests/plot/gr1.rb +73 -0
  319. data/examples/legacy/not_checked/shoes3-tests/plot/gr2.rb +40 -0
  320. data/examples/legacy/not_checked/shoes3-tests/plot/gr3.rb +47 -0
  321. data/examples/legacy/not_checked/shoes3-tests/plot/gr4.rb +35 -0
  322. data/examples/legacy/not_checked/shoes3-tests/plot/gr5.rb +31 -0
  323. data/examples/legacy/not_checked/shoes3-tests/plot/gr6.rb +35 -0
  324. data/examples/legacy/not_checked/shoes3-tests/plot/gr7.rb +37 -0
  325. data/examples/legacy/not_checked/shoes3-tests/plot/grcsv.rb +219 -0
  326. data/examples/legacy/not_checked/shoes3-tests/plot/manual.rb +40 -0
  327. data/examples/legacy/not_checked/shoes3-tests/progress/progress.rb +29 -0
  328. data/examples/legacy/not_checked/shoes3-tests/radio/clear.rb +20 -0
  329. data/examples/legacy/not_checked/shoes3-tests/radio/group.rb +18 -0
  330. data/examples/legacy/not_checked/shoes3-tests/radio/multiple.rb +32 -0
  331. data/examples/legacy/not_checked/shoes3-tests/radio/nogroup.rb +9 -0
  332. data/examples/legacy/not_checked/shoes3-tests/simpletest.svg +14 -0
  333. data/examples/legacy/not_checked/shoes3-tests/spinner.rb +15 -0
  334. data/examples/legacy/not_checked/shoes3-tests/svg.rb +208 -0
  335. data/examples/legacy/not_checked/shoes3-tests/switch/switch.rb +28 -0
  336. data/examples/legacy/not_checked/shoes3-tests/systray/back.rb +20 -0
  337. data/examples/legacy/not_checked/shoes3-tests/systray/note.rb +17 -0
  338. data/examples/legacy/not_checked/shoes3-tests/terminal/cursor.rb +27 -0
  339. data/examples/legacy/not_checked/shoes3-tests/terminal/ed.rb +65 -0
  340. data/examples/legacy/not_checked/shoes3-tests/terminal/el.rb +50 -0
  341. data/examples/legacy/not_checked/shoes3-tests/terminal/logattr.rb +31 -0
  342. data/examples/legacy/not_checked/shoes3-tests/tests_color.rb +138 -0
  343. data/examples/legacy/not_checked/shoes3-tests/tests_svg.rb +228 -0
  344. data/examples/legacy/not_checked/shoes3-tests/tests_video_vlc.rb +186 -0
  345. data/examples/legacy/not_checked/shoes3-tests/tooltips.rb +20 -0
  346. data/examples/legacy/not_checked/shoes3-tests/video_vlc.rb +242 -0
  347. data/examples/legacy/not_checked/shoes3-tests/wheel/wheel1.rb +21 -0
  348. data/examples/legacy/not_checked/simple/accordion.rb +81 -0
  349. data/examples/legacy/not_checked/simple/anim-shapes.rb +17 -0
  350. data/examples/legacy/not_checked/simple/anim-text.rb +13 -0
  351. data/examples/legacy/not_checked/simple/arc.rb +23 -0
  352. data/examples/legacy/not_checked/simple/bounce.rb +24 -0
  353. data/examples/legacy/not_checked/simple/chipmunk.rb +26 -0
  354. data/examples/legacy/not_checked/simple/control-sizes.rb +24 -0
  355. data/examples/legacy/not_checked/simple/curve-control-points.rb +24 -0
  356. data/examples/legacy/not_checked/simple/curve.rb +26 -0
  357. data/examples/legacy/not_checked/simple/dialogs.rb +29 -0
  358. data/examples/legacy/not_checked/simple/downloader.rb +40 -0
  359. data/examples/legacy/not_checked/simple/downloader1.rb +31 -0
  360. data/examples/legacy/not_checked/simple/draw.rb +13 -0
  361. data/examples/legacy/not_checked/simple/editor.rb +28 -0
  362. data/examples/legacy/not_checked/simple/form.rb +30 -0
  363. data/examples/legacy/not_checked/simple/image.rb +21 -0
  364. data/examples/legacy/not_checked/simple/info.rb +78 -0
  365. data/examples/legacy/not_checked/simple/mask.rb +21 -0
  366. data/examples/legacy/not_checked/simple/mask2.rb +27 -0
  367. data/examples/legacy/not_checked/simple/menu.rb +31 -0
  368. data/examples/legacy/not_checked/simple/menu1.rb +35 -0
  369. data/examples/legacy/not_checked/simple/slide.rb +45 -0
  370. data/examples/legacy/not_checked/simple/sphere.rb +28 -0
  371. data/examples/legacy/not_checked/superleg.rb +244 -0
  372. data/examples/legacy/working/shoes-contrib/basic/a-poem.rb +24 -0
  373. data/examples/legacy/working/shoes-contrib/basic/basic-blocks-instances.rb +7 -0
  374. data/examples/legacy/working/shoes-contrib/basic/basic-blocks.rb +7 -0
  375. data/examples/legacy/working/shoes-contrib/basic/basic-slot.rb +8 -0
  376. data/examples/legacy/working/shoes-contrib/basic/intro.rb +20 -0
  377. data/examples/legacy/working/shoes-contrib/basic/two-column.rb +12 -0
  378. data/examples/legacy/working/shoes-contrib/elements/edit_box.rb +6 -0
  379. data/examples/legacy/working/shoes-contrib/kernel/alert.rb +3 -0
  380. data/examples/legacy/working/simple/calc.rb +71 -0
  381. data/examples/legacy/working/simple/sqlite3.rb +27 -0
  382. data/examples/legacy/working/simple/timer.rb +13 -0
  383. data/examples/line.rb +5 -0
  384. data/examples/link.rb +20 -0
  385. data/examples/list_box.rb +8 -0
  386. data/examples/para/collection_of_arguments.rb +9 -0
  387. data/examples/para/hello_world.rb +5 -0
  388. data/examples/para/hide_and_show.rb +9 -0
  389. data/examples/para/rainbow.rb +11 -0
  390. data/examples/para/rainbow_2.rb +11 -0
  391. data/examples/para/sizes.rb +11 -0
  392. data/examples/para/sizes_2.rb +12 -0
  393. data/examples/para/strong.rb +3 -0
  394. data/examples/para_text_widgets.rb +4 -0
  395. data/examples/pirate.png +0 -0
  396. data/examples/raw_flow.rb +11 -0
  397. data/examples/ruby_racer.rb +52 -0
  398. data/examples/shapes/arc.rb +8 -0
  399. data/examples/shapes/shapes.rb +8 -0
  400. data/examples/shapes/shapes_fill.rb +10 -0
  401. data/examples/shapes/star.rb +5 -0
  402. data/examples/shoes_school.rb +68 -0
  403. data/examples/shoes_splorer.rb +150 -0
  404. data/examples/simple_slides.rb +73 -0
  405. data/examples/skip_ci/parrot.rb +22 -0
  406. data/examples/skip_ci/say.rb +20 -0
  407. data/examples/sleepless.rb +26 -0
  408. data/examples/slots.rb +2 -4
  409. data/examples/spacing.rb +18 -0
  410. data/examples/span.rb +6 -0
  411. data/examples/stack/background.rb +35 -0
  412. data/examples/stack/border.rb +11 -0
  413. data/examples/stack/gradients.rb +6 -0
  414. data/examples/stack/raw_stack.rb +8 -0
  415. data/examples/stack/stack.rb +27 -0
  416. data/examples/text_change.rb +4 -0
  417. data/examples/text_sizes.rb +10 -0
  418. data/examples/timmy.rb +109 -0
  419. data/examples/title_and_resize.rb +3 -0
  420. data/exe/scarpe +108 -0
  421. data/lib/constants.rb +5 -0
  422. data/lib/scarpe/alert.rb +19 -0
  423. data/lib/scarpe/app.rb +78 -0
  424. data/lib/scarpe/arc.rb +49 -0
  425. data/lib/scarpe/background.rb +14 -0
  426. data/lib/scarpe/border.rb +16 -0
  427. data/lib/scarpe/button.rb +26 -18
  428. data/lib/scarpe/colors.rb +215 -0
  429. data/lib/scarpe/display_service.rb +189 -0
  430. data/lib/scarpe/document_root.rb +20 -0
  431. data/lib/scarpe/edit_box.rb +24 -0
  432. data/lib/scarpe/edit_line.rb +16 -30
  433. data/lib/scarpe/fill.rb +23 -0
  434. data/lib/scarpe/flow.rb +18 -15
  435. data/lib/scarpe/glibui/README.md +34 -0
  436. data/lib/scarpe/glibui/alert.rb +65 -0
  437. data/lib/scarpe/glibui/app.rb +27 -0
  438. data/lib/scarpe/glibui/background.rb +18 -0
  439. data/lib/scarpe/glibui/border.rb +22 -0
  440. data/lib/scarpe/glibui/button.rb +38 -0
  441. data/lib/scarpe/glibui/dimensions.rb +22 -0
  442. data/lib/scarpe/glibui/document_root.rb +33 -0
  443. data/lib/scarpe/glibui/edit_box.rb +44 -0
  444. data/lib/scarpe/glibui/edit_line.rb +43 -0
  445. data/lib/scarpe/glibui/flow.rb +33 -0
  446. data/lib/scarpe/glibui/html.rb +77 -0
  447. data/lib/scarpe/glibui/image.rb +36 -0
  448. data/lib/scarpe/glibui/link.rb +29 -0
  449. data/lib/scarpe/glibui/local_display.rb +62 -0
  450. data/lib/scarpe/glibui/para.rb +84 -0
  451. data/lib/scarpe/glibui/spacing.rb +41 -0
  452. data/lib/scarpe/glibui/stack.rb +33 -0
  453. data/lib/scarpe/glibui/text_widget.rb +30 -0
  454. data/lib/scarpe/glibui/widget.rb +81 -0
  455. data/lib/scarpe/glibui.rb +29 -0
  456. data/lib/scarpe/image.rb +28 -9
  457. data/lib/scarpe/libui/alert.rb +9 -0
  458. data/lib/scarpe/libui/button.rb +18 -0
  459. data/lib/scarpe/libui/colors.rb +157 -0
  460. data/lib/scarpe/libui/core.rb +66 -0
  461. data/lib/scarpe/libui/flow.rb +16 -0
  462. data/lib/scarpe/libui/libui.rb +45 -0
  463. data/lib/scarpe/libui/notepad.md +26 -0
  464. data/lib/scarpe/libui/para.rb +154 -0
  465. data/lib/scarpe/libui/stack.rb +34 -0
  466. data/lib/scarpe/line.rb +25 -0
  467. data/lib/scarpe/link.rb +25 -0
  468. data/lib/scarpe/list_box.rb +25 -0
  469. data/lib/scarpe/logger.rb +155 -0
  470. data/lib/scarpe/para.rb +84 -12
  471. data/lib/scarpe/promises.rb +387 -0
  472. data/lib/scarpe/shape.rb +19 -0
  473. data/lib/scarpe/spacing.rb +9 -0
  474. data/lib/scarpe/span.rb +26 -0
  475. data/lib/scarpe/stack.rb +66 -12
  476. data/lib/scarpe/star.rb +47 -0
  477. data/lib/scarpe/text_widget.rb +42 -0
  478. data/lib/scarpe/unit_test_helpers.rb +163 -0
  479. data/lib/scarpe/version.rb +2 -2
  480. data/lib/scarpe/widget.rb +198 -0
  481. data/lib/scarpe/widgets.rb +30 -0
  482. data/lib/scarpe/wv/alert.rb +65 -0
  483. data/lib/scarpe/wv/app.rb +85 -0
  484. data/lib/scarpe/wv/arc.rb +57 -0
  485. data/lib/scarpe/wv/background.rb +18 -0
  486. data/lib/scarpe/wv/border.rb +22 -0
  487. data/lib/scarpe/wv/button.rb +50 -0
  488. data/lib/scarpe/wv/control_interface.rb +153 -0
  489. data/lib/scarpe/wv/control_interface_test.rb +253 -0
  490. data/lib/scarpe/wv/dimensions.rb +22 -0
  491. data/lib/scarpe/wv/document_root.rb +50 -0
  492. data/lib/scarpe/wv/edit_box.rb +44 -0
  493. data/lib/scarpe/wv/edit_line.rb +43 -0
  494. data/lib/scarpe/wv/fill.rb +30 -0
  495. data/lib/scarpe/wv/flow.rb +32 -0
  496. data/lib/scarpe/wv/html.rb +107 -0
  497. data/lib/scarpe/wv/image.rb +36 -0
  498. data/lib/scarpe/wv/line.rb +38 -0
  499. data/lib/scarpe/wv/link.rb +29 -0
  500. data/lib/scarpe/wv/list_box.rb +50 -0
  501. data/lib/scarpe/wv/para.rb +90 -0
  502. data/lib/scarpe/wv/shape.rb +34 -0
  503. data/lib/scarpe/wv/shape_helper.rb +44 -0
  504. data/lib/scarpe/wv/spacing.rb +41 -0
  505. data/lib/scarpe/wv/span.rb +66 -0
  506. data/lib/scarpe/wv/stack.rb +42 -0
  507. data/lib/scarpe/wv/star.rb +64 -0
  508. data/lib/scarpe/wv/text_widget.rb +30 -0
  509. data/lib/scarpe/wv/web_wrangler.rb +679 -0
  510. data/lib/scarpe/wv/webview_local_display.rb +72 -0
  511. data/lib/scarpe/wv/webview_relay_display.rb +185 -0
  512. data/lib/scarpe/wv/widget.rb +181 -0
  513. data/lib/scarpe/wv/wv_display_worker.rb +65 -0
  514. data/lib/scarpe/wv.rb +39 -0
  515. data/lib/scarpe/wv_local.rb +6 -0
  516. data/lib/scarpe/wv_relay.rb +6 -0
  517. data/lib/scarpe.rb +35 -27
  518. data/logger/debug_web_wrangler.json +4 -0
  519. data/logger/scarpe_wv_test.json +4 -0
  520. data/scarpegen.rb +193 -0
  521. data/sig/scarpe.rbs +1 -1
  522. data/templates/basic_class_template.erb +38 -0
  523. data/templates/class_template_with_event_bind.erb +27 -0
  524. data/templates/class_template_with_shapes.erb +43 -0
  525. data/templates/example_template.erb +3 -0
  526. data/templates/module_template.erb +12 -0
  527. data/templates/webview_template.erb +30 -0
  528. metadata +586 -9
  529. data/lib/scarpe/container.rb +0 -10
  530. data/lib/scarpe/internal_app.rb +0 -46
@@ -0,0 +1,85 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Scarpe
4
+ # Scarpe::WebviewApp must only be used from the main thread, due to GTK+ limitations.
5
+ class WebviewApp < WebviewWidget
6
+ attr_reader :debug
7
+ attr_reader :control_interface
8
+
9
+ attr_writer :shoes_linkable_id
10
+
11
+ def initialize(properties)
12
+ # Is this a thing? Do we care about this?
13
+ # opts = @control_interface.app_opts_get_override(opts)
14
+
15
+ super
16
+
17
+ # It's possible to provide a Ruby script by setting
18
+ # SCARPE_TEST_CONTROL to its file path. This can
19
+ # allow pre-setting test options or otherwise
20
+ # performing additional actions not written into
21
+ # the Shoes app itself.
22
+ #
23
+ # The control interface is what lets these files see
24
+ # events, specify overrides and so on.
25
+ @control_interface = ControlInterface.new
26
+ if ENV["SCARPE_TEST_CONTROL"]
27
+ @control_interface.instance_eval File.read(ENV["SCARPE_TEST_CONTROL"])
28
+ end
29
+
30
+ # TODO: rename @view
31
+ @view = Scarpe::WebWrangler.new title: @title,
32
+ width: @width,
33
+ height: @height,
34
+ resizable: @resizable,
35
+ debug: @debug
36
+
37
+ # The control interface has to exist to get callbacks like "override Scarpe app opts".
38
+ # But the Scarpe App needs those options to be created. So we can't pass these to
39
+ # ControlInterface.new.
40
+ @control_interface.set_system_components app: self, doc_root: nil, wrangler: @view
41
+
42
+ bind_shoes_event(event_name: "init") { init }
43
+ bind_shoes_event(event_name: "run") { run }
44
+ bind_shoes_event(event_name: "destroy") { destroy }
45
+ end
46
+
47
+ attr_writer :document_root
48
+
49
+ def init
50
+ scarpe_app = self
51
+
52
+ @view.init_code("scarpeInit") do
53
+ @document_root.request_redraw!
54
+ end
55
+
56
+ @view.bind("scarpeHandler") do |*args|
57
+ @document_root.handle_callback(*args)
58
+ end
59
+
60
+ @view.bind("scarpeExit") do
61
+ scarpe_app.destroy
62
+ end
63
+ end
64
+
65
+ def run
66
+ @control_interface.dispatch_event(:init)
67
+
68
+ # This takes control of the main thread and never returns. And it *must* be run from
69
+ # the main thread. And it stops any Ruby background threads.
70
+ # That's totally cool and normal, right?
71
+ @view.run
72
+ end
73
+
74
+ def destroy
75
+ if @document_root || @view
76
+ @control_interface.dispatch_event :shutdown
77
+ end
78
+ @document_root = nil
79
+ if @view
80
+ @view.destroy
81
+ @view = nil
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "shape_helper"
4
+
5
+ class Scarpe
6
+ class WebviewArc < Scarpe::WebviewWidget
7
+ include ShapeHelper
8
+ def initialize(properties)
9
+ super(properties)
10
+ end
11
+
12
+ def element(&block)
13
+ HTML.render do |h|
14
+ h.div(id: html_id, style: style) do
15
+ h.svg(width: @width, height: @height) do
16
+ h.path(d: arc_path)
17
+ end
18
+ block.call(h) if block_given?
19
+ end
20
+ end
21
+ end
22
+
23
+ private
24
+
25
+ def style
26
+ {
27
+ left: "#{@left}px",
28
+ top: "#{@top}px",
29
+ width: "#{@width}px",
30
+ height: "#{@height}px",
31
+ }
32
+ end
33
+
34
+ def arc_path
35
+ center_x = @width / 2
36
+ center_y = @height / 2
37
+ radius_x = @width / 2
38
+ radius_y = @height / 2
39
+ start_angle_degrees = radians_to_degrees(@angle1) % 360
40
+ end_angle_degrees = radians_to_degrees(@angle2) % 360
41
+ large_arc_flag = (end_angle_degrees - start_angle_degrees) % 360 > 180 ? 1 : 0
42
+
43
+ "M#{center_x} #{center_y} L#{@width} #{center_y} " \
44
+ "A#{radius_x} #{radius_y} 0 #{large_arc_flag} 0 " \
45
+ "#{center_x + radius_x * Math.cos(degrees_to_radians(end_angle_degrees))} " \
46
+ "#{center_y + radius_y * Math.sin(degrees_to_radians(end_angle_degrees))} Z"
47
+ end
48
+
49
+ def degrees_to_radians(degrees)
50
+ degrees * Math::PI / 180
51
+ end
52
+
53
+ def radians_to_degrees(radians)
54
+ radians * (180.0 / Math::PI)
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Scarpe
4
+ module WebviewBackground
5
+ def style
6
+ styles = (super if defined?(super)) || {}
7
+ return styles unless @background_color
8
+
9
+ color = if @background_color.is_a?(Range)
10
+ "linear-gradient(45deg, #{@background_color.first}, #{@background_color.last})"
11
+ else
12
+ @background_color
13
+ end
14
+
15
+ styles.merge(background: color)
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Scarpe
4
+ module WebviewBorder
5
+ def style
6
+ styles = (super if defined?(super)) || {}
7
+ return styles unless @border_color
8
+
9
+ border_color = if @border_color.is_a?(Range)
10
+ { "border-image": "linear-gradient(45deg, #{@border_color.first}, #{@border_color.last}) 1" }
11
+ else
12
+ { "border-color": @border_color }
13
+ end
14
+
15
+ styles.merge(
16
+ "border-style": "solid",
17
+ "border-width": "#{@options[:strokewidth] || 1}px",
18
+ "border-radius": "#{@options[:curve] || 0}px",
19
+ ).merge(border_color)
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Scarpe
4
+ class WebviewButton < WebviewWidget
5
+ def initialize(properties)
6
+ super
7
+
8
+ # Bind to display-side handler for "click"
9
+ bind("click") do
10
+ # This will be sent to the bind_self_event in Button
11
+ send_self_event(event_name: "click")
12
+ end
13
+ end
14
+
15
+ def element
16
+ HTML.render do |h|
17
+ h.button(id: html_id, onclick: handler_js_code("click"), style: style) do
18
+ @text
19
+ end
20
+ end
21
+ end
22
+
23
+ private
24
+
25
+ def style
26
+ styles = {}
27
+ styles["background-color"] = @color
28
+ styles["padding-top"] = @padding_top
29
+ styles["padding-bottom"] = @padding_bottom
30
+ styles[:color] = @text_color
31
+ styles[:width] = Dimensions.length(@width) if @width
32
+ styles[:height] = Dimensions.length(@height) if @height
33
+ styles["font-size"] = @font_size
34
+
35
+ styles[:top] = Dimensions.length(@top) if @top
36
+ styles[:left] = Dimensions.length(@left) if @left
37
+ styles[:position] = "absolute" if @top || @left
38
+ styles["font-size"] = Dimensions.length(font_size) if @size
39
+ styles["font-family"] = @font if @font
40
+ styles["color"] = rgb_to_hex(@stroke) if @stroke
41
+ styles
42
+ end
43
+
44
+ def font_size
45
+ font_size = @size.is_a?(Symbol) ? SIZES[@size] : @size
46
+
47
+ Dimensions.length(font_size)
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,153 @@
1
+ # frozen_string_literal: true
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 override
5
+ # test-relevant values like the options to Shoes.app(). Note that no part
6
+ # of the Scarpe framework should ever *depend* on ControlInterface. It's
7
+ # for testing, not normal operation. If no ControlInterface were ever
8
+ # created or called, Scarpe apps should run 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
+
13
+ class Scarpe
14
+ class ControlInterface
15
+ include Scarpe::Log
16
+
17
+ SUBSCRIBE_EVENTS = [:init, :shutdown, :next_redraw, :every_redraw, :next_heartbeat, :every_heartbeat]
18
+ DISPATCH_EVENTS = [:init, :shutdown, :redraw, :heartbeat]
19
+
20
+ attr_writer :doc_root
21
+ attr_reader :do_shutdown
22
+
23
+ # The control interface needs to see major system components to hook into their events
24
+ def initialize
25
+ log_init("WV::ControlInterface")
26
+
27
+ @do_shutdown = false
28
+ @event_handlers = {}
29
+ (SUBSCRIBE_EVENTS | DISPATCH_EVENTS).each { |e| @event_handlers[e] = [] }
30
+ end
31
+
32
+ def inspect
33
+ "<#ControlInterface>"
34
+ end
35
+
36
+ # This should get called once, from Scarpe::App
37
+ def set_system_components(app:, doc_root:, wrangler:)
38
+ unless app && wrangler
39
+ @log.error("False app passed to set_system_components!") unless app
40
+ @log.error("False wrangler passed to set_system_components!") unless wrangler
41
+ raise "Must pass non-nil app and wrangler to ControlInterface#set_system_components!"
42
+ end
43
+ @app = app
44
+ @doc_root = doc_root # May be nil at this point
45
+ @wrangler = wrangler
46
+
47
+ @wrangler.control_interface = self
48
+
49
+ @wrangler.on_every_redraw { self.dispatch_event(:redraw) }
50
+ end
51
+
52
+ def app
53
+ unless @app
54
+ raise "ControlInterface code needs to be wrapped in handlers like on_event(:init) " +
55
+ "to make sure they have access to app, doc_root, wrangler, etc!"
56
+ end
57
+
58
+ @app
59
+ end
60
+
61
+ def doc_root
62
+ unless @doc_root
63
+ raise "ControlInterface code needs to be wrapped in handlers like on_event(:init) " +
64
+ "to make sure they have access to app, doc_root, wrangler, etc!"
65
+ end
66
+
67
+ @doc_root
68
+ end
69
+
70
+ def wrangler
71
+ unless @wrangler
72
+ raise "ControlInterface code needs to be wrapped in handlers like on_event(:init) " +
73
+ "to make sure they have access to app, doc_root, wrangler, etc!"
74
+ end
75
+
76
+ @wrangler
77
+ end
78
+
79
+ # The control interface has overrides for certain settings. If the override has been specified,
80
+ # those settings will be overridden.
81
+
82
+ # Override the Shoes app opts like "debug:" and "die_after:" with new ones.
83
+ def override_app_opts(new_opts)
84
+ @new_app_opts = new_opts
85
+ end
86
+
87
+ # Called by Scarpe::App to get the override options
88
+ def app_opts_get_override(opts)
89
+ @new_app_opts || opts
90
+ end
91
+
92
+ # On recognised events, this sets a handler for that event
93
+ def on_event(event, &block)
94
+ unless SUBSCRIBE_EVENTS.include?(event)
95
+ raise "Illegal subscribe to event #{event.inspect}! Valid values are: #{SUBSCRIBE_EVENTS.inspect}"
96
+ end
97
+
98
+ @event_handlers[event] << block
99
+ end
100
+
101
+ # Send out the specified event
102
+ def dispatch_event(event, *args, **keywords)
103
+ @log.debug("CTL event #{event.inspect} #{args.inspect} #{keywords.inspect}")
104
+
105
+ unless DISPATCH_EVENTS.include?(event)
106
+ raise "Illegal dispatch of event #{event.inspect}! Valid values are: #{DISPATCH_EVENTS.inspect}"
107
+ end
108
+
109
+ if @do_shutdown
110
+ @log.debug("CTL: Shutting down - not dispatching #{event}!")
111
+ return
112
+ end
113
+
114
+ if event == :redraw
115
+ dumb_dispatch_event(:every_redraw, *args, **keywords)
116
+
117
+ # Next redraw is interesting. We can add new handlers
118
+ # when dispatching a next_redraw handler. But we want
119
+ # each handler to run only once.
120
+ handlers = @event_handlers[:next_redraw]
121
+ dumb_dispatch_event(:next_redraw, *args, **keywords)
122
+ @event_handlers[:next_redraw] -= handlers
123
+ return
124
+ end
125
+
126
+ if event == :heartbeat
127
+ dumb_dispatch_event(:every_heartbeat, *args, **keywords)
128
+
129
+ # Next heartbeat is interesting. We can add new handlers
130
+ # when dispatching a next_heartbeat handler. But we want
131
+ # each handler to run only once.
132
+ handlers = @event_handlers[:next_heartbeat]
133
+ dumb_dispatch_event(:next_heartbeat, *args, **keywords)
134
+ @event_handlers[:next_heartbeat] -= handlers
135
+ return
136
+ end
137
+
138
+ if event == :shutdown
139
+ @do_shutdown = true
140
+ end
141
+
142
+ dumb_dispatch_event(event, *args, **keywords)
143
+ end
144
+
145
+ private
146
+
147
+ def dumb_dispatch_event(event, *args, **keywords)
148
+ @event_handlers[event].each do |handler|
149
+ instance_eval(*args, **keywords, &handler)
150
+ end
151
+ end
152
+ end
153
+ end
@@ -0,0 +1,253 @@
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
+ class Scarpe
11
+ DEFAULT_ASSERTION_TIMEOUT = 1.0
12
+
13
+ class ControlInterface
14
+ def timed_out?
15
+ @did_time_out
16
+ end
17
+
18
+ def die_after(time)
19
+ t_start = Time.now
20
+ @die_after = [t_start, time]
21
+
22
+ wrangler.periodic_code("scarpeTestTimeout") do |*_args|
23
+ t_delta = (Time.now - t_start).to_f
24
+ if t_delta > time
25
+ @did_time_out = true
26
+ @log.warn("die_after - timed out after #{t_delta.inspect} (threshold: #{time.inspect})")
27
+ return_results(false, "Timed out!")
28
+ app.destroy
29
+ end
30
+ end
31
+ end
32
+
33
+ # This is returned alongside the actual results automatically
34
+ def test_metadata
35
+ data = {}
36
+ if @die_after
37
+ t_delta = (Time.now - @die_after[0]).to_f
38
+ data["die_after"] = {
39
+ t_start: @die_after[0].to_s,
40
+ threshold: @die_after[1],
41
+ passed: t_delta,
42
+ }
43
+ end
44
+ data
45
+ end
46
+
47
+ # This does a final return of results. If it gets called
48
+ # multiple times, the test fails because that's not okay.
49
+ def return_results(result_bool, msg, data = {})
50
+ result_file = ENV["SCARPE_TEST_RESULTS"] || "./scarpe_results.txt"
51
+
52
+ result_structs = [result_bool, msg, data.merge(test_metadata)]
53
+
54
+ # Multiple different sets of results is bad, even if both are passing.
55
+ if @results_returned && @results_returned[0..1] != result_structs[0..1]
56
+ # Just raising here doesn't reliably fail the test.
57
+ # See: https://github.com/scarpe-team/scarpe/issues/212
58
+ @log.error("Writing multi-result failure file to #{result_file.inspect}!")
59
+
60
+ new_res_data = { first_result: @results_returned, second_result: result_structs }.merge(test_metadata)
61
+ bad_result = [false, "Returned two sets of results!", new_res_data]
62
+ File.write(result_file, JSON.pretty_generate(bad_result))
63
+
64
+ return
65
+ end
66
+
67
+ @log.debug("Writing results file #{result_file.inspect} to disk!")
68
+ File.write(result_file, JSON.pretty_generate(result_structs))
69
+
70
+ @results_returned = result_structs
71
+ end
72
+
73
+ # Need to be able to query widgets in test code
74
+
75
+ def all_wv_widgets
76
+ known = [doc_root]
77
+ to_check = [doc_root]
78
+
79
+ until to_check.empty?
80
+ next_layer = to_check.flat_map(&:children)
81
+ known += next_layer
82
+ to_check = next_layer
83
+ end
84
+
85
+ # I don't *think* we'll ever have widget trees that merge back together, but just in case we'll de-dup
86
+ known.uniq
87
+ end
88
+
89
+ # Shoes doesn't name widgets. We aren't guaranteed that the Shoes widgets are even in the same
90
+ # process, since we have the Relay display service for Webview. So mostly we can look by
91
+ # display service class.
92
+ def find_wv_widgets(*specifiers)
93
+ widgets = all_wv_widgets
94
+
95
+ specifiers.each do |spec|
96
+ if spec.is_a?(Class)
97
+ widgets.select! { |w| spec === w }
98
+ else
99
+ raise "I don't know how to search for widgets by #{spec.inspect}!"
100
+ end
101
+ end
102
+
103
+ widgets
104
+ end
105
+
106
+ # We want an assertions library, but one that runs inside the spawned
107
+ # Webview sub-process.
108
+
109
+ def return_when_assertions_done
110
+ assertions_may_exist
111
+
112
+ wrangler.periodic_code("scarpeReturnWhenAssertionsDone") do |*_args|
113
+ if @assertions_pending.empty?
114
+ success = @assertions_failed.empty?
115
+ return_results success, "Assertions #{success ? "succeeded" : "failed"}", assertion_data_as_a_struct
116
+ app.destroy
117
+ end
118
+ end
119
+ end
120
+
121
+ def assertions_may_exist
122
+ @assertions_pending ||= {}
123
+ @assertions_failed ||= {}
124
+ @assertions_passed ||= 0
125
+ @assertion_counter ||= 0
126
+ end
127
+
128
+ def start_assertion(code)
129
+ assertions_may_exist
130
+
131
+ this_assertion = @assertion_counter
132
+ @assertion_counter += 1
133
+
134
+ @assertions_pending[this_assertion] = {
135
+ id: this_assertion,
136
+ code: code,
137
+ }
138
+
139
+ this_assertion
140
+ end
141
+
142
+ def pass_assertion(id)
143
+ @assertions_pending.delete(id)
144
+ @assertions_passed += 1
145
+ end
146
+
147
+ def fail_assertion(id, fail_message)
148
+ item = @assertions_pending.delete(id)
149
+ item[:fail_message] = fail_message
150
+ @assertions_failed[id] = item
151
+ end
152
+
153
+ def assertions_pending?
154
+ !@assertions_pending.empty?
155
+ end
156
+
157
+ def assertion_data_as_a_struct
158
+ {
159
+ still_pending: @assertions_pending.size,
160
+ succeeded: @assertions_passed,
161
+ failed: @assertions_failed.size,
162
+ failures: @assertions_failed.values.map { |item| [item[:code], item[:failure_reason]] },
163
+ }
164
+ end
165
+
166
+ # Create a promise to do a JS assertion, normally after other ops have finished.
167
+ def assert_js(js_code, wait_for: [], timeout: DEFAULT_ASSERTION_TIMEOUT)
168
+ id = start_assertion(js_code)
169
+
170
+ # this isn't a TestPromise, so it doesn't have the additional DSL entries
171
+ promise = wrangler.eval_js_async(js_code, wait_for: wait_for, timeout: timeout)
172
+ promise.on_rejected do
173
+ fail_assertion(id, "JS Eval failed: #{promise.reason.inspect}")
174
+ end
175
+ promise.on_fulfilled do
176
+ ret_val = promise.returned_value
177
+ if ret_val
178
+ pass_assertion(id)
179
+ else
180
+ fail_assertion(id, "Expected true JS value: #{ret_val.inspect}")
181
+ end
182
+ end
183
+
184
+ # So we wrap it in a no-op TestPromise, to get the DSL entries.
185
+ TestPromise.new(iface: self, wait_for: [promise]).to_execute {}
186
+ end
187
+
188
+ def assert(value, msg = nil)
189
+ id = start_assertion("#{caller[0]}: #{msg || "Value should be true!"}")
190
+
191
+ if value
192
+ pass_assertion(id)
193
+ else
194
+ fail_assertion(id, "Expected true Ruby value: #{value.inspect}")
195
+ end
196
+ end
197
+
198
+ def assert_equal(val1, val2, msg = nil)
199
+ assert val1 == val2, (msg || "Expected #{val2.inspect} to equal #{val1.inspect}!")
200
+ end
201
+
202
+ # How do we signal an error?
203
+ def with_js_value(js_code, wait_for: [], timeout: DEFAULT_ASSERTION_TIMEOUT, &block)
204
+ raise "Must give a block to with_js_value!" unless block
205
+
206
+ js_promise = wrangler.eval_js_async(js_code, wait_for: wait_for, timeout: timeout)
207
+ ruby_promise = TestPromise.new(iface: self, wait_for: [js_promise])
208
+ ruby_promise.to_execute(&block)
209
+ ruby_promise
210
+ end
211
+
212
+ def with_js_dom_html(wait_for: [], timeout: DEFAULT_ASSERTION_TIMEOUT, &block)
213
+ with_js_value("document.getElementById('wrapper-wvroot').innerHTML", wait_for: wait_for, timeout: timeout, &block)
214
+ end
215
+
216
+ def fully_updated(wait_for: [])
217
+ wrangler.promise_dom_fully_updated
218
+ end
219
+ end
220
+
221
+ # A Promise but with helper functions
222
+ class TestPromise < Promise
223
+ def initialize(iface:, state: nil, wait_for: [], &scheduler)
224
+ @iface = iface
225
+ super(state: state, parents: wait_for, &scheduler)
226
+ end
227
+
228
+ def inspect
229
+ "<#TestPromise::#{object_id} state=#{state.inspect} parents=#{parents.inspect} value=#{returned_value.inspect} reason=#{reason.inspect}>"
230
+ end
231
+
232
+ # This method expects to wait for the parent TestPromise and then run a block of Ruby that returns
233
+ # another promise. This is useful for wrapping Promises like those from replace() that don't have
234
+ # the test DSL built in. The block will execute when this outer promise is scheduled -- so we don't do
235
+ # a replace() too early, for instance. And then the outer promise will fulfill when the inner one does.
236
+ def then_ruby_promise(wait_for: [], &block)
237
+ ruby_wrapper_promise = TestPromise.new iface: @iface, wait_for: ([self] + wait_for)
238
+
239
+ ruby_wrapper_promise.on_scheduled do
240
+ inner_ruby_promise = block.call
241
+ inner_ruby_promise.on_fulfilled { ruby_wrapper_promise.fulfilled!(inner_ruby_promise.returned_value) }
242
+ end
243
+ end
244
+
245
+ def then_with_js_value(js_code, wait_for: [], timeout: DEFAULT_ASSERTION_TIMEOUT, &block)
246
+ @iface.with_js_value(js_code, wait_for: (wait_for + [self]), timeout:, &block)
247
+ end
248
+
249
+ def then_with_js_dom_html(wait_for: [], timeout: DEFAULT_ASSERTION_TIMEOUT, &block)
250
+ @iface.with_js_dom_html(wait_for: (wait_for + [self]), timeout:, &block)
251
+ end
252
+ end
253
+ end
@@ -0,0 +1,22 @@
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