scriptorium 0.0.3 → 0.7.2

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 (353) hide show
  1. checksums.yaml +4 -4
  2. data/README.lt3 +324 -0
  3. data/README.md +3155 -1
  4. data/assets/.DS_Store +0 -0
  5. data/assets/README.md +44 -0
  6. data/assets/icons/social/reddit.png +0 -0
  7. data/assets/icons/social/x-logo.png +0 -0
  8. data/assets/icons/ui/.DS_Store +0 -0
  9. data/assets/icons/ui/back.png +0 -0
  10. data/assets/icons/ui/copy.png +0 -0
  11. data/assets/icons/ui/down.png +0 -0
  12. data/assets/icons/ui/end.png +0 -0
  13. data/assets/icons/ui/exit.png +0 -0
  14. data/assets/icons/ui/foo +10 -0
  15. data/assets/icons/ui/home.png +0 -0
  16. data/assets/icons/ui/left.png +0 -0
  17. data/assets/icons/ui/next.png +0 -0
  18. data/assets/icons/ui/right.png +0 -0
  19. data/assets/icons/ui/start.png +0 -0
  20. data/assets/icons/ui/up.png +0 -0
  21. data/assets/imagenotfound.jpg +0 -0
  22. data/assets/samples/placeholder.svg +9 -0
  23. data/assets/themes/standard/favicon.svg +6 -0
  24. data/bin/sblog +84 -5
  25. data/bin/scriptorium +1 -0
  26. data/doc/README.txt +6 -0
  27. data/doc/anti-amnesia/20250727-054000-scriptorium-overview.md +94 -0
  28. data/doc/anti-amnesia/20250727-123000-anti-amnesia-conventions.md +2 -0
  29. data/doc/anti-amnesia/20250727-172600-cursor-rbenv-ruby-version-mystery.md +45 -0
  30. data/doc/anti-amnesia/20250727-172900-ai-cognitive-assessment-capabilities.md +40 -0
  31. data/doc/anti-amnesia/20250728-124243-aaa-syntax-clarification.md +46 -0
  32. data/doc/anti-amnesia/20250729-210000-reddit-autopost-integration-complete.md +158 -0
  33. data/doc/anti-amnesia/20250804-190500-cognitive-loop-bug.md +35 -0
  34. data/doc/anti-amnesia/20250804-190700-anti-amnesia-timestamping-fix.md +27 -0
  35. data/doc/anti-amnesia/20250807-213025.md +116 -0
  36. data/doc/anti-amnesia/20250901-211714-codemirror-integration-and-web-tests.md +172 -0
  37. data/doc/anti-amnesia/20250902-002402-backup-restore-system.md +126 -0
  38. data/doc/anti-amnesia/20250907-203339-backup-metadata-implementation.md +66 -0
  39. data/doc/banner_svg_config.md +114 -0
  40. data/doc/contrib.lt3 +8 -0
  41. data/doc/dependencies.md +281 -0
  42. data/doc/hacker.lt3 +5 -0
  43. data/doc/imported/0001-elixir-conf-2014/metadata.txt +7 -0
  44. data/doc/imported/0001-elixir-conf-2014/post.html +37 -0
  45. data/doc/imported/0001-elixir-conf-2014/source.lt3 +22 -0
  46. data/doc/imported/0002-programmers-and-word-processing/metadata.txt +7 -0
  47. data/doc/imported/0002-programmers-and-word-processing/post.html +192 -0
  48. data/doc/imported/0002-programmers-and-word-processing/source.lt3 +146 -0
  49. data/doc/imported/0003-how-to-turn-your-brain-sideways/metadata.txt +7 -0
  50. data/doc/imported/0003-how-to-turn-your-brain-sideways/post.html +60 -0
  51. data/doc/imported/0003-how-to-turn-your-brain-sideways/source.lt3 +40 -0
  52. data/doc/imported/0004-upcoming-lone-star-ruby-conference/metadata.txt +7 -0
  53. data/doc/imported/0004-upcoming-lone-star-ruby-conference/post.html +42 -0
  54. data/doc/imported/0004-upcoming-lone-star-ruby-conference/source.lt3 +24 -0
  55. data/doc/imported/0005-elixir-conf-2015-announced/metadata.txt +7 -0
  56. data/doc/imported/0005-elixir-conf-2015-announced/post.html +30 -0
  57. data/doc/imported/0005-elixir-conf-2015-announced/source.lt3 +16 -0
  58. data/doc/imported/0006-ruby-for-dinosaurs/metadata.txt +7 -0
  59. data/doc/imported/0006-ruby-for-dinosaurs/post.html +43 -0
  60. data/doc/imported/0006-ruby-for-dinosaurs/source.lt3 +27 -0
  61. data/doc/imported/0007-phoenix-isnt-rails/metadata.txt +7 -0
  62. data/doc/imported/0007-phoenix-isnt-rails/post.html +116 -0
  63. data/doc/imported/0007-phoenix-isnt-rails/source.lt3 +87 -0
  64. data/doc/imported/0008-concerning-the-term-monkeypatching/metadata.txt +7 -0
  65. data/doc/imported/0008-concerning-the-term-monkeypatching/post.html +129 -0
  66. data/doc/imported/0008-concerning-the-term-monkeypatching/source.lt3 +92 -0
  67. data/doc/imported/0009-announcement-coming-soon/metadata.txt +7 -0
  68. data/doc/imported/0009-announcement-coming-soon/post.html +33 -0
  69. data/doc/imported/0009-announcement-coming-soon/source.lt3 +19 -0
  70. data/doc/imported/0010-immutable-data-ditching-the-wax-tablet/metadata.txt +7 -0
  71. data/doc/imported/0010-immutable-data-ditching-the-wax-tablet/post.html +175 -0
  72. data/doc/imported/0010-immutable-data-ditching-the-wax-tablet/source.lt3 +139 -0
  73. data/doc/imported/0011-computer-science-as-a-lost-art/metadata.txt +7 -0
  74. data/doc/imported/0011-computer-science-as-a-lost-art/post.html +139 -0
  75. data/doc/imported/0011-computer-science-as-a-lost-art/source.lt3 +104 -0
  76. data/doc/imported/0012-ruby-day-in-turin-italy/metadata.txt +7 -0
  77. data/doc/imported/0012-ruby-day-in-turin-italy/post.html +42 -0
  78. data/doc/imported/0012-ruby-day-in-turin-italy/source.lt3 +24 -0
  79. data/doc/imported/0013-rubyday-was-a-success/metadata.txt +7 -0
  80. data/doc/imported/0013-rubyday-was-a-success/post.html +44 -0
  81. data/doc/imported/0013-rubyday-was-a-success/source.lt3 +27 -0
  82. data/doc/imported/0014-working-on-the-blogging-software/metadata.txt +7 -0
  83. data/doc/imported/0014-working-on-the-blogging-software/post.html +63 -0
  84. data/doc/imported/0014-working-on-the-blogging-software/source.lt3 +41 -0
  85. data/doc/imported/0015-ok-its-not-really-a-lost-art/metadata.txt +7 -0
  86. data/doc/imported/0015-ok-its-not-really-a-lost-art/post.html +172 -0
  87. data/doc/imported/0015-ok-its-not-really-a-lost-art/source.lt3 +134 -0
  88. data/doc/imported/0016-an-in-operator-for-ruby/metadata.txt +7 -0
  89. data/doc/imported/0016-an-in-operator-for-ruby/post.html +155 -0
  90. data/doc/imported/0016-an-in-operator-for-ruby/source.lt3 +106 -0
  91. data/doc/imported/0017-the-forgotten-mathematician/metadata.txt +7 -0
  92. data/doc/imported/0017-the-forgotten-mathematician/post.html +161 -0
  93. data/doc/imported/0017-the-forgotten-mathematician/source.lt3 +119 -0
  94. data/doc/imported/0018-ruby-puns/metadata.txt +7 -0
  95. data/doc/imported/0018-ruby-puns/post.html +46 -0
  96. data/doc/imported/0018-ruby-puns/source.lt3 +28 -0
  97. data/doc/imported/0019-custom-exceptions-via-metaprogramming/metadata.txt +7 -0
  98. data/doc/imported/0019-custom-exceptions-via-metaprogramming/post.html +138 -0
  99. data/doc/imported/0019-custom-exceptions-via-metaprogramming/source.lt3 +101 -0
  100. data/doc/imported/0020-fffff/metadata.txt +7 -0
  101. data/doc/imported/0020-fffff/post.html +24 -0
  102. data/doc/imported/0020-fffff/source.lt3 +12 -0
  103. data/doc/imported/0021-trying-ror-yet-again/metadata.txt +7 -0
  104. data/doc/imported/0021-trying-ror-yet-again/post.html +26 -0
  105. data/doc/imported/0021-trying-ror-yet-again/source.lt3 +12 -0
  106. data/doc/imported/0023-doctor-sleep/metadata.txt +7 -0
  107. data/doc/imported/0023-doctor-sleep/post.html +63 -0
  108. data/doc/imported/0023-doctor-sleep/source.lt3 +44 -0
  109. data/doc/imported/0024-just-a-test/metadata.txt +7 -0
  110. data/doc/imported/0024-just-a-test/post.html +24 -0
  111. data/doc/imported/0024-just-a-test/source.lt3 +12 -0
  112. data/doc/imported/import_summary.txt +98 -0
  113. data/doc/livetext-informal-spec.txt +65 -0
  114. data/doc/myuserdoc/ch-0.lt3 +31 -0
  115. data/doc/myuserdoc/ch-1.lt3 +37 -0
  116. data/doc/myuserdoc/ch-10.lt3 +22 -0
  117. data/doc/myuserdoc/ch-2.lt3 +37 -0
  118. data/doc/myuserdoc/ch-3.lt3 +19 -0
  119. data/doc/myuserdoc/ch-4.lt3 +43 -0
  120. data/doc/myuserdoc/ch-5.lt3 +22 -0
  121. data/doc/myuserdoc/ch-6.lt3 +19 -0
  122. data/doc/myuserdoc/ch-7.lt3 +16 -0
  123. data/doc/myuserdoc/ch-8.lt3 +13 -0
  124. data/doc/myuserdoc/ch-9.lt3 +19 -0
  125. data/doc/myuserdoc/tweak.rb +18 -0
  126. data/doc/myuserdoc/userdoc-toc.txt +88 -0
  127. data/doc/old-posts/0001-elixir-conf-2014.lt3 +24 -0
  128. data/doc/old-posts/0002-programmers-and-word-processing.lt3 +150 -0
  129. data/doc/old-posts/0003-how-to-turn-your-brain-sideways.lt3 +43 -0
  130. data/doc/old-posts/0004-upcoming-lone-star-ruby-conference.lt3 +26 -0
  131. data/doc/old-posts/0005-elixir-conf-2015-announced.lt3 +17 -0
  132. data/doc/old-posts/0006-ruby-for-dinosaurs.lt3 +30 -0
  133. data/doc/old-posts/0007-phoenix-isnt-rails.lt3 +90 -0
  134. data/doc/old-posts/0008-concerning-the-term-monkeypatching.lt3 +105 -0
  135. data/doc/old-posts/0009-announcement-coming-soon.lt3 +20 -0
  136. data/doc/old-posts/0010-immutable-data-ditching-the-wax-tablet.lt3 +142 -0
  137. data/doc/old-posts/0011-computer-science-as-a-lost-art.lt3 +117 -0
  138. data/doc/old-posts/0012-ruby-day-in-turin-italy.lt3 +26 -0
  139. data/doc/old-posts/0013-rubyday-was-a-success.lt3 +28 -0
  140. data/doc/old-posts/0014-working-on-the-blogging-software.lt3 +42 -0
  141. data/doc/old-posts/0015-ok-its-not-really-a-lost-art.lt3 +137 -0
  142. data/doc/old-posts/0016-an-in-operator-for-ruby.lt3 +142 -0
  143. data/doc/old-posts/0017-the-forgotten-mathematician.lt3 +129 -0
  144. data/doc/old-posts/0018-ruby-puns.lt3 +31 -0
  145. data/doc/old-posts/0019-custom-exceptions-via-metaprogramming.lt3 +116 -0
  146. data/doc/old-posts/0021-trying-ror-yet-again.lt3 +35 -0
  147. data/doc/old-posts/0023-doctor-sleep.lt3 +43 -0
  148. data/doc/old-posts/0024-just-a-test.lt3 +12 -0
  149. data/doc/old-posts/0025-trying-another-post.lt3 +12 -0
  150. data/doc/old-repo +1 -0
  151. data/doc/reddit_credentials_template.json +8 -0
  152. data/doc/reddit_integration.md +207 -0
  153. data/doc/user.lt3 +35 -0
  154. data/doc/user_guide_section_1.md +137 -0
  155. data/doc/user_guide_section_10.md +515 -0
  156. data/doc/user_guide_section_11.md +708 -0
  157. data/doc/user_guide_section_2.md +233 -0
  158. data/doc/user_guide_section_3.md +5 -0
  159. data/doc/user_guide_section_4.md +221 -0
  160. data/doc/user_guide_section_5.md +243 -0
  161. data/doc/user_guide_section_6.md +147 -0
  162. data/doc/user_guide_section_7.md +311 -0
  163. data/doc/user_guide_section_8.md +224 -0
  164. data/doc/user_guide_section_9.md +375 -0
  165. data/lib/rouge/lexers/livetext.rb +74 -0
  166. data/lib/scriptorium/api.rb +2373 -0
  167. data/lib/scriptorium/banner_svg.rb +729 -0
  168. data/lib/scriptorium/contract.rb +34 -0
  169. data/lib/scriptorium/exceptions.rb +201 -1
  170. data/lib/scriptorium/helpers.rb +675 -0
  171. data/lib/scriptorium/post.rb +259 -0
  172. data/lib/scriptorium/reddit.rb +83 -0
  173. data/lib/scriptorium/repo.rb +938 -0
  174. data/lib/scriptorium/standard_files.rb +149 -0
  175. data/lib/scriptorium/support/bootstrap/css.txt +5 -0
  176. data/lib/scriptorium/support/bootstrap/js.txt +4 -0
  177. data/lib/scriptorium/support/common_js/clipboard.js +35 -0
  178. data/lib/scriptorium/support/common_js/content-loader.js +187 -0
  179. data/lib/scriptorium/support/common_js/navigation.js +52 -0
  180. data/lib/scriptorium/support/common_js/syntax-highlighting.js +27 -0
  181. data/lib/scriptorium/support/config/reddit.txt +10 -0
  182. data/lib/scriptorium/support/config/reddit_template.txt +17 -0
  183. data/lib/scriptorium/support/config/social.txt +8 -0
  184. data/lib/scriptorium/support/highlight/css.txt +2 -0
  185. data/lib/scriptorium/support/highlight/custom.css +119 -0
  186. data/lib/scriptorium/support/highlight/js.txt +1 -0
  187. data/lib/scriptorium/support/post_index/config.txt +15 -0
  188. data/lib/scriptorium/support/post_index/style.css +55 -0
  189. data/lib/scriptorium/support/templates/index_entry.lt3 +16 -0
  190. data/lib/scriptorium/support/templates/initial_post.lt3 +12 -0
  191. data/lib/scriptorium/support/templates/layout.txt +5 -0
  192. data/lib/scriptorium/support/templates/post.lt3 +104 -0
  193. data/lib/scriptorium/support/theme/footer.lt3 +2 -0
  194. data/lib/scriptorium/support/theme/header.lt3 +4 -0
  195. data/lib/scriptorium/support/theme/left.lt3 +3 -0
  196. data/lib/scriptorium/support/theme/main.lt3 +5 -0
  197. data/lib/scriptorium/support/theme/right.lt3 +3 -0
  198. data/lib/scriptorium/theme.rb +192 -0
  199. data/lib/scriptorium/version.rb +1 -1
  200. data/lib/scriptorium/view.rb +1021 -0
  201. data/lib/scriptorium/widgets/featured_posts.rb +149 -0
  202. data/lib/scriptorium/widgets/links.rb +112 -0
  203. data/lib/scriptorium/widgets/pages.rb +133 -0
  204. data/lib/scriptorium/widgets/widget.rb +133 -0
  205. data/lib/scriptorium.rb +38 -34
  206. data/lib/skeleton.rb +10 -1
  207. data/scriptorium.gemspec +17 -5
  208. data/test/README.md +69 -0
  209. data/test/WEB_INTEGRATION_README.md +196 -0
  210. data/test/all +83 -0
  211. data/test/api_demo.rb +99 -0
  212. data/test/assets/imagenotfound.jpg +0 -0
  213. data/test/assets/images/.DS_Store +0 -0
  214. data/test/assets/images/README.md +27 -0
  215. data/test/assets/images/odd_aspect.png +0 -0
  216. data/test/assets/images/perfect.png +0 -0
  217. data/test/assets/images/small.png +0 -0
  218. data/test/assets/images/tall.png +0 -0
  219. data/test/assets/images/very_tall.png +0 -0
  220. data/test/assets/images/very_wide.png +0 -0
  221. data/test/assets/images/wide.png +0 -0
  222. data/test/assets/testbanner.jpg +0 -0
  223. data/test/banner_svg/simple_helpers.rb +13 -0
  224. data/test/banner_svg/unit.rb +1000 -0
  225. data/test/config/deployment.txt +5 -0
  226. data/test/ed_test.rb +204 -0
  227. data/test/integration/cursor_banner_combinations.rb +193 -0
  228. data/test/integration/cursor_banner_features.rb +374 -0
  229. data/test/integration/integration_test.rb +326 -0
  230. data/test/integration/preview_flow_test.rb +94 -0
  231. data/test/livetext_plugin_test.rb +500 -0
  232. data/test/manual/asset_mgmt.rb +67 -0
  233. data/test/manual/banner-tests/index.html +45 -0
  234. data/test/manual/banner-tests/svg.txt +3 -0
  235. data/test/manual/banner-tests/test01.html +122 -0
  236. data/test/manual/banner-tests/test02.html +122 -0
  237. data/test/manual/banner-tests/test03.html +122 -0
  238. data/test/manual/banner-tests/test04.html +129 -0
  239. data/test/manual/banner-tests/test05.html +129 -0
  240. data/test/manual/banner-tests/test06.html +129 -0
  241. data/test/manual/banner-tests/test07.html +129 -0
  242. data/test/manual/banner-tests/test08.html +123 -0
  243. data/test/manual/banner-tests/test09.html +123 -0
  244. data/test/manual/banner-tests/test10.html +123 -0
  245. data/test/manual/banner-tests/test11.html +123 -0
  246. data/test/manual/banner-tests/test12.html +123 -0
  247. data/test/manual/banner-tests/test13.html +123 -0
  248. data/test/manual/banner-tests/test14.html +123 -0
  249. data/test/manual/banner-tests/test15.html +122 -0
  250. data/test/manual/banner-tests/test16.html +122 -0
  251. data/test/manual/banner-tests/test17.html +122 -0
  252. data/test/manual/banner-tests/test18.html +132 -0
  253. data/test/manual/banner-tests/test19.html +132 -0
  254. data/test/manual/banner-tests/test20.html +132 -0
  255. data/test/manual/banner-tests/test21.html +132 -0
  256. data/test/manual/banner-tests/test22.html +132 -0
  257. data/test/manual/banner-tests/test23.html +132 -0
  258. data/test/manual/banner-tests/test24.html +132 -0
  259. data/test/manual/banner-tests/test25.html +131 -0
  260. data/test/manual/banner_environment.rb +205 -0
  261. data/test/manual/codemirror_demo.html +773 -0
  262. data/test/manual/create_posts_for_web.rb +114 -0
  263. data/test/manual/environment.rb +67 -0
  264. data/test/manual/make_banner.rb +153 -0
  265. data/test/manual/preview_manual_test.rb +129 -0
  266. data/test/manual/sample_banner_config.txt +12 -0
  267. data/test/manual/test_advanced_widgets.rb +73 -0
  268. data/test/manual/test_banner_combinations.rb +120 -0
  269. data/test/manual/test_banner_features.rb +306 -0
  270. data/test/manual/test_banner_integration.rb +115 -0
  271. data/test/manual/test_banner_radial.rb +87 -0
  272. data/test/manual/test_basic_posts.rb +47 -0
  273. data/test/manual/test_layout_widgets.rb +40 -0
  274. data/test/manual/test_pagination.rb +24 -0
  275. data/test/manual/test_random_posts.rb +38 -0
  276. data/test/manual/test_syntax_highlighting.rb +167 -0
  277. data/test/rubytext/rubytext_comprehensive_test.rb +307 -0
  278. data/test/rubytext/rubytext_demo_test.rb +42 -0
  279. data/test/rubytext/rubytext_testing_guide.md +277 -0
  280. data/test/run_automated_tests.rb +45 -0
  281. data/test/staging/.DS_Store +0 -0
  282. data/test/support/preview_utils.rb +88 -0
  283. data/test/syntax_highlighting_test.lt3 +124 -0
  284. data/test/test_gem_assets.rb +48 -0
  285. data/test/test_helpers.rb +240 -0
  286. data/test/tui_editor_integration_test.rb +296 -0
  287. data/test/tui_integration_test.rb +883 -0
  288. data/test/unit/api.rb +1776 -0
  289. data/test/unit/asset_management.rb +219 -0
  290. data/test/unit/backup_test.rb +451 -0
  291. data/test/unit/clipboard_test.rb +60 -0
  292. data/test/unit/contract_test.rb +69 -0
  293. data/test/unit/core.rb +1211 -0
  294. data/test/unit/deploy_config_test.rb +248 -0
  295. data/test/unit/deploy_test.rb +478 -0
  296. data/test/unit/edit_post_test.rb +168 -0
  297. data/test/unit/gem_asset_management.rb +183 -0
  298. data/test/unit/livetext_basic.rb +57 -0
  299. data/test/unit/livetext_compatibility.rb +82 -0
  300. data/test/unit/parse_cmd_test.rb +260 -0
  301. data/test/unit/permalink_copy_test.rb +211 -0
  302. data/test/unit/post.rb +309 -0
  303. data/test/unit/post_index_config_test.rb +258 -0
  304. data/test/unit/post_state_helpers_test.rb +137 -0
  305. data/test/unit/read_commented_file_test.rb +278 -0
  306. data/test/unit/reddit_test.rb +235 -0
  307. data/test/unit/repo.rb +569 -0
  308. data/test/unit/social_test.rb +366 -0
  309. data/test/unit/syntax_highlighting.rb +70 -0
  310. data/test/unit/theme_management_test.rb +91 -0
  311. data/test/unit/view.rb +498 -0
  312. data/test/unit/widgets.rb +669 -0
  313. data/test/web_integration_test.rb +231 -0
  314. data/test/web_test_helper.rb +218 -0
  315. data/test/web_workflow_test.rb +527 -0
  316. data/test/wizard_test.rb +123 -0
  317. data/ui/README.md +67 -0
  318. data/ui/common/lib/ui_common.rb +8 -0
  319. data/ui/rubytext/README.md +191 -0
  320. data/ui/rubytext/bin/scriptorium-rubytext +402 -0
  321. data/ui/rubytext/lib/rubytext_ui.rb +300 -0
  322. data/ui/tui/bin/scriptorium +1890 -0
  323. data/ui/tui/test/tui_test.rb +23 -0
  324. data/ui/web/app/app.rb +2600 -0
  325. data/ui/web/app/assets/livetext_mode.js +244 -0
  326. data/ui/web/app/error_helpers.rb +150 -0
  327. data/ui/web/app/views/advanced_config.erb +196 -0
  328. data/ui/web/app/views/asset_management.erb +645 -0
  329. data/ui/web/app/views/backup_management.erb +238 -0
  330. data/ui/web/app/views/banner_config.erb +200 -0
  331. data/ui/web/app/views/config_widget.erb +232 -0
  332. data/ui/web/app/views/configure_view.erb +401 -0
  333. data/ui/web/app/views/dashboard.erb +154 -0
  334. data/ui/web/app/views/deploy_config.erb +149 -0
  335. data/ui/web/app/views/edit_pages.erb +363 -0
  336. data/ui/web/app/views/edit_post.erb +175 -0
  337. data/ui/web/app/views/edit_theme.erb +73 -0
  338. data/ui/web/app/views/edit_theme_file.erb +74 -0
  339. data/ui/web/app/views/error_page.erb +29 -0
  340. data/ui/web/app/views/header_config.erb +155 -0
  341. data/ui/web/app/views/layout_config.erb +147 -0
  342. data/ui/web/app/views/navbar_config.erb +411 -0
  343. data/ui/web/app/views/theme_management.erb +130 -0
  344. data/ui/web/app/views/view_dashboard.erb +779 -0
  345. data/ui/web/app/views/widgets.erb +249 -0
  346. data/ui/web/bin/scriptorium-web +164 -0
  347. data/ui/web/test/web_basic_test.rb +38 -0
  348. data/ui/web/test_navbar.txt +7 -0
  349. data/ui/web/tmp/timing.log +17 -0
  350. data/ui/web/tmp/web_server.log +0 -0
  351. metadata +434 -8
  352. data/lib/scriptorium/engine.rb +0 -22
  353. data/test/engine/unit.rb +0 -44
