scriptorium 0.6.1 → 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 (358) hide show
  1. checksums.yaml +4 -4
  2. data/assets/icons/social/reddit.png +0 -0
  3. data/assets/icons/social/x-logo.png +0 -0
  4. data/assets/imagenotfound.jpg +0 -0
  5. data/bin/sblog +84 -5
  6. data/bin/scriptorium +1 -0
  7. data/doc/anti-amnesia/20250727-054000-scriptorium-overview.md +0 -1
  8. data/doc/anti-amnesia/20250727-123000-anti-amnesia-conventions.md +0 -29
  9. data/doc/anti-amnesia/20250727-172600-cursor-rbenv-ruby-version-mystery.md +0 -19
  10. data/doc/anti-amnesia/20250727-172900-ai-cognitive-assessment-capabilities.md +1 -1
  11. data/doc/anti-amnesia/20250728-124243-aaa-syntax-clarification.md +1 -1
  12. data/doc/anti-amnesia/20250729-210000-reddit-autopost-integration-complete.md +1 -1
  13. data/doc/anti-amnesia/20250804-190500-cognitive-loop-bug.md +0 -10
  14. data/doc/anti-amnesia/20250804-190700-anti-amnesia-timestamping-fix.md +1 -4
  15. data/doc/anti-amnesia/20250901-211714-codemirror-integration-and-web-tests.md +172 -0
  16. data/doc/anti-amnesia/20250902-002402-backup-restore-system.md +126 -0
  17. data/doc/anti-amnesia/20250907-203339-backup-metadata-implementation.md +66 -0
  18. data/doc/imported/0001-elixir-conf-2014/metadata.txt +7 -0
  19. data/doc/imported/0001-elixir-conf-2014/post.html +37 -0
  20. data/doc/imported/0001-elixir-conf-2014/source.lt3 +22 -0
  21. data/doc/imported/0002-programmers-and-word-processing/metadata.txt +7 -0
  22. data/doc/imported/0002-programmers-and-word-processing/post.html +192 -0
  23. data/doc/imported/0002-programmers-and-word-processing/source.lt3 +146 -0
  24. data/doc/imported/0003-how-to-turn-your-brain-sideways/metadata.txt +7 -0
  25. data/doc/imported/0003-how-to-turn-your-brain-sideways/post.html +60 -0
  26. data/doc/imported/0003-how-to-turn-your-brain-sideways/source.lt3 +40 -0
  27. data/doc/imported/0004-upcoming-lone-star-ruby-conference/metadata.txt +7 -0
  28. data/doc/imported/0004-upcoming-lone-star-ruby-conference/post.html +42 -0
  29. data/doc/imported/0004-upcoming-lone-star-ruby-conference/source.lt3 +24 -0
  30. data/doc/imported/0005-elixir-conf-2015-announced/metadata.txt +7 -0
  31. data/doc/imported/0005-elixir-conf-2015-announced/post.html +30 -0
  32. data/doc/imported/0005-elixir-conf-2015-announced/source.lt3 +16 -0
  33. data/doc/imported/0006-ruby-for-dinosaurs/metadata.txt +7 -0
  34. data/doc/imported/0006-ruby-for-dinosaurs/post.html +43 -0
  35. data/doc/imported/0006-ruby-for-dinosaurs/source.lt3 +27 -0
  36. data/doc/imported/0007-phoenix-isnt-rails/metadata.txt +7 -0
  37. data/doc/imported/0007-phoenix-isnt-rails/post.html +116 -0
  38. data/doc/imported/0007-phoenix-isnt-rails/source.lt3 +87 -0
  39. data/doc/imported/0008-concerning-the-term-monkeypatching/metadata.txt +7 -0
  40. data/doc/imported/0008-concerning-the-term-monkeypatching/post.html +129 -0
  41. data/doc/imported/0008-concerning-the-term-monkeypatching/source.lt3 +92 -0
  42. data/doc/imported/0009-announcement-coming-soon/metadata.txt +7 -0
  43. data/doc/imported/0009-announcement-coming-soon/post.html +33 -0
  44. data/doc/imported/0009-announcement-coming-soon/source.lt3 +19 -0
  45. data/doc/imported/0010-immutable-data-ditching-the-wax-tablet/metadata.txt +7 -0
  46. data/doc/imported/0010-immutable-data-ditching-the-wax-tablet/post.html +175 -0
  47. data/doc/imported/0010-immutable-data-ditching-the-wax-tablet/source.lt3 +139 -0
  48. data/doc/imported/0011-computer-science-as-a-lost-art/metadata.txt +7 -0
  49. data/doc/imported/0011-computer-science-as-a-lost-art/post.html +139 -0
  50. data/doc/imported/0011-computer-science-as-a-lost-art/source.lt3 +104 -0
  51. data/doc/imported/0012-ruby-day-in-turin-italy/metadata.txt +7 -0
  52. data/doc/imported/0012-ruby-day-in-turin-italy/post.html +42 -0
  53. data/doc/imported/0012-ruby-day-in-turin-italy/source.lt3 +24 -0
  54. data/doc/imported/0013-rubyday-was-a-success/metadata.txt +7 -0
  55. data/doc/imported/0013-rubyday-was-a-success/post.html +44 -0
  56. data/doc/imported/0013-rubyday-was-a-success/source.lt3 +27 -0
  57. data/doc/imported/0014-working-on-the-blogging-software/metadata.txt +7 -0
  58. data/doc/imported/0014-working-on-the-blogging-software/post.html +63 -0
  59. data/doc/imported/0014-working-on-the-blogging-software/source.lt3 +41 -0
  60. data/doc/imported/0015-ok-its-not-really-a-lost-art/metadata.txt +7 -0
  61. data/doc/imported/0015-ok-its-not-really-a-lost-art/post.html +172 -0
  62. data/doc/imported/0015-ok-its-not-really-a-lost-art/source.lt3 +134 -0
  63. data/doc/imported/0016-an-in-operator-for-ruby/metadata.txt +7 -0
  64. data/doc/imported/0016-an-in-operator-for-ruby/post.html +155 -0
  65. data/doc/imported/0016-an-in-operator-for-ruby/source.lt3 +106 -0
  66. data/doc/imported/0017-the-forgotten-mathematician/metadata.txt +7 -0
  67. data/doc/imported/0017-the-forgotten-mathematician/post.html +161 -0
  68. data/doc/imported/0017-the-forgotten-mathematician/source.lt3 +119 -0
  69. data/doc/imported/0018-ruby-puns/metadata.txt +7 -0
  70. data/doc/imported/0018-ruby-puns/post.html +46 -0
  71. data/doc/imported/0018-ruby-puns/source.lt3 +28 -0
  72. data/doc/imported/0019-custom-exceptions-via-metaprogramming/metadata.txt +7 -0
  73. data/doc/imported/0019-custom-exceptions-via-metaprogramming/post.html +138 -0
  74. data/doc/imported/0019-custom-exceptions-via-metaprogramming/source.lt3 +101 -0
  75. data/doc/imported/0020-fffff/metadata.txt +7 -0
  76. data/doc/imported/0020-fffff/post.html +24 -0
  77. data/doc/imported/0020-fffff/source.lt3 +12 -0
  78. data/doc/imported/0021-trying-ror-yet-again/metadata.txt +7 -0
  79. data/doc/imported/0021-trying-ror-yet-again/post.html +26 -0
  80. data/doc/imported/0021-trying-ror-yet-again/source.lt3 +12 -0
  81. data/doc/imported/0023-doctor-sleep/metadata.txt +7 -0
  82. data/doc/imported/0023-doctor-sleep/post.html +63 -0
  83. data/doc/imported/0023-doctor-sleep/source.lt3 +44 -0
  84. data/doc/imported/0024-just-a-test/metadata.txt +7 -0
  85. data/doc/imported/0024-just-a-test/post.html +24 -0
  86. data/doc/imported/0024-just-a-test/source.lt3 +12 -0
  87. data/doc/imported/import_summary.txt +98 -0
  88. data/doc/livetext-informal-spec.txt +65 -0
  89. data/doc/myuserdoc/ch-0.lt3 +31 -0
  90. data/doc/myuserdoc/ch-1.lt3 +37 -0
  91. data/doc/myuserdoc/ch-10.lt3 +22 -0
  92. data/doc/myuserdoc/ch-2.lt3 +37 -0
  93. data/doc/myuserdoc/ch-3.lt3 +19 -0
  94. data/doc/myuserdoc/ch-4.lt3 +43 -0
  95. data/doc/myuserdoc/ch-5.lt3 +22 -0
  96. data/doc/myuserdoc/ch-6.lt3 +19 -0
  97. data/doc/myuserdoc/ch-7.lt3 +16 -0
  98. data/doc/myuserdoc/ch-8.lt3 +13 -0
  99. data/doc/myuserdoc/ch-9.lt3 +19 -0
  100. data/doc/myuserdoc/tweak.rb +18 -0
  101. data/doc/{userdoc-toc.txt → myuserdoc/userdoc-toc.txt} +27 -27
  102. data/doc/old-posts/0001-elixir-conf-2014.lt3 +24 -0
  103. data/doc/old-posts/0002-programmers-and-word-processing.lt3 +150 -0
  104. data/doc/old-posts/0003-how-to-turn-your-brain-sideways.lt3 +43 -0
  105. data/doc/old-posts/0004-upcoming-lone-star-ruby-conference.lt3 +26 -0
  106. data/doc/old-posts/0005-elixir-conf-2015-announced.lt3 +17 -0
  107. data/doc/old-posts/0006-ruby-for-dinosaurs.lt3 +30 -0
  108. data/doc/old-posts/0007-phoenix-isnt-rails.lt3 +90 -0
  109. data/doc/old-posts/0008-concerning-the-term-monkeypatching.lt3 +105 -0
  110. data/doc/old-posts/0009-announcement-coming-soon.lt3 +20 -0
  111. data/doc/old-posts/0010-immutable-data-ditching-the-wax-tablet.lt3 +142 -0
  112. data/doc/old-posts/0011-computer-science-as-a-lost-art.lt3 +117 -0
  113. data/doc/old-posts/0012-ruby-day-in-turin-italy.lt3 +26 -0
  114. data/doc/old-posts/0013-rubyday-was-a-success.lt3 +28 -0
  115. data/doc/old-posts/0014-working-on-the-blogging-software.lt3 +42 -0
  116. data/doc/old-posts/0015-ok-its-not-really-a-lost-art.lt3 +137 -0
  117. data/doc/old-posts/0016-an-in-operator-for-ruby.lt3 +142 -0
  118. data/doc/old-posts/0017-the-forgotten-mathematician.lt3 +129 -0
  119. data/doc/old-posts/0018-ruby-puns.lt3 +31 -0
  120. data/doc/old-posts/0019-custom-exceptions-via-metaprogramming.lt3 +116 -0
  121. data/doc/old-posts/0021-trying-ror-yet-again.lt3 +35 -0
  122. data/doc/old-posts/0023-doctor-sleep.lt3 +43 -0
  123. data/doc/old-posts/0024-just-a-test.lt3 +12 -0
  124. data/doc/old-posts/0025-trying-another-post.lt3 +12 -0
  125. data/doc/old-repo +1 -0
  126. data/doc/reddit_integration.md +2 -2
  127. data/doc/user.lt3 +0 -3
  128. data/lib/scriptorium/api.rb +1811 -78
  129. data/lib/scriptorium/banner_svg.rb +55 -68
  130. data/lib/scriptorium/contract.rb +3 -2
  131. data/lib/scriptorium/exceptions.rb +133 -102
  132. data/lib/scriptorium/helpers.rb +282 -82
  133. data/lib/scriptorium/post.rb +81 -17
  134. data/lib/scriptorium/reddit.rb +1 -1
  135. data/lib/scriptorium/repo.rb +478 -164
  136. data/lib/scriptorium/standard_files.rb +30 -396
  137. data/lib/scriptorium/support/common_js/clipboard.js +35 -0
  138. data/lib/scriptorium/support/common_js/content-loader.js +187 -0
  139. data/lib/scriptorium/support/common_js/navigation.js +52 -0
  140. data/lib/scriptorium/support/common_js/syntax-highlighting.js +27 -0
  141. data/lib/scriptorium/support/config/reddit_template.txt +17 -0
  142. data/{test/scriptorium-TEST-1754622690-146/views/sample → lib/scriptorium/support}/config/social.txt +1 -0
  143. data/lib/scriptorium/support/highlight/css.txt +2 -0
  144. data/lib/scriptorium/support/highlight/custom.css +119 -0
  145. data/lib/scriptorium/support/highlight/js.txt +1 -0
  146. data/lib/scriptorium/support/post_index/config.txt +15 -0
  147. data/lib/scriptorium/support/post_index/style.css +55 -0
  148. data/lib/scriptorium/support/templates/index_entry.lt3 +16 -0
  149. data/{test/scriptorium-TEST-1754622690-146/themes/standard/initial/post.lt3 → lib/scriptorium/support/templates/initial_post.lt3} +5 -5
  150. data/lib/scriptorium/support/templates/post.lt3 +104 -0
  151. data/{test/scriptorium-TEST-1754622690-146/themes/standard/layout/config/header.txt → lib/scriptorium/support/theme/header.lt3} +1 -1
  152. data/lib/scriptorium/theme.rb +83 -70
  153. data/lib/scriptorium/version.rb +2 -2
  154. data/lib/scriptorium/view.rb +194 -149
  155. data/lib/scriptorium.rb +24 -1
  156. data/lib/skeleton.rb +4 -1
  157. data/scriptorium.gemspec +2 -1
  158. data/test/WEB_INTEGRATION_README.md +196 -0
  159. data/test/all +40 -0
  160. data/test/banner_svg/unit.rb +267 -35
  161. data/test/config/deployment.txt +5 -0
  162. data/test/integration/integration_test.rb +7 -7
  163. data/test/integration/preview_flow_test.rb +94 -0
  164. data/test/livetext_plugin_test.rb +453 -182
  165. data/test/manual/banner-tests/test01.html +82 -18
  166. data/test/manual/banner-tests/test02.html +82 -18
  167. data/test/manual/banner-tests/test03.html +82 -18
  168. data/test/manual/banner-tests/test04.html +89 -25
  169. data/test/manual/banner-tests/test05.html +89 -25
  170. data/test/manual/banner-tests/test06.html +89 -25
  171. data/test/manual/banner-tests/test07.html +89 -25
  172. data/test/manual/banner-tests/test08.html +82 -18
  173. data/test/manual/banner-tests/test09.html +82 -18
  174. data/test/manual/banner-tests/test10.html +82 -18
  175. data/test/manual/banner-tests/test11.html +82 -18
  176. data/test/manual/banner-tests/test12.html +82 -18
  177. data/test/manual/banner-tests/test13.html +82 -18
  178. data/test/manual/banner-tests/test14.html +82 -18
  179. data/test/manual/banner-tests/test15.html +82 -18
  180. data/test/manual/banner-tests/test16.html +82 -18
  181. data/test/manual/banner-tests/test17.html +82 -18
  182. data/test/manual/banner-tests/test18.html +90 -26
  183. data/test/manual/banner-tests/test19.html +90 -26
  184. data/test/manual/banner-tests/test20.html +90 -26
  185. data/test/manual/banner-tests/test21.html +90 -26
  186. data/test/manual/banner-tests/test22.html +90 -26
  187. data/test/manual/banner-tests/test23.html +90 -26
  188. data/test/manual/banner-tests/test24.html +90 -26
  189. data/test/manual/banner-tests/test25.html +89 -25
  190. data/test/manual/banner_environment.rb +15 -2
  191. data/test/manual/codemirror_demo.html +773 -0
  192. data/test/manual/create_posts_for_web.rb +114 -0
  193. data/test/manual/preview_manual_test.rb +129 -0
  194. data/test/manual/test_banner_features.rb +14 -14
  195. data/test/manual/test_banner_integration.rb +115 -0
  196. data/test/manual/test_banner_radial.rb +87 -0
  197. data/test/manual/test_syntax_highlighting.rb +60 -40
  198. data/test/support/preview_utils.rb +88 -0
  199. data/test/test_gem_assets.rb +48 -0
  200. data/test/test_helpers.rb +10 -0
  201. data/test/tui_editor_integration_test.rb +15 -15
  202. data/test/tui_integration_test.rb +687 -441
  203. data/test/unit/api.rb +757 -37
  204. data/test/unit/asset_management.rb +195 -221
  205. data/test/unit/backup_test.rb +451 -0
  206. data/test/unit/contract_test.rb +1 -23
  207. data/test/unit/core.rb +415 -61
  208. data/test/unit/deploy_config_test.rb +248 -0
  209. data/test/unit/deploy_test.rb +312 -21
  210. data/test/unit/edit_post_test.rb +168 -0
  211. data/test/unit/gem_asset_management.rb +36 -42
  212. data/test/unit/livetext_basic.rb +23 -35
  213. data/test/unit/livetext_compatibility.rb +7 -14
  214. data/test/unit/parse_cmd_test.rb +260 -0
  215. data/test/unit/{symlink_test.rb → permalink_copy_test.rb} +47 -49
  216. data/test/unit/post.rb +91 -26
  217. data/test/unit/post_index_config_test.rb +258 -0
  218. data/test/unit/post_state_helpers_test.rb +137 -0
  219. data/test/unit/read_commented_file_test.rb +8 -6
  220. data/test/unit/repo.rb +75 -54
  221. data/test/unit/social_test.rb +41 -44
  222. data/test/unit/syntax_highlighting.rb +70 -0
  223. data/test/unit/theme_management_test.rb +91 -0
  224. data/test/unit/view.rb +79 -12
  225. data/test/unit/widgets.rb +8 -8
  226. data/test/web_integration_test.rb +231 -0
  227. data/test/web_test_helper.rb +218 -0
  228. data/test/web_workflow_test.rb +527 -0
  229. data/ui/tui/bin/scriptorium +885 -415
  230. data/ui/web/app/app.rb +1398 -176
  231. data/ui/web/app/assets/livetext_mode.js +244 -0
  232. data/ui/web/app/error_helpers.rb +16 -16
  233. data/ui/web/app/views/advanced_config.erb +8 -2
  234. data/ui/web/app/views/asset_management.erb +56 -0
  235. data/ui/web/app/views/backup_management.erb +238 -0
  236. data/ui/web/app/views/config_widget.erb +232 -0
  237. data/ui/web/app/views/dashboard.erb +64 -72
  238. data/ui/web/app/views/deploy_config.erb +3 -0
  239. data/ui/web/app/views/edit_pages.erb +170 -2
  240. data/ui/web/app/views/edit_post.erb +130 -9
  241. data/ui/web/app/views/edit_theme.erb +73 -0
  242. data/ui/web/app/views/edit_theme_file.erb +74 -0
  243. data/ui/web/app/views/theme_management.erb +130 -0
  244. data/ui/web/app/views/view_dashboard.erb +666 -25
  245. data/ui/web/app/views/widgets.erb +249 -0
  246. data/ui/web/bin/scriptorium-web +35 -24
  247. data/ui/web/tmp/timing.log +17 -0
  248. data/ui/web/tmp/web_server.log +0 -5
  249. metadata +190 -116
  250. data/assets/back-icon.png +0 -0
  251. data/assets/icons/facebook.svg +0 -1
  252. data/assets/icons/github.svg +0 -1
  253. data/assets/icons/instagram.svg +0 -1
  254. data/assets/icons/reddit.svg +0 -1
  255. data/assets/icons/x.svg +0 -1
  256. data/assets/icons/youtube.svg +0 -1
  257. data/bin/scriptorium +0 -1511
  258. data/doc/anti-amnesia/20250727-060000-api-design-tui-planning.md +0 -34
  259. data/doc/anti-amnesia/20250727-061000-runeblog-tui-analysis.md +0 -50
  260. data/doc/anti-amnesia/20250727-154000-livetext-plugin-file-stats.md +0 -73
  261. data/doc/anti-amnesia/20250727-172600-unified-minitest-framework.md +0 -70
  262. data/doc/anti-amnesia/20250727-173000-widget-testing-achievement.md +0 -110
  263. data/doc/anti-amnesia/20250727-180000-post-id-num-refactoring.md +0 -73
  264. data/doc/anti-amnesia/20250728-124421-conversation-summary-concise.md +0 -124
  265. data/doc/anti-amnesia/20250729-190000-scriptorium-tui-testing-complete.md +0 -46
  266. data/doc/anti-amnesia/20250729-200000-scriptorium-tui-testing-edit-file-workflow.md +0 -97
  267. data/doc/anti-amnesia/20250729-211500-dependency-management-system.md +0 -211
  268. data/doc/anti-amnesia/20250729-213000-python-virtual-environment-setup.md +0 -141
  269. data/doc/anti-amnesia/20250729-214500-theme-management-commands.md +0 -211
  270. data/doc/anti-amnesia/20250729-215000-version-update-to-0.6.0.md +0 -134
  271. data/doc/anti-amnesia/20250729-220000-user-guide-complete.md +0 -41
  272. data/doc/anti-amnesia/20250804-213700-publishing-test-fix.md +0 -49
  273. data/doc/anti-amnesia/20250804-214400-additional-test-fixes.md +0 -46
  274. data/doc/anti-amnesia/20250804-220000-asset-function-logic-clarification.md +0 -41
  275. data/doc/anti-amnesia/20250806-202032-asset-function-logic-clarification.md +0 -41
  276. data/doc/anti-amnesia/20250813-082428-syntax-highlighting-and-navigation-improvements.md +0 -256
  277. data/lib/scriptorium/syntax_highlighter.rb +0 -234
  278. data/test/manual/deploy_symlink_demo.rb +0 -142
  279. data/test/manual/symlink_demo.rb +0 -117
  280. data/test/manual/test2.rb +0 -12
  281. data/test/manual/test_banner_from_file.rb +0 -150
  282. data/test/manual/test_banner_in_header.rb +0 -35
  283. data/test/manual/test_code_highlighting.rb +0 -68
  284. data/test/manual/test_complex_header.rb +0 -74
  285. data/test/manual/test_empty_header.rb +0 -32
  286. data/test/manual/test_radial_custom.rb +0 -58
  287. data/test/manual/test_radial_large_radius.rb +0 -52
  288. data/test/manual/test_svg_debug.rb +0 -47
  289. data/test/pages-demo/config/currentview.txt +0 -1
  290. data/test/pages-demo/views/demo/config/common.js +0 -57
  291. data/test/pages-demo/views/demo/config/footer.txt +0 -1
  292. data/test/pages-demo/views/demo/config/global-head.txt +0 -8
  293. data/test/pages-demo/views/demo/config/header.txt +0 -1
  294. data/test/pages-demo/views/demo/config/layout.txt +0 -1
  295. data/test/pages-demo/views/demo/config/left.txt +0 -1
  296. data/test/pages-demo/views/demo/config/main.txt +0 -1
  297. data/test/pages-demo/views/demo/config/right.txt +0 -1
  298. data/test/pages-demo/views/demo/config.txt +0 -3
  299. data/test/pages-demo/views/demo/output/panes/footer.html +0 -1
  300. data/test/pages-demo/views/demo/output/panes/header.html +0 -1
  301. data/test/pages-demo/views/demo/output/panes/left.html +0 -1
  302. data/test/pages-demo/views/demo/output/panes/main.html +0 -1
  303. data/test/pages-demo/views/demo/output/panes/right.html +0 -1
  304. data/test/scriptorium-TEST-1754622690-146/config/bootstrap_css.txt +0 -5
  305. data/test/scriptorium-TEST-1754622690-146/config/bootstrap_js.txt +0 -4
  306. data/test/scriptorium-TEST-1754622690-146/config/common.js +0 -57
  307. data/test/scriptorium-TEST-1754622690-146/config/currentview.txt +0 -1
  308. data/test/scriptorium-TEST-1754622690-146/config/global-head.txt +0 -9
  309. data/test/scriptorium-TEST-1754622690-146/config/last_post_num.txt +0 -1
  310. data/test/scriptorium-TEST-1754622690-146/config/os_helpers.rb +0 -4
  311. data/test/scriptorium-TEST-1754622690-146/config/widgets.txt +0 -3
  312. data/test/scriptorium-TEST-1754622690-146/posts/0001/meta.txt +0 -8
  313. data/test/scriptorium-TEST-1754622690-146/posts/0001/source.lt3 +0 -6
  314. data/test/scriptorium-TEST-1754622690-146/themes/standard/README.txt +0 -1
  315. data/test/scriptorium-TEST-1754622690-146/themes/standard/config.txt +0 -1
  316. data/test/scriptorium-TEST-1754622690-146/themes/standard/layout/gen/text.css +0 -1
  317. data/test/scriptorium-TEST-1754622690-146/themes/standard/templates/index.lt3 +0 -1
  318. data/test/scriptorium-TEST-1754622690-146/themes/standard/templates/index_entry.lt3 +0 -14
  319. data/test/scriptorium-TEST-1754622690-146/themes/standard/templates/post.lt3 +0 -13
  320. data/test/scriptorium-TEST-1754622690-146/themes/standard/templates/widget.lt3 +0 -1
  321. data/test/scriptorium-TEST-1754622690-146/views/sample/config/bootstrap_css.txt +0 -5
  322. data/test/scriptorium-TEST-1754622690-146/views/sample/config/bootstrap_js.txt +0 -4
  323. data/test/scriptorium-TEST-1754622690-146/views/sample/config/common.js +0 -57
  324. data/test/scriptorium-TEST-1754622690-146/views/sample/config/deploy.txt +0 -5
  325. data/test/scriptorium-TEST-1754622690-146/views/sample/config/footer.txt +0 -2
  326. data/test/scriptorium-TEST-1754622690-146/views/sample/config/global-head.txt +0 -9
  327. data/test/scriptorium-TEST-1754622690-146/views/sample/config/header.txt +0 -4
  328. data/test/scriptorium-TEST-1754622690-146/views/sample/config/layout.txt +0 -5
  329. data/test/scriptorium-TEST-1754622690-146/views/sample/config/left.txt +0 -3
  330. data/test/scriptorium-TEST-1754622690-146/views/sample/config/main.txt +0 -5
  331. data/test/scriptorium-TEST-1754622690-146/views/sample/config/right.txt +0 -3
  332. data/test/scriptorium-TEST-1754622690-146/views/sample/config/status.txt +0 -7
  333. data/test/scriptorium-TEST-1754622690-146/views/sample/config.txt +0 -3
  334. data/test/scriptorium-TEST-1754622690-146/views/sample/layout/footer.html +0 -3
  335. data/test/scriptorium-TEST-1754622690-146/views/sample/layout/header.html +0 -3
  336. data/test/scriptorium-TEST-1754622690-146/views/sample/layout/left.html +0 -3
  337. data/test/scriptorium-TEST-1754622690-146/views/sample/layout/main.html +0 -3
  338. data/test/scriptorium-TEST-1754622690-146/views/sample/layout/right.html +0 -3
  339. data/test/scriptorium-TEST-1754622690-146/views/sample/output/panes/footer.html +0 -1
  340. data/test/scriptorium-TEST-1754622690-146/views/sample/output/panes/header.html +0 -1
  341. data/test/scriptorium-TEST-1754622690-146/views/sample/output/panes/left.html +0 -1
  342. data/test/scriptorium-TEST-1754622690-146/views/sample/output/panes/main.html +0 -1
  343. data/test/scriptorium-TEST-1754622690-146/views/sample/output/panes/right.html +0 -1
  344. data/ui/web/tmp/web_server.pid +0 -1
  345. /data/{test/pages-demo/views/demo/config/bootstrap_css.txt → lib/scriptorium/support/bootstrap/css.txt} +0 -0
  346. /data/{test/pages-demo/views/demo/config/bootstrap_js.txt → lib/scriptorium/support/bootstrap/js.txt} +0 -0
  347. /data/{test/scriptorium-TEST-1754622690-146/views/sample → lib/scriptorium/support}/config/reddit.txt +0 -0
  348. /data/{test/scriptorium-TEST-1754622690-146/themes/standard/layout → lib/scriptorium/support/templates}/layout.txt +0 -0
  349. /data/{test/scriptorium-TEST-1754622690-146/themes/standard/layout/config/footer.txt → lib/scriptorium/support/theme/footer.lt3} +0 -0
  350. /data/{test/scriptorium-TEST-1754622690-146/themes/standard/layout/config/left.txt → lib/scriptorium/support/theme/left.lt3} +0 -0
  351. /data/{test/scriptorium-TEST-1754622690-146/themes/standard/layout/config/main.txt → lib/scriptorium/support/theme/main.lt3} +0 -0
  352. /data/{test/scriptorium-TEST-1754622690-146/themes/standard/layout/config/right.txt → lib/scriptorium/support/theme/right.lt3} +0 -0
  353. /data/test/manual/banner-tests/{config.txt → svg.txt} +0 -0
  354. /data/test/manual/{test6.rb → test_advanced_widgets.rb} +0 -0
  355. /data/test/manual/{test1.rb → test_basic_posts.rb} +0 -0
  356. /data/test/manual/{test4.rb → test_layout_widgets.rb} +0 -0
  357. /data/test/manual/{test5.rb → test_pagination.rb} +0 -0
  358. /data/test/manual/{test3.rb → test_random_posts.rb} +0 -0
