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
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'minitest/autorun'
4
4
  require_relative '../lib/scriptorium'
5
+ require 'tempfile'
5
6
  require_relative 'test_helpers'
6
7
 
7
8
  class LivetextPluginTest < Minitest::Test
@@ -16,6 +17,21 @@ class LivetextPluginTest < Minitest::Test
16
17
  cleanup_test_repo
17
18
  end
18
19
 
20
+ def create_test_environment_with_content
21
+ # Create test repo using API
22
+ @api = Scriptorium::API.new(testmode: true)
23
+ @api.create_repo(@test_repo_path)
24
+
25
+ # Create a view
26
+ @api.create_view("testview", "Test View")
27
+
28
+ # Create a page using the API
29
+ @api.create_page("testview", "testpage", "Test Page", "This is a test page for link testing.")
30
+
31
+ # Create a post using the API
32
+ @api.create_post("Test Post", "This is a test post for link testing.", views: "testview", tags: "test")
33
+ end
34
+
19
35
  def test_001_basic_dot_commands
20
36
  # Test basic dot commands that should work
21
37
  content = <<~EOS
@@ -23,180 +39,442 @@ class LivetextPluginTest < Minitest::Test
23
39
  .created
24
40
  .views sample
25
41
  .tags ruby, testing
26
- .blurb This is a test post
42
+ .blurb
43
+ This is a test post
44
+ .end
27
45
  This is the body content
28
46
  EOS
29
47
 
30
- result = process_livetext(content)
48
+ body, vars = process_livetext(content)
31
49
 
32
50
  # Check that variables were set correctly
33
- assert_equal("My Test Post", result[:vars][:"post.title"])
34
- assert_equal("sample", result[:vars][:"post.views"])
35
- assert_equal("ruby, testing", result[:vars][:"post.tags"])
36
- assert_equal("This is a test post", result[:vars][:"post.blurb"])
51
+ assert_equal("My Test Post", vars[:"post.title"])
52
+ assert_equal("sample", vars[:"post.views"])
53
+ assert_equal("ruby, testing", vars[:"post.tags"])
54
+ assert_equal("This is a test post", vars[:"post.blurb"])
37
55
 
38
56
  # Check that body text is returned