@@ -0,0 +1,167 @@
1
+ require_relative "./environment"
2
+
3
+ manual_setup
4
+
5
+ @repo.create_view("testview", "Test View", "A test view for manual inspection")
6
+
7
+ # Ensure Highlight.js is enabled via global-head.txt
8
+ global_head_file = "test/scriptorium-TEST/views/testview/config/global-head.txt"
9
+ head_contents = File.exist?(global_head_file) ? File.read(global_head_file) : ""
10
+ add_lines = []
11
+ add_lines << "highlight # Enable Highlight.js assets" unless head_contents.include?("\nhighlight")
12
+ add_lines << "highlight_custom # Optional Highlight.js CSS overrides" unless head_contents.include?("\nhighlight_custom")
13
+ unless add_lines.empty?
14
+ File.open(global_head_file, "a") { |f| add_lines.each { |ln| f.puts ln } }
15
+ end
16
+
17
+ # Post with comprehensive syntax highlighting tests
18
+ draft_body = <<~'BODY'
19
+ .blurb
20
+ Testing Highlight.js syntax highlighting with multiple languages.
21
+ .end
22
+ This post tests the integrated syntax highlighters with Ruby, Elixir, JavaScript, and plain text.
23
+
24
+ ## Ruby Code Example (Rouge)
25
+
26
+ .code ruby
27
+ class User
28
+ attr_accessor :name, :email
29
+
30
+ def initialize(name, email)
31
+ @name = name
32
+ @email = email
33
+ end
34
+
35
+ def greet
36
+ puts "Hello, #{@name}!"
37
+ end
38
+
39
+ def valid_email?
40
+ email.match?(/\\A[\\w+\\-.]+@[a-z\\d\\-]+(\\.[a-z\\d\\-]+)*\\.[a-z]+\\z/i)
41
+ end
42
+ end
43
+
44
+ user = User.new("Alice", "alice@example.com")
45
+ user.greet
46
+ .end
47
+
48
+ ## Elixir Code Example (Rouge)
49
+
50
+ .code elixir
51
+ defmodule Calculator do
52
+ def add(a, b), do: a + b
53
+ def subtract(a, b), do: a - b
54
+ def multiply(a, b), do: a * b
55
+ def divide(a, b) when b != 0, do: a / b
56
+ def divide(_, 0), do: {:error, "Division by zero"}
57
+
58
+ def calculate(operation, a, b) do
59
+ case operation do
60
+ :add -> add(a, b)
61
+ :subtract -> subtract(a, b)
62
+ :multiply -> multiply(a, b)
63
+ :divide -> divide(a, b)
64
+ _ -> {:error, "Unknown operation"}
65
+ end
66
+ end
67
+ end
68
+
69
+ # Test the calculator
70
+ IO.puts("5 + 3 = 8")
71
+ .end
72
+
73
+ ## JavaScript Code Example (Highlight.js)
74
+
75
+ .code javascript
76
+ class TodoList {
77
+ constructor() {
78
+ this.todos = [];
79
+ this.nextId = 1;
80
+ }
81
+
82
+ addTodo(text, completed = false) {
83
+ const todo = {
84
+ id: this.nextId++,
85
+ text: text,
86
+ completed: completed,
87
+ createdAt: new Date()
88
+ };
89
+
90
+ this.todos.push(todo);
91
+ return todo;
92
+ }
93
+
94
+ toggleTodo(id) {
95
+ const todo = this.todos.find(t => t.id === id);
96
+ if (todo) {
97
+ todo.completed = !todo.completed;
98
+ }
99
+ return todo;
100
+ }
101
+ }
102
+
103
+ // Usage example
104
+ const todoList = new TodoList();
105
+ todoList.addTodo("Learn syntax highlighting");
106
+ todoList.addTodo("Test multiple languages");
107
+ .end
108
+
109
+ ## Simple Ruby Example
110
+
111
+ .code ruby
112
+ def hello_world
113
+ puts "Hello, World!"
114
+ @greeting = "Welcome to Scriptorium"
115
+ return @greeting
116
+ end
117
+ .end
118
+
119
+ ## Plain Text Example
120
+
121
+ .code text
122
+ This is just plain text
123
+ No syntax highlighting needed
124
+ But it should still be in a code block
125
+ .end
126
+
127
+ ## Test Results
128
+
129
+ Each code block above should display with proper syntax highlighting:
130
+
131
+ - **Ruby (Rouge)**: Keywords in red, strings in blue, variables in orange
132
+ - **Elixir (Rouge)**: Functions in purple, atoms in green, strings in blue
133
+ - **JavaScript (Highlight.js)**: Keywords in red, functions in purple, strings in blue
134
+ - **Plain text**: No highlighting, just code block formatting
135
+
136
+ Rouge and Highlight.js highlighting should work automatically!
137
+ BODY
138
+
139
+ name = @repo.create_draft(title: "Comprehensive Syntax Highlighting Test", views: ["testview"], body: draft_body)
140
+ num = @repo.finish_draft(name)
141
+ @repo.generate_post(num)
142
+
143
+ @repo.generate_front_page("testview")
144
+
145
+ # Open the generated post directly (works under simple httpd without SPA)
146
+ unless ARGV.include?("--automated")
147
+ post_url = "http://127.0.0.1:8000/scriptorium-TEST/views/testview/output/posts/0001-comprehensive-syntax-highlighting-test.html"
148
+ puts "Press Enter to open the post directly to verify highlighting."
149
+ STDIN.gets
150
+ system("open #{post_url}")
151
+ end
152
+
153
+ instruct <<~EOS
154
+ Front page should have one post with comprehensive syntax highlighting.
155
+
156
+ Highlight.js (Ruby, Elixir, JavaScript):
157
+ - Ruby/Elixir/JS: Token colors applied client-side
158
+
159
+ Plain text: No highlighting, just code block formatting
160
+
161
+ Check that Highlight.js CSS/JS are included in the generated HTML.
162
+ All code blocks should have proper token classes and syntax highlighting.
163
+ Then open the post directly to verify:
164
+ http://127.0.0.1:8000/scriptorium-TEST/views/testview/output/posts/0001-comprehensive-syntax-highlighting-test.html
165
+ EOS
166
+
167
+ examine("testview")
@@ -0,0 +1,307 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'minitest/autorun'
4
+ require 'pty'
5
+ require 'expect'
6
+ require 'timeout'
7
+ require 'tempfile'
8
+
9
+ class RubyTextComprehensiveTest < Minitest::Test
10
+ # Test categories for RubyText
11
+
12
+ def test_001_basic_initialization
13
+ # Test that RubyText can start without errors
14
+ PTY.spawn('ruby -e "require \"rubytext\"; RubyText.start { puts \"Hello\"; gets }"') do |read, write, pid|
15
+ begin
16
+ # Wait for RubyText to start
17
+ result = read.expect(/Hello/, 5)
18
+ assert result, "RubyText should start and display 'Hello'"
19
+
20
+ # Send quit command
21
+ write.puts "q"
22
+ Process.wait(pid)
23
+ assert_equal 0, $?.exitstatus
24
+ ensure
25
+ Process.kill('TERM', pid) rescue nil
26
+ end
27
+ end
28
+ end
29
+
30
+ def test_002_menu_functionality
31
+ # Test menu creation and interaction
32
+ menu_script = <<~RUBY
33
+ require 'rubytext'
34
+ RubyText.start do
35
+ menu = RubyText::Menu.new(["Option 1", "Option 2", "Option 3"])
36
+ result = menu.show
37
+ puts "Selected: #{result}"
38
+ gets
39
+ end
40
+ RUBY
41
+
42
+ PTY.spawn("ruby -e \"#{menu_script}\"") do |read, write, pid|
43
+ begin
44
+ # Wait for menu to appear
45
+ read.expect(/Option 1/, 5)
46
+
47
+ # Navigate and select
48
+ write.puts "\e[B" # Down arrow
49
+ sleep 0.1
50
+ write.puts "\r" # Enter
51
+
52
+ # Check result
53
+ result = read.expect(/Selected: Option 2/, 5)
54
+ assert result, "Menu should return selected option"
55
+
56
+ write.puts "q"
57
+ Process.wait(pid)
58
+ ensure
59
+ Process.kill('TERM', pid) rescue nil
60
+ end
61
+ end
62
+ end
63
+
64
+ def test_003_screen_rendering
65
+ # Test screen rendering and layout
66
+ screen_script = <<~RUBY
67
+ require 'rubytext'
68
+ RubyText.start do
69
+ screen = RubyText::Screen.new(80, 24)
70
+ screen.puts("Test content")
71
+ screen.refresh
72
+ gets
73
+ end
74
+ RUBY
75
+
76
+ PTY.spawn("ruby -e \"#{screen_script}\"") do |read, write, pid|
77
+ begin
78
+ # Wait for content to appear
79
+ result = read.expect(/Test content/, 5)
80
+ assert result, "Screen should display content"
81
+
82
+ write.puts "q"
83
+ Process.wait(pid)
84
+ ensure
85
+ Process.kill('TERM', pid) rescue nil
86
+ end
87
+ end
88
+ end
89
+
90
+ def test_004_input_handling
91
+ # Test various input methods
92
+ input_script = <<~RUBY
93
+ require 'rubytext'
94
+ RubyText.start do
95
+ puts "Press any key..."
96
+ key = RubyText.getch
97
+ puts "Key pressed: #{key.inspect}"
98
+ gets
99
+ end
100
+ RUBY
101
+
102
+ PTY.spawn("ruby -e \"#{input_script}\"") do |read, write, pid|
103
+ begin
104
+ read.expect(/Press any key/, 5)
105
+
106
+ # Send a key
107
+ write.puts "a"
108
+
109
+ result = read.expect(/Key pressed/, 5)
110
+ assert result, "Should detect key press"
111
+
112
+ write.puts "q"
113
+ Process.wait(pid)
114
+ ensure
115
+ Process.kill('TERM', pid) rescue nil
116
+ end
117
+ end
118
+ end
119
+
120
+ def test_005_color_and_style
121
+ # Test color and style functionality
122
+ color_script = <<~RUBY
123
+ require 'rubytext'
124
+ RubyText.start do
125
+ RubyText.color(:red) { puts "Red text" }
126
+ RubyText.color(:blue) { puts "Blue text" }
127
+ RubyText.bold { puts "Bold text" }
128
+ gets
129
+ end
130
+ RUBY
131
+
132
+ PTY.spawn("ruby -e \"#{color_script}\"") do |read, write, pid|
133
+ begin
134
+ # Check for colored output (this might be hard to test in PTY)
135
+ result = read.expect(/Red text|Blue text|Bold text/, 5)
136
+ assert result, "Should display styled text"
137
+
138
+ write.puts "q"
139
+ Process.wait(pid)
140
+ ensure
141
+ Process.kill('TERM', pid) rescue nil
142
+ end
143
+ end
144
+ end
145
+
146
+ def test_006_window_management
147
+ # Test window creation and management
148
+ window_script = <<~RUBY
149
+ require 'rubytext'
150
+ RubyText.start do
151
+ window = RubyText::Window.new(10, 5, 5, 5)
152
+ window.puts("Window content")
153
+ window.refresh
154
+ gets
155
+ end
156
+ RUBY
157
+
158
+ PTY.spawn("ruby -e \"#{window_script}\"") do |read, write, pid|
159
+ begin
160
+ result = read.expect(/Window content/, 5)
161
+ assert result, "Window should display content"
162
+
163
+ write.puts "q"
164
+ Process.wait(pid)
165
+ ensure
166
+ Process.kill('TERM', pid) rescue nil
167
+ end
168
+ end
169
+ end
170
+
171
+ def test_007_error_handling
172
+ # Test error handling and recovery
173
+ error_script = <<~RUBY
174
+ require 'rubytext'
175
+ begin
176
+ RubyText.start do
177
+ # Try to do something that might cause an error
178
+ RubyText::Screen.new(-1, -1) # Invalid dimensions
179
+ end
180
+ rescue => e
181
+ puts "Error caught: #{e.class}"
182
+ exit 0
183
+ end
184
+ RUBY
185
+
186
+ PTY.spawn("ruby -e \"#{error_script}\"") do |read, write, pid|
187
+ begin
188
+ result = read.expect(/Error caught/, 5)
189
+ assert result, "Should handle errors gracefully"
190
+
191
+ Process.wait(pid)
192
+ assert_equal 0, $?.exitstatus
193
+ ensure
194
+ Process.kill('TERM', pid) rescue nil
195
+ end
196
+ end
197
+ end
198
+
199
+ def test_008_performance
200
+ # Test performance with large content
201
+ performance_script = <<~RUBY
202
+ require 'rubytext'
203
+ require 'benchmark'
204
+
205
+ RubyText.start do
206
+ time = Benchmark.measure do
207
+ 100.times do |i|
208
+ puts "Line #{i}: " + "x" * 50
209
+ end
210
+ end
211
+ puts "Rendering time: #{time.real}s"
212
+ gets
213
+ end
214
+ RUBY
215
+
216
+ PTY.spawn("ruby -e \"#{performance_script}\"") do |read, write, pid|
217
+ begin
218
+ result = read.expect(/Rendering time/, 10)
219
+ assert result, "Should complete performance test"
220
+
221
+ write.puts "q"
222
+ Process.wait(pid)
223
+ ensure
224
+ Process.kill('TERM', pid) rescue nil
225
+ end
226
+ end
227
+ end
228
+
229
+ def test_009_integration_scenarios
230
+ # Test real-world usage scenarios
231
+ scenarios = [
232
+ {
233
+ name: "Simple menu navigation",
234
+ script: <<~RUBY,
235
+ require 'rubytext'
236
+ RubyText.start do
237
+ menu = RubyText::Menu.new(["Edit", "View", "Quit"])
238
+ result = menu.show
239
+ puts "Selected: #{result}"
240
+ gets
241
+ end
242
+ RUBY
243
+ expected: /Selected: (Edit|View|Quit)/
244
+ },
245
+ {
246
+ name: "Form input",
247
+ script: <<~RUBY,
248
+ require 'rubytext'
249
+ RubyText.start do
250
+ puts "Enter your name:"
251
+ name = gets.chomp
252
+ puts "Hello, #{name}!"
253
+ gets
254
+ end
255
+ RUBY
256
+ expected: /Hello, TestUser!/
257
+ }
258
+ ]
259
+
260
+ scenarios.each do |scenario|
261
+ PTY.spawn("ruby -e \"#{scenario[:script]}\"") do |read, write, pid|
262
+ begin
263
+ # Wait for prompt
264
+ read.expect(/Enter your name:|Menu/, 5)
265
+
266
+ # Send input
267
+ if scenario[:name].include?("menu")
268
+ write.puts "\r" # Select first option
269
+ else
270
+ write.puts "TestUser"
271
+ write.puts "\r"
272
+ end
273
+
274
+ # Check result
275
+ result = read.expect(scenario[:expected], 5)
276
+ assert result, "Scenario '#{scenario[:name]}' should work"
277
+
278
+ write.puts "q"
279
+ Process.wait(pid)
280
+ ensure
281
+ Process.kill('TERM', pid) rescue nil
282
+ end
283
+ end
284
+ end
285
+ end
286
+
287
+ private
288
+
289
+ def load_expected_screens
290
+ # Load expected screen states from fixtures
291
+ screens = []
292
+ fixture_dir = "test/fixtures/rubytext_screens"
293
+ if Dir.exist?(fixture_dir)
294
+ Dir.glob("#{fixture_dir}/*.txt").sort.each do |file|
295
+ screens << File.read(file)
296
+ end
297
+ end
298
+ screens
299
+ end
300
+
301
+ def capture_current_screens
302
+ # Capture current screen states for comparison
303
+ screens = []
304
+ # Implementation would depend on RubyText's screen capture capabilities
305
+ screens
306
+ end
307
+ end
@@ -0,0 +1,42 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'minitest/autorun'
4
+ require 'pty'
5
+ require 'expect'
6
+ require 'timeout'
7
+
8
+ class RubyTextDemoTest < Minitest::Test
9
+ # Test the demo/slideshow functionality
10
+ def test_001_demo_automation
11
+ # Run the demo in automated mode
12
+ PTY.spawn('ruby -e "require \"rubytext\"; RubyText.start { demo_mode }"') do |read, write, pid|
13
+ begin
14
+ # Wait for demo to start
15
+ read.expect(/Demo/, 10)
16
+
17
+ # Send navigation commands
18
+ write.puts "n" # next slide
19
+ sleep 0.5
20
+ write.puts "n" # next slide
21
+ sleep 0.5
22
+ write.puts "q" # quit
23
+
24
+ # Should exit cleanly
25
+ Process.wait(pid)
26
+ assert_equal 0, $?.exitstatus
27
+ ensure
28
+ Process.kill('TERM', pid) rescue nil
29
+ end
30
+ end
31
+ end
32
+
33
+ def test_002_slideshow_regression
34
+ # Capture expected screen states and compare
35
+ expected_screens = load_expected_screens
36
+ current_screens = capture_current_screens
37
+
38
+ expected_screens.each_with_index do |expected, index|
39
+ assert_equal expected, current_screens[index], "Screen #{index} doesn't match expected"
40
+ end
41
+ end
42
+ end