@@ -1,245 +1,219 @@
1
1
  # Test file for asset management functionality
2
- # Tests the $$asset and $$image_asset Livetext functions
2
+ # Tests the $$asset and $$image Livetext functions
3
3
 
4
4
  require 'minitest/autorun'
5
5
  require_relative '../../lib/scriptorium'
6
6
  require_relative '../test_helpers'
7
- require_relative '../../lt3scriptor'
8
7
  require 'fileutils'
9
8
 
10
9
  class TestAssetManagement < Minitest::Test
11
- include Scriptorium::Helpers
12
10
  include TestHelpers
13
11
 
14
12
  def setup
15
- @test_dir = "test/asset_management_test"
16
- FileUtils.rm_rf(@test_dir) if File.exist?(@test_dir)
17
- FileUtils.mkdir_p(@test_dir)
18
- Scriptorium::Repo.testing = true
13
+ @repo_name = "test/scriptorium-TEST"
14
+ @view_name = "asset_test_view"
19
15
 
20
- # Create test repository with unique view name
21
- @repo = create_test_repo
22
- @repo.create_view("asset_test_view", "Testing assets")
16
+ # Create test repo and API
17
+ @api = Scriptorium::API.new
18
+ @api.create_repo(@repo_name)
19
+ @api.open_repo(@repo_name)
23
20
 