39
- assert_match(/This is the body content/, result[:text])
40
- end
41
-
42
- # def test_002_html_formatting_commands
43
- # # Test HTML formatting commands
44
- # content = <<~EOS
45
- # .h1 Main Heading
46
- # .h2 Sub Heading
47
- # .list
48
- # Item 1
49
- # Item 2
50
- # Item 3
51
- # .end
52
- # .nlist
53
- # Numbered 1
54
- # Numbered 2
55
- # .end
56
- # .quote
57
- # This is a quote
58
- # .end
59
- # .hr
60
- # EOS
61
- #
62
- # result = process_livetext(content)
63
- #
64
- # # Check HTML output
65
- # assert_match(/<h1>Main Heading<\/h1>/, result[:text])
66
- # assert_match(/<h2>Sub Heading<\/h2>/, result[:text])
67
- # assert_match(/<ul>/, result[:text])
68
- # assert_match(/<li>Item 1<\/li>/, result[:text])
69
- # assert_match(/<ol>/, result[:text])
70
- # assert_match(/<li>Numbered 1<\/li>/, result[:text])
71
- # assert_match(/<blockquote>/, result[:text])
72
- # assert_match(/<hr>/, result[:text])
73
- # end
74
-
75
- # def test_003_special_formatting
76
- # # Test special formatting like dropcap and inset
77
- # content = <<~EOS
78
- # .dropcap This is a dropcap test
79
- # .inset left 25
80
- # |This goes in the inset
81
- # This goes in the body
82
- # /This only goes in inset
83
- # .end
84
- # EOS
85
- #
86
- # result = process_livetext(content)
87
- #
88
- # # Check for dropcap formatting
89
- # assert_match(/mydrop/, result[:text])
90
- # assert_match(/his is a dropcap test/, result[:text]) # The remainder after the dropcap
91
- #
92
- # # Check for inset formatting
93
- # assert_match(/float:left/, result[:text])
94
- # assert_match(/width: 25%/, result[:text])
95
- # end
96
-
97
- # def test_004_functions
98
- # # Test Livetext functions
99
- # content = <<~EOS
100
- # $$br:2
101
- # $$h1[Function Heading]
102
- # $$h2[Sub Heading]
103
- # $$image:test.jpg
104
- # EOS
105
- #
106
- # result = process_livetext(content)
107
- #
108
- # # Check function output
109
- # assert_match(/<br><br>/, result[:text])
110
- # assert_match(/<h1>Function Heading<\/h1>/, result[:text])
111
- # assert_match(/<h2>Sub Heading<\/h2>/, result[:text])
112
- # assert_match(/<img src='test\.jpg'><\/img>/, result[:text])
113
- # end
114
-
115
- # def test_005_faq_command
116
- # # Test the FAQ command
117
- # content = <<~EOS
118
- # .faq What is this?
119
- # This is a test question and answer.
120
- # .end
121
- # .faq Another question?
122
- # Another answer.
123
- # .end
124
- # EOS
125
- #
126
- # result = process_livetext(content)
127
- #
128
- # # Check FAQ formatting
129
- # assert_match(/data-toggle="collapse"/, result[:text])
130
- # assert_match(/What is this\?/, result[:text])
131
- # assert_match(/This is a test question and answer/, result[:text])
132
- # assert_match(/Another question\?/, result[:text])
133
- # end
134
-
135
- # def test_006_last_updated_command
136
- # # Test the last_updated command
137
- # content = <<~EOS
138
- # .created
139
- # .title Test Post
140
- # .last_updated
141
- # EOS
142
- #
143
- # result = process_livetext(content)
144
- #
145
- # # Check that last_updated outputs the publication date
146
- # assert_match(/Published:/, result[:text])
147
- # today = Time.now.strftime("%Y-%m-%d")
148
- # assert_match(/#{today}/, result[:text]) # Should match today's date
149
- # end
150
-
151
- # def test_007_wordcount_function
152
- # # Test the wordcount function
153
- # content = <<~EOS
154
- # .title Test Post
155
- # This is a test post with some words.
156
- # It has multiple sentences and paragraphs.
157
- #
158
- # .wordcount
159
- # The file $File has $wordcount words.
160
- #
161
- # More content here to increase the word count.
162
- # This should be counted as well.
163
- # EOS
164
- #
165
- # result = process_livetext(content)
166
- #
167
- # # Check that wordcount function worked
168
- # assert_match(/The file .* has \d+ words\./, result[:text])
169
- # # Should not contain the literal ".wordcount" if working
170
- # refute_match(/\.wordcount/, result[:text])
171
- # # Should not contain the literal "$wordcount" if working
172
- # refute_match(/\$wordcount/, result[:text])
173
- # end
174
-
175
- # def test_008_stats_command
176
- # # Test the stats command that sets multiple variables
177
- # content = <<~EOS
178
- # .title Test Post
179
- # This is a test post with some words.
180
- # It has multiple sentences and paragraphs.
181
- #
182
- # .stats
183
- # This file has $file.wordcount words, $file.charcount characters, and takes about $file.readingtime minutes to read.
184
- #
185
- # More content here to increase the word count.
186
- # This should be counted as well.
187
- # EOS
188
- #
189
- # result = process_livetext(content)
190
- #
191
- # # Check that stats command worked
192
- # assert_match(/This file has \d+ words, \d+ characters, and takes about \d+ minutes to read\./, result[:text])
193
- # # Should not contain the literal ".stats" if working
194
- # refute_match(/\.stats/, result[:text])
195
- # # Should not contain the literal variable names if working
196
- # refute_match(/\$file\.wordcount/, result[:text])
197
- # refute_match(/\$file\.charcount/, result[:text])
198
- # refute_match(/\$file\.readingtime/, result[:text])
199
- # end
57
+ assert_match(/This is the body content/, body)
58
+ end
59
+
60
+ def test_002_html_formatting_commands
61
+ # Test HTML formatting commands
62
+ content = <<~EOS
63
+ .h1 Main Heading
64
+ .h2 Sub Heading
65
+ .list
66
+ Item 1
67
+ Item 2
68
+ Item 3
69
+ .end
70
+ .nlist
71
+ Numbered 1
72
+ Numbered 2
73
+ .end
74
+ .quote
75
+ This is a quote
76
+ .end
77
+ .hr
78
+ EOS
79
+
80
+ body, vars = process_livetext(content)
81
+
82
+ # Check HTML output
83
+ assert_match(/<h1>Main Heading<\/h1>/, body)
84
+ assert_match(/<h2>Sub Heading<\/h2>/, body)
85
+ assert_match(/<ul>/, body)
86
+ assert_match(/<li>Item 1<\/li>/, body)
87
+ assert_match(/<ol>/, body)
88
+ assert_match(/<li>Numbered 1<\/li>/, body)
89
+ assert_match(/<blockquote>/, body)
90
+ assert_match(/<hr>/, body)
91
+ end
92
+
93
+ def test_003_special_formatting
94
+ # Test special formatting like dropcap and inset
95
+ content = <<~EOS
96
+ .dropcap
97
+ This is a dropcap test with multiple lines.
98
+ The dropcap should apply to the first letter of this content.
99
+ .end
100
+ .inset left 25
101
+ |This goes in the inset
102
+ This goes in the body
103
+ /This only goes in inset
104
+ .end
105
+ EOS
106
+
107
+ body, vars = process_livetext(content)
108
+
109
+ # Check for dropcap formatting - should be a span with class for first character
110
+ assert_match(/<span class="dropcap">/, body)
111
+ assert_match(/his is a dropcap test with multiple lines\./, body)
112
+ assert_match(/The dropcap should apply to the first letter/, body)
113
+
114
+ # Check for inset formatting
115
+ assert_match(/float:left/, body)
116
+ assert_match(/width: 25%/, body)
117
+ end
118
+
119
+ def test_004_functions
120
+ # Test Livetext functions
121
+ content = <<~EOS
122
+ $$br:2
123
+ $$h1[Function Heading]
124
+ $$h2[Sub Heading]
125
+ $$image:test.jpg
126
+ EOS
127
+
128
+ body, vars = process_livetext(content)
129
+
130
+ # Check function output
131
+ assert_match(/<br><br>/, body)
132
+ assert_match(/<h1>Function Heading<\/h1>/, body)
133
+ assert_match(/<h2>Sub Heading<\/h2>/, body)
134
+ # In non-post context with no real file, $$image resolves to missing image
135
+ assert_match(/<img src=assets\/imagenotfound\.jpg alt='No alt text'><\/img>/, body)
136
+ end
137
+
138
+ def test_024_center_dot_command_with_image_function
139
+ content = <<~EOS
140
+ .center
141
+ $$image:test.jpg
142
+ .end
143
+ EOS
144
+
145
+ body, vars = process_livetext(content)
146
+
147
+ assert_match(/<div style="text-align:center">/, body)
148
+ # In non-post context with no real file, $$image resolves to missing image
149
+ assert_match(/<img src=assets\/imagenotfound\.jpg alt='No alt text'><\/img>/, body)
150
+ end
151
+
152
+ def test_023_asset_dot_command_copies_to_post_assets
153
+ # Create repo/view/post context
154
+ create_test_environment_with_content
155
+ # Create a temp file to copy
156
+ tmp = Tempfile.new(['sample', '.txt'])
157
+ tmp.write("hello")
158
+ tmp.close
159
+
160
+ repo_root = 'scriptorium-TEST'
161
+ source_path = File.join(repo_root, 'posts', '0001', 'source.lt3')
162
+ # Append .asset and a reference line to the post source
163
+ File.open(source_path, 'a') do |f|
164
+ f.puts ".asset #{tmp.path}"
165
+ f.puts "Copied path: $$asset[#{File.basename(tmp.path)}]"
166
+ end
167
+
168
+ # Generate the post so the snippet is rendered
169
+ api = Scriptorium::API.new(testmode: true)
170
+ api.open_repo(repo_root)
171
+ api.generate_post(1)
172
+
173
+ # Read body.html and verify both copy and rendered reference
174
+ body_file = File.join(repo_root, 'posts', '0001', 'body.html')
175
+ body = File.read(body_file)
176
+ post_asset_path = File.join(repo_root, 'posts', '0001', 'assets', File.basename(tmp.path))
177
+ assert File.exist?(post_asset_path), "Expected copied asset under post assets"
178
+ assert_includes body, "Copied path: ../assets/posts/0001/#{File.basename(tmp.path)}"
179
+ ensure
180
+ tmp.unlink if tmp && File.exist?(tmp.path)
181
+ end
182
+
183
+ def test_005_dropcap_command
184
+ # Test the dropcap command
185
+ content = <<~EOS
186
+ .dropcap
187
+ Once upon a time there was a story that began with a dropcap.
188
+ This is the rest of the paragraph that flows naturally.
189
+ .end
190
+ EOS
191
+
192
+ body, vars = process_livetext(content)
193
+
194
+ # Check dropcap formatting
195
+ assert_match(/<span class="dropcap">/, body)
196
+ assert_match(/nce upon a time there was a story/, body)
197
+ assert_match(/This is the rest of the paragraph/, body)
198
+
199
+ # Should be a single paragraph, not split into multiple divs
200
+ refute_match(/mydrop/, body)
201
+ refute_match(/padding-top: 1px/, body)
202
+ end
203
+
204
+ def test_006_faq_command
205
+ # Test the FAQ command
206
+ content = <<~EOS
207
+ .faq What is this?
208
+ This is a test question and answer.
209
+ .end
210
+ .faq Another question?
211
+ Another answer.
212
+ .end
213
+ EOS
214
+
215
+ body, vars = process_livetext(content)
216
+
217
+ # Check FAQ formatting
218
+ assert_match(/data-toggle="collapse"/, body)
219
+ assert_match(/What is this\?/, body)
220
+ assert_match(/This is a test question and answer/, body)
221
+ assert_match(/Another question\?/, body)
222
+ end
223
+
224
+ def test_007_last_updated_command
225
+ skip "Possible LiveText bug with last_updated command"
226
+ content = <<~EOS
227
+ .created
228
+ .title Test Post
229
+ .last_updated
230
+ EOS
231
+ body, vars = process_livetext(content)
232
+ assert_match(/Published:/, body)
233
+ today = Time.now.strftime("%Y-%m-%d")
234
+ assert_match(/#{today}/, body)
235
+ end
236
+
237
+ def test_008_image_command
238
+ # Test the .image command
239
+ content = <<~EOS
240
+ .title Test Post
241
+ .image test.jpg
242
+ This is the body content.
243
+ EOS
244
+
245
+ body, vars = process_livetext(content)
246
+
247
+ # Check that image command worked
248
+ assert_match(/<img/, body)
249
+ assert_match(/src=assets\/imagenotfound\.jpg/, body)
250
+ assert_match(/alt='No alt text'/, body)
251
+ assert_match(/This is the body content/, body)
252
+ # Should not contain the literal ".image" if working
253
+ refute_match(/\.image/, body)
254
+ end
255
+
256
+ def test_010_image_exclamation_command
257
+ # Test the .image! command (featured image)
258
+ content = <<~EOS
259
+ .title Test Post
260
+ .image! featured.jpg 800 600 1 Featured image with alt text
261
+ This is the body content.
262
+ EOS
263
+
264
+ body, vars = process_livetext(content)
265
+
266
+ # Check that image! command worked
267
+ assert_match(/<img/, body)
268
+ assert_match(/src=assets\/imagenotfound\.jpg/, body)
269
+ assert_match(/width=800/, body)
270
+ assert_match(/height=600/, body)
271
+ assert_match(/alt='Featured image with alt text'/, body)
272
+ assert_match(/This is the body content/, body)
273
+ # Should not contain the literal ".image!" if working
274
+ refute_match(/\.image!/, body)
275
+ end
276
+
277
+ def test_011_image_with_alt_text
278
+ # Test image command with alt text
279
+ content = <<~EOS
280
+ .title Test Post
281
+ .image test.jpg Alt text for image
282
+ This is the body content.
283
+ EOS
284
+
285
+ body, vars = process_livetext(content)
286
+
287
+ # Check that image with alt text worked
288
+ assert_match(/<img/, body)
289
+ assert_match(/src=assets\/imagenotfound\.jpg/, body)
290
+ assert_match(/alt='Alt text for image'/, body)
291
+ assert_match(/This is the body content/, body)
292
+ end
293
+
294
+ def test_012_pullquote_command
295
+ # Test the pullquote command
296
+ content = <<~EOS
297
+ .title Test Post
298
+ This is some content before the pullquote.
299
+
300
+ .pullquote right 200px
301
+ This is an impactful sentence that will be highlighted in a box.
302
+ .end
303
+
304
+ This is content after the pullquote that should flow around it.
305
+
306
+ .pullquote left 180px
307
+ This is another important point on the left side.
308
+ .end
309
+
310
+ More content that flows around the left-aligned pullquote.
311
+ EOS
312
+
313
+ body, vars = process_livetext(content)
314
+
315
+ # Check that pullquote HTML was generated
316
+ assert_match(/<div class="pullquote pullquote-right"/, body)
317
+ assert_match(/<div class="pullquote pullquote-left"/, body)
318
+ assert_match(/style="width: 200px;"/, body)
319
+ assert_match(/style="width: 180px;"/, body)
320
+
321
+ # Check that the content is included
322
+ assert_match(/This is an impactful sentence/, body)
323
+ assert_match(/This is another important point/, body)
324
+
325
+ # Check that surrounding content is present
326
+ assert_match(/This is some content before/, body)
327
+ assert_match(/This is content after the pullquote/, body)
328
+ assert_match(/More content that flows around/, body)
329
+
330
+ # Should not contain the literal ".pullquote" if working
331
+ refute_match(/\.pullquote/, body)
332
+ end
333
+
334
+ def test_013_page_function_with_content
335
+ create_test_environment_with_content
336
+
337
+ content = <<~EOS
338
+ Check out this page: $$page[testpage]
339
+ EOS
340
+
341
+ # Set the view context for the LiveText functions
342
+ temp_file = "test/temp_livetext.lt3"
343
+ write_file(temp_file, content)
344
+ live = Livetext.customize(mix: "lt3scriptor", call: ".nopara", vars: { View: "testview" })
345
+ body, vars = live.process(file: temp_file)
346
+
347
+ assert_includes body, '<a href="testpage.html">Test Page</a>'
348
+ refute_includes body, '[link is broken]'
349
+ ensure
350
+ File.delete(temp_file) if temp_file && File.exist?(temp_file)
351
+ end
352
+
353
+ def test_014_page_function_missing
354
+ create_test_environment_with_content
355
+
356
+ content = <<~EOS
357
+ Check out this missing page: $$page[nonexistent]
358
+ EOS
359
+
360
+ temp_file = "test/temp_livetext.lt3"
361
+ write_file(temp_file, content)
362
+ live = Livetext.customize(mix: "lt3scriptor", call: ".nopara", vars: { View: "testview" })
363
+ body, vars = live.process(file: temp_file)
364
+
365
+ assert_includes body, '<a href="nonexistent.html">Nonexistent</a>'
366
+ assert_includes body, '[link is broken]'
367
+ ensure
368
+ File.delete(temp_file) if temp_file && File.exist?(temp_file)
369
+ end
370
+
371
+ def test_015_post_function_with_content
372
+ create_test_environment_with_content
373
+
374
+ content = <<~EOS
375
+ Check out this post: $$post[1]
376
+ EOS
377
+
378
+ temp_file = "test/temp_livetext.lt3"
379
+ write_file(temp_file, content)
380
+ live = Livetext.customize(mix: "lt3scriptor", call: ".nopara", vars: { View: "testview" })
381
+ body, vars = live.process(file: temp_file)
382
+
383
+ assert_includes body, '<a href="0001-test-post">Test Post</a>'
384
+ refute_includes body, '[link is broken]'
385
+ ensure
386
+ File.delete(temp_file) if temp_file && File.exist?(temp_file)
387
+ end
388
+
389
+ def test_016_post_function_missing
390
+ create_test_environment_with_content
391
+
392
+ content = <<~EOS
393
+ Check out this missing post: $$post[999]
394
+ EOS
395
+
396
+ temp_file = "test/temp_livetext.lt3"
397
+ write_file(temp_file, content)
398
+ live = Livetext.customize(mix: "lt3scriptor", call: ".nopara", vars: { View: "testview" })
399
+ body, vars = live.process(file: temp_file)
400
+
401
+ assert_includes body, '<a href="0999-untitled.html">Post 999</a>'
402
+ assert_includes body, '[link is broken]'
403
+ ensure
404
+ File.delete(temp_file) if temp_file && File.exist?(temp_file)
405
+ end
406
+
407
+ def test_017_imglink_function
408
+ content = <<~EOS
409
+ Check out this image: $$imglink[test.jpg|https://example.com|Click me]
410
+ EOS
411
+
412
+ body, vars = process_livetext(content)
413
+
414
+ assert_includes body, '<a href="https://example.com">'
415
+ assert_includes body, '<img src='
416
+ assert_includes body, 'alt="Click me"'
417
+ end
418
+
419
+ def test_018_imglink_function_minimal
420
+ content = <<~EOS
421
+ Simple image: $$imglink[icon.png]
422
+ EOS
423
+
424
+ body, vars = process_livetext(content)
425
+
426
+ assert_includes body, '<a href="#">'
427
+ assert_includes body, '<img src='
428
+ assert_includes body, 'alt="Image"'
429
+ end
430
+
431
+ def test_019_p_dotcmd
432
+ content = <<~EOS
433
+ .p This is a paragraph
434
+ EOS
435
+
436
+ body, vars = process_livetext(content)
437
+
438
+ assert_includes body, '<p>This is a paragraph</p>'
439
+ end
440
+
441
+ def test_020_para_dotcmd
442
+ content = <<~EOS
443
+ .para
444
+ This is a paragraph
445
+ with multiple lines
446
+ .end
447
+ EOS
448
+
449
+ body, vars = process_livetext(content)
450
+
451
+ assert_includes body, '<p>This is a paragraph with multiple lines</p>'
452
+ end
453
+
454
+ def test_021_quote_dotcmd
455
+ content = <<~EOS
456
+ .quote
457
+ This is a quote
458
+ with multiple lines
459
+ .end
460
+ EOS
461
+
462
+ body, vars = process_livetext(content)
463
+
464
+ assert_includes body, '<blockquote>'
465
+ assert_includes body, 'This is a quote with multiple lines'
466
+ assert_includes body, '</blockquote>'
467
+ end
468
+
469
+ def test_022_page_title_dotcmd
470
+ content = <<~EOS
471
+ .page_title My Page Title
472
+ EOS
473
+
474
+ body, vars = process_livetext(content)
475
+
476
+ assert_equal "My Page Title", vars[:"page.title"]
477
+ end
200
478
 
201
479
  private
202
480
 
@@ -204,21 +482,14 @@ class LivetextPluginTest < Minitest::Test
204
482
  # Create a temporary file with the content
205
483
  temp_file = "test/temp_livetext.lt3"
206
484
  write_file(temp_file, content)
207
-
208
- # Process with Livetext using the plugin
209
- begin
210
- # Use the new unified Livetext API
211
- live = Livetext.customize(mix: "lt3scriptor", call: ".nopara")
212
- body, vars = live.process(file: temp_file)
213
-
214
- # Return the actual data structures
215
- return { vars: vars, text: body, body: body }
216
- rescue => e
217
- return { error: e.message, backtrace: e.backtrace.first }
218
- ensure
219
- # Clean up
220
- File.delete(temp_file) if File.exist?(temp_file)
221
- end
485
+ live = Livetext.customize(mix: "lt3scriptor", call: ".nopara")
486
+ body, vars = live.process(file: temp_file)
487
+ return [body, vars]
488
+ rescue => e
489
+ return [nil, { error: e.message, backtrace: e.backtrace.first }]
490
+ ensure
491
+ # Clean up
492
+ File.delete(temp_file) if File.exist?(temp_file)
222
493
  end
223
494
 
224
495
  def cleanup_test_repo