24
- # Set up LiveText variables for testing
25
- setup_livetext_vars
21
+ # Create a view for testing
22
+ @api.create_view(@view_name, "Asset Test View")
26
23
 
27
- # Create test assets
28
- create_test_assets
29
- end
30
-
31
- def teardown
32
- FileUtils.rm_rf(@test_dir) if File.exist?(@test_dir)
33
- # Also clean up the test repository
34
- FileUtils.rm_rf("test/scriptorium-TEST") if File.exist?("test/scriptorium-TEST")
35
- end
36
-
37
- def setup_livetext_vars
38
- # Set up LiveText variables for testing
39
- @vars = { View: "asset_test_view", "post.id": "0001" }
40
- end
41
-
42
- def create_test_assets
43
- # Create global asset
44
- File.write(@repo.root/"assets"/"image1.jpg", "Global Asset 1")
45
-
46
- # Create view asset
47
- File.write(@repo.root/"views"/"asset_test_view"/"assets"/"image2.jpg", "View Asset 2")
48
-
49
- # Create post asset
50
- FileUtils.mkdir_p(@repo.root/"posts"/"0001"/"assets")
51
- File.write(@repo.root/"posts"/"0001"/"assets"/"image3.jpg", "Post Asset 3")
52
-
53
- # Create library asset
54
- FileUtils.mkdir_p(@repo.root/"assets"/"library")
55
- File.write(@repo.root/"assets"/"library"/"image4.jpg", "Library Asset 4")
56
- end
57
-
58
- def process_livetext(content)
59
- # Create a temporary file with the content
60
- temp_file = "#{@test_dir}/temp_livetext.lt3"
61
- write_file(temp_file, content)
62
-
63
- # Process with Livetext using the plugin
64
- begin
65
- live = Livetext.customize(mix: "lt3scriptor", call: ".nopara", vars: @vars)
66
- body, vars = live.process(file: temp_file)
67
- vars = vars.to_h
68
- return { vars: vars, body: body }
69
- rescue => e
70
- puts "Livetext error: #{e.message}"
71
- puts "Backtrace: #{e.backtrace.first}"
72
- return { error: e.message, backtrace: e.backtrace.first }
73
- ensure
74
- # Clean up
75
- File.delete(temp_file) if File.exist?(temp_file)
76
- end
77
- end
78
-
79
- def test_001_asset_function_finds_global_asset
80
- content = "$$asset[image1.jpg]"
81
- result = process_livetext(content)
82
- assert_equal "assets/image1.jpg", result[:body].strip
83
- end
84
-
85
- def test_002_asset_function_finds_view_asset
86
- content = "$$asset[image2.jpg]"
87
- result = process_livetext(content)
88
-
89
- assert_equal "assets/image2.jpg", result[:body].strip
90
- end
91
-
92
- def test_003_asset_function_finds_post_asset
93
- content = "$$asset[image3.jpg]"
94
- result = process_livetext(content)
95
-
96
- assert_equal "assets/0001/image3.jpg", result[:body].strip
97
- end
98
-
99
- def test_003b_asset_function_finds_library_asset
100
- content = "$$asset[image4.jpg]"
101
- result = process_livetext(content)
102
-
103
- assert_equal "assets/image4.jpg", result[:body].strip
104
- end
105
-
106
- def test_004_asset_function_search_hierarchy
107
- # Create same filename in multiple locations to test hierarchy
108
- File.write(@repo.root/"assets"/"duplicate.jpg", "Global")
109
- File.write(@repo.root/"views"/"asset_test_view"/"assets"/"duplicate.jpg", "View")
110
- File.write(@repo.root/"posts"/"0001"/"assets"/"duplicate.jpg", "Post")
111
-
112
- content = "$$asset[duplicate.jpg]"
113
- result = process_livetext(content)
114
-
115
- # Should find post asset first (highest priority)
116
- assert_equal "assets/0001/duplicate.jpg", result[:body].strip
117
- end
118
-
119
- def test_005_asset_function_missing_asset_generates_placeholder
120
- content = "$$asset[nonexistent.jpg]"
121
- result = process_livetext(content)
24
+ # Create test posts
25
+ @api.create_post("Test Post 1", "This is the first test post for asset testing.")
26
+ @api.create_post("Test Post 2", "This is the second test post for asset testing.")
122
27
 
123
- assert_equal "assets/missing/nonexistent.jpg.svg", result[:body].strip
28
+ # Generate the view to create output directory structure
29
+ @api.generate_view(@view_name)
124
30
  end
125
31
 
126
- def test_006_image_asset_function_wraps_in_img_tag
127
- content = "$$image_asset[image1.jpg]"
128
- result = process_livetext(content)
129
-
130
- expected = '<img src="assets/image1.jpg" alt="image1.jpg">'
131
- assert_equal expected, result[:body].strip
32
+ def teardown
33
+ FileUtils.rm_rf("test/scriptorium-TEST") # Commented out for debugging
132
34
  end
133
-
134
- def test_007_image_asset_function_with_missing_asset
135
- content = "$$image_asset[missing.jpg]"
136
- result = process_livetext(content)
35
+
36
+ def test_001_asset_function_basic_functionality
37
+ # Test that asset() function returns correct paths for existing assets
38
+ # Create a global asset
39
+ global_file = Tempfile.new(['global-image', '.jpg'])
40
+ global_file.write("global image content")
41
+ global_file.close
42
+ @api.upload_asset(global_file.path, filename: "global-image.jpg")
137
43
 
138
- expected = '<img src="assets/missing/missing.jpg.svg" alt="missing.jpg">'
139
- assert_equal expected, result[:body].strip
44
+ # Update existing post 0001 with asset reference
45
+ source_file = "test/scriptorium-TEST/posts/0001/source.lt3"
46
+ File.write(source_file, "Global asset: $$asset[global-image.jpg]")
47
+
48
+ # Generate the view
49
+ @api.generate_view(@view_name)
50
+
51
+ # Check that the asset path is correct in generated HTML
52
+ html_file = "test/scriptorium-TEST/views/#{@view_name}/output/posts/0001-test-post-1.html"
53
+ html_content = File.read(html_file)
54
+
55
+ assert_includes_concise_string html_content, "Global asset: ../assets/global-image.jpg", "Asset function should return correct path"
56
+ end
57
+
58
+ def test_002_asset_function_missing_asset
59
+ # Test that asset() function returns fallback for missing assets
60
+ # Update existing post 0002 with missing asset reference
61
+ source_file = "test/scriptorium-TEST/posts/0002/source.lt3"
62
+ File.write(source_file, "Missing asset: $$asset[missing-image.jpg]")
63
+
64
+ # Generate the view
65
+ @api.generate_view(@view_name)
66
+
67
+ # Check that the fallback path is used
68
+ html_file = "test/scriptorium-TEST/views/#{@view_name}/output/posts/0002-test-post-2.html"
69
+ html_content = File.read(html_file)
70
+
71
+ assert_includes_concise_string html_content, "Missing asset: ../assets/imagenotfound.jpg", "Asset function should return fallback for missing assets"
72
+ end
73
+
74
+ def test_003_image_function_basic_functionality
75
+ # Test that image() function generates correct HTML
76
+ # Create a global asset
77
+ global_file = Tempfile.new(['global-image', '.jpg'])
78
+ global_file.write("global image content")
79
+ global_file.close
80
+ @api.upload_asset(global_file.path, filename: "global-image.jpg")
81
+
82
+ # Update existing post 0001 with image reference
83
+ source_file = "test/scriptorium-TEST/posts/0001/source.lt3"
84
+ File.write(source_file, "Image:\n.image global-image.jpg")
85
+
86
+ # Generate the view
87
+ @api.generate_view(@view_name)
88
+
89
+ # Check that the image tag is correct
90
+ html_file = "test/scriptorium-TEST/views/#{@view_name}/output/posts/0001-test-post-1.html"
91
+ html_content = File.read(html_file)
92
+
93
+ assert_includes_concise_string html_content, "<img src=../assets/global-image.jpg alt='No alt text'></img>", "Image function should generate correct HTML"
94
+ end
95
+
96
+ def test_004_image_function_with_real_asset
97
+ # Test that image() function works with actual test assets
98
+ # Upload a real test asset
99
+ @api.upload_asset("test/assets/testbanner.jpg", filename: "testbanner.jpg")
100
+
101
+ # Update existing post 0002 with image reference
102
+ source_file = "test/scriptorium-TEST/posts/0002/source.lt3"
103
+ File.write(source_file, "Real asset:\n.image testbanner.jpg")
104
+
105
+ # Generate the view
106
+ @api.generate_view(@view_name)
107
+
108
+ # Check that the image tag is correct
109
+ html_file = "test/scriptorium-TEST/views/#{@view_name}/output/posts/0002-test-post-2.html"
110
+ html_content = File.read(html_file)
111
+
112
+ assert_includes_concise_string html_content, "<img src=../assets/testbanner.jpg alt='No alt text'></img>", "Image function should work with real assets"
113
+ end
114
+
115
+ def test_005_global_asset_copied_to_view
116
+ # Test that global assets are automatically copied to view assets during generation
117
+ # First, create a global asset file directly in the repo
118
+ global_asset_path = "test/scriptorium-TEST/assets/global-copy-test.jpg"
119
+ FileUtils.cp("test/assets/testbanner.jpg", global_asset_path)
120
+
121
+ # Update existing post 0001 to reference the global asset
122
+ source_file = "test/scriptorium-TEST/posts/0001/source.lt3"
123
+ File.write(source_file, "Global asset copy test:\n.image global-copy-test.jpg")
124
+
125
+ # Assert initial state before generation
126
+ view_assets_dir = "test/scriptorium-TEST/views/#{@view_name}/assets"
127
+
128
+ # The global asset we just created should NOT be in view assets yet
129
+ view_asset_path = "#{view_assets_dir}/global-copy-test.jpg"
130
+ refute File.exist?(view_asset_path), "Global asset should not be in view assets before generation"
131
+
132
+ # Generate the view (this should copy the global asset to the view)
133
+ @api.generate_view(@view_name)
134
+
135
+ # Check that the global asset was copied to the view assets directory
136
+ view_asset_path = "test/scriptorium-TEST/views/#{@view_name}/assets/global-copy-test.jpg"
137
+ assert File.exist?(view_asset_path), "Global asset should be copied to view assets directory"
138
+
139
+ # Check that the image tag references the correct path
140
+ html_file = "test/scriptorium-TEST/views/#{@view_name}/output/posts/0001-test-post-1.html"
141
+ html_content = File.read(html_file)
142
+ assert_includes_concise_string html_content, "<img src=../assets/global-copy-test.jpg alt='No alt text'></img>", "Image should reference the copied asset"
140
143
  end
141
-
142
- def test_008_asset_function_without_post_id
143
- # Test without post.id variable
144
- @vars["post.id"] = nil
145
-
146
- content = "$$asset[image1.jpg]"
147
- result = process_livetext(content)
148
- assert_equal "assets/image1.jpg", result[:body].strip
149
-
150
- # Post assets should not be found
151
- content = "$$asset[image3.jpg]"
152
- result = process_livetext(content)
153
- assert_equal "assets/missing/image3.jpg.svg", result[:body].strip
144
+
145
+ def test_006_asset_priority_hierarchy
146
+ # Test that post assets take precedence over view assets with same filename
147
+ # 1. Create a file with specific contents and upload to view assets
148
+ view_file = Tempfile.new(['priority-test', '.txt'])
149
+ view_file.write("File 1, view asset")
150
+ view_file.close
151
+ @api.upload_asset(view_file.path, 'view', @view_name, filename: "priority-test.txt")
152
+
153
+ # 2. Create another file with SAME NAME but different contents and upload to post 2 assets
154
+ post_file = Tempfile.new(['priority-test', '.txt'])
155
+ post_file.write("File 2, post asset")
156
+ post_file.close
157
+ @api.upload_asset(post_file.path, 'post', 2, filename: "priority-test.txt")
158
+
159
+ # 3. Update both posts to reference the asset
160
+ source_file_1 = "test/scriptorium-TEST/posts/0001/source.lt3"
161
+ File.write(source_file_1, "Asset priority test:\n$$asset[priority-test.txt]")
162
+
163
+ source_file_2 = "test/scriptorium-TEST/posts/0002/source.lt3"
164
+ File.write(source_file_2, "Asset priority test:\n$$asset[priority-test.txt]")
165
+
166
+ # 4. Generate the view
167
+ @api.generate_view(@view_name)
168
+
169
+ # 5. Check that post 1 refers to the view asset (since it has no post asset)
170
+ html_file_1 = "test/scriptorium-TEST/views/#{@view_name}/output/posts/0001-test-post-1.html"
171
+ html_content_1 = File.read(html_file_1)
172
+ assert_includes_concise_string html_content_1, "../assets/priority-test.txt", "Post 1 should reference the view asset"
173
+
174
+ # 6. Check that post 2 refers to its own post asset (post assets take precedence)
175
+ html_file_2 = "test/scriptorium-TEST/views/#{@view_name}/output/posts/0002-test-post-2.html"
176
+ html_content_2 = File.read(html_file_2)
177
+ assert_includes_concise_string html_content_2, "../assets/posts/0002/priority-test.txt", "Post 2 should reference its post asset"
178
+
179
+ # 7. Verify the actual files exist in the correct locations
180
+ view_asset_path = "test/scriptorium-TEST/views/#{@view_name}/assets/priority-test.txt"
181
+ post_asset_path = "test/scriptorium-TEST/posts/0002/assets/priority-test.txt"
182
+
183
+ assert File.exist?(view_asset_path), "View asset should exist"
184
+ assert File.exist?(post_asset_path), "Post asset should exist"
154
185
 
155
- # Restore post.id for other tests
156
- @vars["post.id"] = "0001"
186
+ # 8. Check that the files have the correct contents
187
+ view_content = File.read(view_asset_path)
188
+ post_content = File.read(post_asset_path)
189
+
190
+ assert_includes view_content, "File 1, view asset", "View asset should have correct content"
191
+ assert_includes post_content, "File 2, post asset", "Post asset should have correct content"
157
192
  end
158
-
159
- def test_009_asset_function_output_directory_structure
160
- # Call asset function to test path returns
161
- result1 = process_livetext("$$asset[image1.jpg]")
162
- result2 = process_livetext("$$asset[image2.jpg]")
163
- result3 = process_livetext("$$asset[image3.jpg]")
164
- result4 = process_livetext("$$asset[nonexistent.jpg]")
165
-
166
- # Verify correct paths are returned
167
- assert_equal "assets/image1.jpg", result1[:body].strip
168
- assert_equal "assets/image2.jpg", result2[:body].strip
169
- assert_equal "assets/0001/image3.jpg", result3[:body].strip
170
- assert_equal "assets/missing/nonexistent.jpg.svg", result4[:body].strip
171
- end
172
-
173
- def test_010_asset_function_idempotent_calling
174
- # Call asset function multiple times
175
- result1 = process_livetext("$$asset[image1.jpg]")
176
- result2 = process_livetext("$$asset[image1.jpg]")
177
- result3 = process_livetext("$$asset[image1.jpg]")
178
-
179
- # Should return same result each time
180
- assert_equal result1[:body].strip, result2[:body].strip
181
- assert_equal result2[:body].strip, result3[:body].strip
182
- end
183
-
184
- def test_011_theme_assets_in_hierarchy
185
- # Create theme assets directory and add a test asset
186
- theme_assets_dir = @repo.root/"themes"/"standard"/"assets"
187
- FileUtils.mkdir_p(theme_assets_dir)
188
- File.write(theme_assets_dir/"theme-test.jpg", "Theme Asset")
189
-
190
- # Create same filename in multiple locations to test hierarchy
191
- File.write(@repo.root/"assets"/"theme-test.jpg", "Global")
192
- File.write(@repo.root/"views"/"asset_test_view"/"assets"/"theme-test.jpg", "View")
193
- File.write(@repo.root/"posts"/"0001"/"assets"/"theme-test.jpg", "Post")
194
-
195
- # Test with post context - should find post asset first (highest priority)
196
- content = "$$asset[theme-test.jpg]"
197
- result = process_livetext(content)
198
- assert_equal "assets/0001/theme-test.jpg", result[:body].strip
199
-
200
- # Test without post context - should find view asset first
201
- # Temporarily remove post.id from vars
202
- original_post_id = @vars["post.id"]
203
- @vars["post.id"] = nil
204
-
205
- content = "$$asset[theme-test.jpg]"
206
- result = process_livetext(content)
207
- assert_equal "assets/theme-test.jpg", result[:body].strip
208
-
209
- # Restore post.id for other tests
210
- @vars["post.id"] = original_post_id
211
- end
212
-
213
- def test_012_gem_assets_in_hierarchy
214
- # Test gem assets (lowest priority)
215
- content = "$$asset[icons/ui/back-arrow.svg]"
216
- result = process_livetext(content)
217
-
218
- # Should find gem asset and return correct path
219
- assert_equal "assets/icons/ui/back-arrow.svg", result[:body].strip
220
- end
221
-
222
- private
223
-
224
- def process_livetext_no_post(content)
225
- # Process content without post context
226
- temp_file = "#{@test_dir}/temp_livetext_no_post.lt3"
227
- write_file(temp_file, content)
228
-
229
- # Use only View variable, no post.id
230
- vars = { View: "asset_test_view" }
231
-
232
- begin
233
- live = Livetext.customize(mix: "lt3scriptor", call: ".nopara", vars: vars)
234
- body, _vars = live.process(file: temp_file)
235
- return { vars: _vars, body: body }
236
- rescue => e
237
- puts "Livetext error: #{e.message}"
238
- puts "Backtrace: #{e.backtrace.first}"
239
- return { error: e.message, backtrace: e.backtrace.first }
240
- ensure
241
- # Clean up
242
- File.delete(temp_file) if File.exist?(temp_file)
243
- end
193
+
194
+ def test_007_asset_paths_in_post_context
195
+ # Test that asset paths work correctly in post page context (subdirectory)
196
+
197
+ # 1. Create a test asset
198
+ test_file = Tempfile.new(['path-test', '.txt'])
199
+ test_file.write("Path test asset")
200
+ test_file.close
201
+ @api.upload_asset(test_file.path, 'post', 1, filename: "path-test.txt")
202
+
203
+ # 2. Update post 1 to reference the asset
204
+ source_file_1 = "test/scriptorium-TEST/posts/0001/source.lt3"
205
+ File.write(source_file_1, "Asset path test:\n$$asset[path-test.txt]")
206
+
207
+ # 3. Generate the view
208
+ @api.generate_view(@view_name)
209
+
210
+ # 4. Check post page - should have ../assets/posts/0001/path-test.txt
211
+ post_file = "test/scriptorium-TEST/views/#{@view_name}/output/posts/0001-test-post-1.html"
212
+ post_content = File.read(post_file)
213
+ assert_includes_concise_string post_content, "../assets/posts/0001/path-test.txt", "Post page should reference assets with ../ prefix"
214
+
215
+ # 5. Verify the asset file exists in the output directory
216
+ asset_file = "test/scriptorium-TEST/views/#{@view_name}/output/assets/posts/0001/path-test.txt"
217
+ assert File.exist?(asset_file), "Asset should be copied to output directory"
244
218
  end
245
219
  end