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
@@ -30,6 +30,9 @@ class Scriptorium::BannerSVG
30
30
  @text_anchor = "start"
31
31
  @aspect = 8.0
32
32
  @font = "Verdana"
33
+ @base_font_size = 60
34
+ @title_font_size = @base_font_size * @title_scale
35
+ @subtitle_font_size = @base_font_size * @subtitle_scale
33
36
  # Remove default @title_xy and @subtitle_xy
34
37
  @background = "#fff"
35
38
  @gradient_start_color = nil
@@ -61,11 +64,11 @@ class Scriptorium::BannerSVG
61
64
  end
62
65
 
63
66
  private def validate_background_args(args)
64
- raise CannotHandleBackgroundNoArgs if args.nil? || args.empty?
67
+ raise BackgroundNoArgs if args.nil? || args.empty?
65
68
 
66
- raise CannotHandleBackgroundFirstArgNil if args.first.nil?
69
+ raise BackgroundFirstArgNil if args.first.nil?
67
70
 
68
- raise CannotHandleBackgroundFirstArgEmpty if args.first.to_s.strip.empty?
71
+ raise BackgroundFirstArgEmpty if args.first.to_s.strip.empty?
69
72
  end
70
73
 
71
74
  def handle_linear_gradient(*args)
@@ -76,14 +79,14 @@ class Scriptorium::BannerSVG
76
79
  end
77
80
 
78
81
  private def validate_linear_gradient_args(args)
79
- raise CannotHandleLinearGradientNoArgs if args.nil? || args.empty?
82
+ raise LinearGradientNoArgs if args.nil? || args.empty?
80
83
 
81
- raise CannotHandleLinearGradientStartColorNil if args[0].nil? || args[0].to_s.strip.empty?
84
+ raise LinearGradientStartColorNil if args[0].nil? || args[0].to_s.strip.empty?
82
85
 
83
86
  # Validate all provided arguments (up to 3: start_color, end_color, direction)
84
87
  args.each_with_index do |arg, index|
85
88
  next if arg.nil? # Allow nil for optional arguments
86
- raise CannotHandleLinearGradientArgEmpty(index + 1) if arg.to_s.strip.empty?
89
+ raise LinearGradientArgEmpty(index + 1) if arg.to_s.strip.empty?
87
90
  end
88
91
  end
89
92
 
@@ -100,14 +103,14 @@ class Scriptorium::BannerSVG
100
103
  end
101
104
 
102
105
  private def validate_radial_gradient_args(args)
103
- raise CannotHandleRadialGradientNoArgs if args.nil? || args.empty?
106
+ raise RadialGradientNoArgs if args.nil? || args.empty?
104
107
 
105
- raise CannotHandleRadialGradientStartColorNil if args[0].nil? || args[0].to_s.strip.empty?
108
+ raise RadialGradientStartColorNil if args[0].nil? || args[0].to_s.strip.empty?
106
109
 
107
110
  # Validate all provided arguments (up to 6: start_color, end_color, cx, cy, r, aspect_ratio)
108
111
  args.each_with_index do |arg, index|
109
112
  next if arg.nil? # Allow nil for optional arguments
110
- raise CannotHandleRadialGradientArgEmpty(index + 1) if arg.to_s.strip.empty?
113
+ raise RadialGradientArgEmpty(index + 1) if arg.to_s.strip.empty?
111
114
  end
112
115
  end
113
116
 
@@ -119,11 +122,11 @@ class Scriptorium::BannerSVG
119
122
  end
120
123
 
121
124
  private def validate_image_background_args(args)
122
- raise CannotHandleImageBackgroundNoArgs if args.nil? || args.empty?
125
+ raise ImageBackgroundNoArgs if args.nil? || args.empty?
123
126
 
124
- raise CannotHandleImageBackgroundFirstArgNil if args[0].nil?
127
+ raise ImageBackgroundFirstArgNil if args[0].nil?
125
128
 
126
- raise CannotHandleImageBackgroundFirstArgEmpty if args[0].to_s.strip.empty?
129
+ raise ImageBackgroundFirstArgEmpty if args[0].to_s.strip.empty?
127
130
  end
128
131
 
129
132
  def handle_aspect(*args)
@@ -138,14 +141,14 @@ class Scriptorium::BannerSVG
138
141
  end
139
142
 
140
143
  private def validate_aspect_args(args)
141
- raise CannotHandleAspectNoArgs if args.nil? || args.empty?
144
+ raise AspectNoArgs if args.nil? || args.empty?
142
145
 
143
- raise CannotHandleAspectFirstArgNil if args.first.nil?
146
+ raise AspectFirstArgNil if args.first.nil?
144
147
 
145
- raise CannotHandleAspectFirstArgEmpty if args.first.to_s.strip.empty?
148
+ raise AspectFirstArgEmpty if args.first.to_s.strip.empty?
146
149
 
147
150
  unless args.first.to_s.match?(/^\d+(\.\d+)?$/)
148
- raise CannotHandleAspectInvalidValue(args.first)
151
+ raise AspectInvalidValue(args.first)
149
152
  end
150
153
  end
151
154
 
@@ -159,14 +162,14 @@ class Scriptorium::BannerSVG
159
162
  end
160
163
 
161
164
  private def validate_font_args(args)
162
- raise CannotHandleFontArgsNil if args.nil?
165
+ raise FontArgsNil if args.nil?
163
166
 
164
167
  # Font arguments are optional - empty args array is allowed
165
168
  # But if any arguments are provided, they must be valid
166
169
  args.each_with_index do |arg, index|
167
- raise CannotHandleFontArgNil(index + 1) if arg.nil?
170
+ raise FontArgNil(index + 1) if arg.nil?
168
171
 
169
- raise CannotHandleFontArgEmpty(index + 1) if arg.to_s.strip.empty?
172
+ raise FontArgEmpty(index + 1) if arg.to_s.strip.empty?
170
173
  end
171
174
  end
172
175
 
@@ -176,11 +179,11 @@ class Scriptorium::BannerSVG
176
179
  end
177
180
 
178
181
  private def validate_text_color_args(args)
179
- raise CannotHandleTextColorNoArgs if args.nil? || args.empty?
182
+ raise TextColorNoArgs if args.nil? || args.empty?
180
183
 
181
- raise CannotHandleTextColorFirstArgNil if args.first.nil?
184
+ raise TextColorFirstArgNil if args.first.nil?
182
185
 
183
- raise CannotHandleTextColorFirstArgEmpty if args.first.to_s.strip.empty?
186
+ raise TextColorFirstArgEmpty if args.first.to_s.strip.empty?
184
187
  end
185
188
 
186
189
  def handle_text_align(*args)
@@ -237,29 +240,29 @@ class Scriptorium::BannerSVG
237
240
  end
238
241
 
239
242
  private def validate_xy_which(which)
240
- raise CannotHandleXYWhichNil if which.nil?
243
+ raise XYWhichNil if which.nil?
241
244
 
242
- raise CannotHandleXYWhichEmpty if which.to_s.strip.empty?
245
+ raise XYWhichEmpty if which.to_s.strip.empty?
243
246
 
244
247
  unless ["title", "subtitle"].include?(which)
245
- raise CannotHandleXYInvalidWhich(which)
248
+ raise XYInvalidWhich(which)
246
249
  end
247
250
  end
248
251
 
249
252
  private def validate_align_args(args)
250
- raise CannotHandleAlignNoArgs if args.nil? || args.empty?
253
+ raise AlignNoArgs if args.nil? || args.empty?
251
254
 
252
- raise CannotHandleAlignDirectionNil if args[0].nil? || args[0].to_s.strip.empty?
255
+ raise AlignDirectionNil if args[0].nil? || args[0].to_s.strip.empty?
253
256
 
254
257
  unless ["left", "center", "right"].include?(args[0])
255
- raise CannotHandleAlignInvalidDirection(args[0])
258
+ raise AlignInvalidDirection(args[0])
256
259
  end
257
260
 
258
261
  # Validate optional x and y arguments if provided
259
262
  args.each_with_index do |arg, index|
260
263
  next if index == 0 # Skip direction (already validated)
261
264
  next if arg.nil? # Allow nil for optional arguments
262
- raise CannotHandleAlignArgEmpty(index + 1) if arg.to_s.strip.empty?
265
+ raise AlignArgEmpty(index + 1) if arg.to_s.strip.empty?
263
266
  end
264
267
  end
265
268
 
@@ -341,17 +344,13 @@ class Scriptorium::BannerSVG
341
344
  @subtitle_color = args.first
342
345
  end
343
346
 
344
-
345
-
346
347
  private def validate_color_args(args)
347
- raise CannotHandleColorNoArgs if args.nil? || args.empty?
348
-
349
- raise CannotHandleColorFirstArgNil if args.first.nil?
350
-
351
- raise CannotHandleColorFirstArgEmpty if args.first.to_s.strip.empty?
348
+ raise ColorNoArgs if args.nil? || args.empty?
349
+ raise ColorFirstArgNil if args.first.nil?
350
+ raise ColorFirstArgEmpty if args.first.to_s.strip.empty?
352
351
  end
353
352
 
354
- def parse_header_svg(config_file = "config.txt")
353
+ def parse_header_svg(config_file = "svg.txt")
355
354
  check_invariants
356
355
  assume { config_file.is_a?(String) && !config_file.empty? }
357
356
 
@@ -406,10 +405,9 @@ class Scriptorium::BannerSVG
406
405
  warn "[BannerSVG] Warning: subtitle.align x=#{@subtitle_align_x} conflicts with subtitle.xy x=#{@subtitle_xy[0]} (xy will override)"
407
406
  end
408
407
 
409
- # Set base font size
410
- base_font_size = 60
411
- title_font_size = (base_font_size * @title_scale).to_i
412
- subtitle_font_size = (base_font_size * @subtitle_scale).to_i
408
+ # Recalculate font sizes after config parsing
409
+ @title_font_size = @base_font_size * @title_scale
410
+ @subtitle_font_size = @base_font_size * @subtitle_scale
413
411
 
414
412
  width = 800 # Arbitrary starting point for calculations
415
413
  height = (width / @aspect).to_i # height calculated based on aspect ratio
@@ -466,12 +464,12 @@ class Scriptorium::BannerSVG
466
464
 
467
465
  # Build style strings
468
466
  title_style = "font-family: #{@font}; "
469
- title_style << "font-size: #{title_font_size}px; "
467
+ title_style << "font-size: #{@title_font_size}px; "
470
468
  title_style << "font-weight: #{@title_weight}; "
471
469
  title_style << "font-style: #{@title_style}"
472
470
 
473
471
  subtitle_style = "font-family: #{@font}; "
474
- subtitle_style << "font-size: #{subtitle_font_size}px; "
472
+ subtitle_style << "font-size: #{@subtitle_font_size}px; "
475
473
  subtitle_style << "font-weight: #{@subtitle_weight}; "
476
474
  subtitle_style << "font-style: #{@subtitle_style}"
477
475
 
@@ -506,11 +504,6 @@ class Scriptorium::BannerSVG
506
504
  def generate_svg
507
505
  check_invariants
508
506
 
509
- # Set base font size
510
- base_font_size = 60
511
- title_font_size = (base_font_size * @title_scale).to_i
512
- subtitle_font_size = (base_font_size * @subtitle_scale).to_i
513
-
514
507
  width = 800 # Arbitrary starting point for calculations
515
508
  height = (width / @aspect).to_i # height calculated based on aspect ratio
516
509
 
@@ -574,12 +567,12 @@ class Scriptorium::BannerSVG
574
567
 
575
568
  # Build style strings
576
569
  title_style = "font-family: #{@font}; "
577
- title_style << "font-size: #{title_font_size}px; "
570
+ title_style << "font-size: #{@title_font_size}px; "
578
571
  title_style << "font-weight: #{@title_weight}; "
579
572
  title_style << "font-style: #{@title_style}"
580
573
 
581
574
  subtitle_style = "font-family: #{@font}; "
582
- subtitle_style << "font-size: #{subtitle_font_size}px; "
575
+ subtitle_style << "font-size: #{@subtitle_font_size}px; "
583
576
  subtitle_style << "font-weight: #{@subtitle_weight}; "
584
577
  subtitle_style << "font-style: #{@subtitle_style}"
585
578
 
@@ -647,7 +640,7 @@ class Scriptorium::BannerSVG
647
640
 
648
641
  def get_svg
649
642
  check_invariants
650
-
643
+
651
644
  # Generate SVG without re-parsing config (use current instance variables)
652
645
  svg_code = generate_svg
653
646
  svg_lines = svg_code.split("\n").map {|line| " "*6 + line }
@@ -675,12 +668,8 @@ class Scriptorium::BannerSVG
675
668
  svg.setAttribute('width', svgWidth);
676
669
  svg.setAttribute('height', svgHeight);
677
670
 
678
- const titleScale = #{@title_scale};
679
- const subtitleScale = #{@subtitle_scale};
680
-
681
- const base_font_size = 60;
682
- const titleFontSize = titleScale * base_font_size;
683
- const subtitleFontSize = subtitleScale * base_font_size;
671
+ const titleFontSize = #{@title_scale} * #{@base_font_size};
672
+ const subtitleFontSize = #{@subtitle_scale} * #{@base_font_size};
684
673
 
685
674
  const te1 = svg.querySelector('text:nth-of-type(1)')
686
675
  const te2 = svg.querySelector('text:nth-of-type(2)')
@@ -706,6 +695,10 @@ class Scriptorium::BannerSVG
706
695
  // Set text-anchor for proper positioning (use individual anchors if set)
707
696
  te1.setAttribute('text-anchor', '#{@title_text_anchor || @text_anchor}');
708
697
  te2.setAttribute('text-anchor', '#{@subtitle_text_anchor || @text_anchor}');
698
+
699
+ // Apply calculated font sizes
700
+ te1.setAttribute('font-size', titleFontSize + 'px');
701
+ te2.setAttribute('font-size', subtitleFontSize + 'px');
709
702
 
710
703
  const containerElement = document.getElementById(container);
711
704
  if (containerElement) {
@@ -715,24 +708,18 @@ class Scriptorium::BannerSVG
715
708
  } else {
716
709
  console.error('Container not found:', container);
717
710
  }
718
- }
719
-
720
- console.log('SVG script loaded');
721
- console.log('Header element exists:', !!document.querySelector('header'));
722
-
723
- window.onload = function() {
724
- console.log('SVG insertion starting...');
725
- insert_svg_header('header');
726
- console.log('SVG insertion complete');
727
711
  }
728
712
 
729
- // Also try immediate execution
713
+ console.log('SVG script loaded');
714
+
715
+ // Use DOMContentLoaded to avoid conflicts with main window.onload
730
716
  document.addEventListener('DOMContentLoaded', function() {
731
717
  console.log('DOM ready, trying SVG insertion...');
732
718
  insert_svg_header('header');
733
719
  });
734
- </script>
720
+ </script>
735
721
  EOS
722
+
736
723
  code
737
724
  end
738
725
 
@@ -6,9 +6,10 @@ module Scriptorium::Contract
6
6
  def assume(condition = nil, message = nil, &block)
7
7
  return unless Scriptorium::Contract.enabled?
8
8
  if block_given?
9
- raise "Precondition violated: #{message}" unless instance_eval(&block)
9
+ result = instance_eval(&block)
10
+ raise "Precondition violated: #{message || 'block condition failed'}" unless result
10
11
  else
11
- raise "Precondition violated: #{message}" unless condition
12
+ raise "Precondition violated: #{message || condition}" unless condition
12
13
  end
13
14
  end
14
15
 
@@ -2,7 +2,7 @@ module Scriptorium::Exceptions
2
2
 
3
3
  def make_exception(sym, str, target_class = Object)
4
4
  return if target_class.constants.include?(sym)
5
- klass = sym # :"#{sym}_Class"
5
+ klass = sym
6
6
  target_class.const_set(klass, StandardError)
7
7
  define_method(sym) do |*args|
8
8
  args = [] unless args.first
@@ -32,32 +32,32 @@ module Scriptorium::Exceptions
32
32
  make_exception :InvalidFormatError, "Invalid format '%1': %2"
33
33
 
34
34
  # Specific validation errors
35
- make_exception :CannotCreateViewNameNil, "Cannot create view: name is nil"
36
- make_exception :CannotCreateViewNameEmpty, "Cannot create view: name is empty or whitespace-only"
37
- make_exception :CannotCreateViewNameInvalid, "Cannot create view: invalid name '%1' (only alphanumeric, hyphen, and underscore allowed)"
38
- make_exception :CannotCreateViewTitleNil, "Cannot create view: title is nil"
39
- make_exception :CannotCreateViewTitleEmpty, "Cannot create view: title is empty or whitespace-only"
40
-
41
- make_exception :CannotLookupViewTargetNil, "Cannot lookup view: target is nil"
42
- make_exception :CannotLookupViewTargetEmpty, "Cannot lookup view: target is empty or whitespace-only"
43
-
44
- make_exception :CannotGetPostIdNil, "Cannot get post: id is nil"
45
- make_exception :CannotGetPostIdEmpty, "Cannot get post: id is empty or whitespace-only"
46
- make_exception :CannotGetPostIdInvalid, "Cannot get post: invalid id '%1' (must be numeric)"
47
-
48
- make_exception :CannotCreatePostRepoNil, "Cannot create post: repo is nil"
49
- make_exception :CannotCreatePostNumNil, "Cannot create post: num is nil"
50
- make_exception :CannotCreatePostNumEmpty, "Cannot create post: num is empty or whitespace-only"
51
- make_exception :CannotCreatePostNumInvalid, "Cannot create post: invalid num '%1' (must be numeric)"
52
-
53
- make_exception :CannotSetPubdateYmdNil, "Cannot set pubdate: ymd is nil"
54
- make_exception :CannotSetPubdateYmdEmpty, "Cannot set pubdate: ymd is empty or whitespace-only"
55
- make_exception :CannotSetPubdateInvalidFormat, "Cannot set pubdate: invalid date format '%1' (expected YYYY-MM-DD)"
56
-
57
- make_exception :CannotBuildWidgetsArgNil, "Cannot build widgets: argument is nil"
58
- make_exception :CannotBuildWidgetsArgEmpty, "Cannot build widgets: argument is empty or whitespace-only"
59
- make_exception :CannotBuildWidgetNameNil, "Cannot build widget: widget name is nil or empty"
60
- make_exception :CannotBuildWidgetNameInvalid, "Cannot build widget: invalid widget name '%1' (only alphanumeric and underscore allowed)"
35
+ make_exception :ViewNameNil, "Cannot create view: name is nil"
36
+ make_exception :ViewNameEmpty, "Cannot create view: name is empty or whitespace-only"
37
+ make_exception :ViewNameInvalid, "Cannot create view: invalid name '%1' (only alphanumeric, hyphen, and underscore allowed)"
38
+ make_exception :ViewTitleNil, "Cannot create view: title is nil"
39
+ make_exception :ViewTitleEmpty, "Cannot create view: title is empty or whitespace-only"
40
+ make_exception :ViewTargetNil, "Cannot lookup view: target is nil"
41
+ make_exception :ViewTargetEmpty, "Cannot lookup view: target is empty or whitespace-only"
42
+ make_exception :ViewTargetInvalid, "Cannot lookup view: invalid target '%1' (must be 'view' or 'post')"
43
+
44
+ make_exception :PostIdNil, "Cannot get post: id is nil"
45
+ make_exception :PostIdEmpty, "Cannot get post: id is empty or whitespace-only"
46
+ make_exception :PostIdInvalid, "Cannot get post: invalid id '%1' (must be numeric)"
47
+
48
+ make_exception :PostRepoNil, "Cannot create post: repo is nil"
49
+ make_exception :PostNumNil, "Cannot create post: num is nil"
50
+ make_exception :PostNumEmpty, "Cannot create post: num is empty or whitespace-only"
51
+ make_exception :PostNumInvalid, "Cannot create post: invalid num '%1' (must be numeric)"
52
+
53
+ make_exception :PubdateYmdNil, "Cannot set pubdate: ymd is nil"
54
+ make_exception :PubdateYmdEmpty, "Cannot set pubdate: ymd is empty or whitespace-only"
55
+ make_exception :PubdateInvalidFormat, "Cannot set pubdate: invalid date format '%1' (expected YYYY-MM-DD)"
56
+
57
+ make_exception :WidgetsArgNil, "Cannot build widgets: argument is nil"
58
+ make_exception :WidgetsArgEmpty, "Cannot build widgets: argument is empty or whitespace-only"
59
+ make_exception :WidgetNameNil, "Cannot build widget: widget name is nil or empty"
60
+ make_exception :WidgetNameInvalid, "Cannot build widget: invalid widget name '%1' (only alphanumeric and underscore allowed)"
61
61
 
62
62
  # File/IO errors
63
63
  make_exception :FileNotFoundError, "File not found: %1"
@@ -66,31 +66,31 @@ module Scriptorium::Exceptions
66
66
  make_exception :DirectoryNotFoundError, "Directory not found: %1"
67
67
 
68
68
  # Specific file/IO errors
69
- make_exception :CannotWriteFilePathNil, "Cannot write file: file path is nil"
70
- make_exception :CannotWriteFilePathEmpty, "Cannot write file: file path is empty or whitespace-only"
71
- make_exception :CannotWriteFilePermissionDenied, "Cannot write file %1: permission denied (%2)"
72
- make_exception :CannotWriteFileDiskFull, "Cannot write file %1: disk full (%2)"
73
- make_exception :CannotWriteFileDirectoryNotFound, "Cannot write file %1: directory not found (%2)"
69
+ make_exception :FilePathNil, "Cannot write file: file path is nil"
70
+ make_exception :FilePathEmpty, "Cannot write file: file path is empty or whitespace-only"
71
+ make_exception :FilePermissionDenied, "Cannot write file %1: permission denied (%2)"
72
+ make_exception :FileDiskFull, "Cannot write file %1: disk full (%2)"
73
+ make_exception :FileDirectoryNotFound, "Cannot write file %1: directory not found (%2)"
74
74
  make_exception :CannotWriteFileError, "Cannot write file %1: %2"
75
75
 
76
- make_exception :CannotCreateDirectoryPathNil, "Cannot create directory: directory path is nil"
77
- make_exception :CannotCreateDirectoryPathEmpty, "Cannot create directory: directory path is empty or whitespace-only"
78
- make_exception :CannotCreateDirectoryPermissionDenied, "Cannot create directory %1: permission denied (%2)"
79
- make_exception :CannotCreateDirectoryParentNotFound, "Cannot create directory %1: parent directory not found (%2)"
80
- make_exception :CannotCreateDirectoryDiskFull, "Cannot create directory %1: disk full (%2)"
81
- make_exception :CannotCreateDirectoryError, "Cannot create directory %1: %2"
76
+ make_exception :DirectoryPathNil, "Cannot create directory: directory path is nil"
77
+ make_exception :DirectoryPathEmpty, "Cannot create directory: directory path is empty or whitespace-only"
78
+ make_exception :DirectoryPermissionDenied, "Cannot create directory %1: permission denied (%2)"
79
+ make_exception :DirectoryParentNotFound, "Cannot create directory %1: parent directory not found (%2)"
80
+ make_exception :DirectoryDiskFull, "Cannot create directory %1: disk full (%2)"
81
+ make_exception :DirectoryError, "Cannot create directory %1: %2"
82
82
 
83
- make_exception :CannotReadFilePathNil, "Cannot read file: file path is nil"
84
- make_exception :CannotReadFilePathEmpty, "Cannot read file: file path is empty or whitespace-only"
85
- make_exception :CannotReadFileNotFound, "Cannot read file %1: file not found (%2)"
86
- make_exception :CannotReadFilePermissionDenied, "Cannot read file %1: permission denied (%2)"
87
- make_exception :CannotReadFileError, "Cannot read file %1: %2"
83
+ make_exception :ReadFilePathNil, "Cannot read file: file path is nil"
84
+ make_exception :ReadFilePathEmpty, "Cannot read file: file path is empty or whitespace-only"
85
+ make_exception :ReadFileNotFound, "Cannot read file %1: file not found (%2)"
86
+ make_exception :ReadFilePermissionDenied, "Cannot read file %1: permission denied (%2)"
87
+ make_exception :ReadFileError, "Cannot read file %1: %2"
88
88
 
89
- make_exception :CannotEditFilePathNil, "Cannot edit file: file path is nil"
90
- make_exception :CannotEditFilePathEmpty, "Cannot edit file: file path is empty or whitespace-only"
89
+ make_exception :EditFilePathNil, "Cannot edit file: file path is nil"
90
+ make_exception :EditFilePathEmpty, "Cannot edit file: file path is empty or whitespace-only"
91
91
 
92
- make_exception :CannotRequirePathNil, "Cannot require %1: path is nil"
93
- make_exception :CannotRequirePathEmpty, "Cannot require %1: path is empty or whitespace-only"
92
+ make_exception :RequirePathNil, "Cannot require %1: path is nil"
93
+ make_exception :RequirePathEmpty, "Cannot require %1: path is empty or whitespace-only"
94
94
  make_exception :RequiredFileNotFound, "Required %1 not found: %2"
95
95
  make_exception :InvalidType, "Invalid type: %1 (must be :file or :dir)"
96
96
 
@@ -101,74 +101,105 @@ module Scriptorium::Exceptions
101
101
  # Post errors
102
102
  make_exception :CannotCreatePost, "Cannot create post: %1"
103
103
  make_exception :CannotGetPost, "Cannot get post: %1"
104
+ make_exception :PostAlreadyPublished, "Post %1 is already published"
105
+ make_exception :PostNotPublished, "Post %1 is not published"
106
+ make_exception :PostAlreadyDeployed, "Post %1 is already deployed"
107
+ make_exception :PostDeleted, "Post %1 is deleted"
108
+ make_exception :PostAlreadyDeleted, "Post %1 is already deleted"
109
+ make_exception :PostNotDeleted, "Post %1 is not deleted"
110
+ make_exception :PostNotDeployed, "Post %1 is not deployed"
111
+ make_exception :InvalidStateTransition, "Invalid state transition: %1"
104
112
  make_exception :CannotSetPubdate, "Cannot set pubdate: %1"
105
113
 
106
114
  # Banner SVG errors
107
- make_exception :CannotHandleBackground, "Cannot handle background: %1"
108
- make_exception :CannotHandleGradient, "Cannot handle gradient: %1"
109
- make_exception :CannotHandleImage, "Cannot handle image: %1"
110
- make_exception :CannotHandleAspect, "Cannot handle aspect: %1"
111
- make_exception :CannotHandleFont, "Cannot handle font: %1"
112
- make_exception :CannotHandleColor, "Cannot handle color: %1"
113
- make_exception :CannotHandleAlign, "Cannot handle align: %1"
114
- make_exception :CannotHandleXY, "Cannot handle xy: %1"
115
+ make_exception :InvalidBackground, "Cannot handle background: %1"
116
+ make_exception :InvalidGradient, "Cannot handle gradient: %1"
117
+ make_exception :InvalidImage, "Cannot handle image: %1"
118
+ make_exception :InvalidAspect, "Cannot handle aspect: %1"
119
+ make_exception :InvalidFont, "Cannot handle font: %1"
120
+ make_exception :InvalidColor, "Cannot handle color: %1"
121
+ make_exception :InvalidAlign, "Cannot handle align: %1"
122
+ make_exception :InvalidXY, "Cannot handle xy: %1"
115
123
 
116
124
  # Specific Banner SVG errors
117
- make_exception :CannotHandleBackgroundNoArgs, "Cannot handle background: no arguments provided"
118
- make_exception :CannotHandleBackgroundFirstArgNil, "Cannot handle background: first argument is nil"
119
- make_exception :CannotHandleBackgroundFirstArgEmpty, "Cannot handle background: first argument is empty or whitespace-only"
120
-
121
- make_exception :CannotHandleLinearGradientNoArgs, "Cannot handle linear gradient: no arguments provided"
122
- make_exception :CannotHandleLinearGradientStartColorNil, "Cannot handle linear gradient: start color is nil or empty"
123
- make_exception :CannotHandleLinearGradientArgEmpty, "Cannot handle linear gradient: argument %1 is empty or whitespace-only"
124
-
125
- make_exception :CannotHandleRadialGradientNoArgs, "Cannot handle radial gradient: no arguments provided"
126
- make_exception :CannotHandleRadialGradientStartColorNil, "Cannot handle radial gradient: start color is nil or empty"
127
- make_exception :CannotHandleRadialGradientArgEmpty, "Cannot handle radial gradient: argument %1 is empty or whitespace-only"
128
-
129
- make_exception :CannotHandleImageBackgroundNoArgs, "Cannot handle image background: no arguments provided"
130
- make_exception :CannotHandleImageBackgroundFirstArgNil, "Cannot handle image background: first argument is nil"
131
- make_exception :CannotHandleImageBackgroundFirstArgEmpty, "Cannot handle image background: first argument is empty or whitespace-only"
132
-
133
- make_exception :CannotHandleAspectNoArgs, "Cannot handle aspect: no arguments provided"
134
- make_exception :CannotHandleAspectFirstArgNil, "Cannot handle aspect: first argument is nil"
135
- make_exception :CannotHandleAspectFirstArgEmpty, "Cannot handle aspect: first argument is empty or whitespace-only"
136
- make_exception :CannotHandleAspectInvalidValue, "Cannot handle aspect: invalid aspect value '%1' (must be numeric)"
137
-
138
- make_exception :CannotHandleFontArgsNil, "Cannot handle font: arguments are nil"
139
- make_exception :CannotHandleFontArgNil, "Cannot handle font: argument %1 is nil"
140
- make_exception :CannotHandleFontArgEmpty, "Cannot handle font: argument %1 is empty or whitespace-only"
141
-
142
- make_exception :CannotHandleTextColorNoArgs, "Cannot handle text color: no arguments provided"
143
- make_exception :CannotHandleTextColorFirstArgNil, "Cannot handle text color: first argument is nil"
144
- make_exception :CannotHandleTextColorFirstArgEmpty, "Cannot handle text color: first argument is empty or whitespace-only"
145
-
146
- make_exception :CannotHandleXYWhichNil, "Cannot handle xy: which is nil"
147
- make_exception :CannotHandleXYWhichEmpty, "Cannot handle xy: which is empty or whitespace-only"
148
- make_exception :CannotHandleXYInvalidWhich, "Cannot handle xy: invalid which '%1' (must be 'title' or 'subtitle')"
149
-
150
- make_exception :CannotHandleAlignNoArgs, "Cannot handle align: no arguments provided"
151
- make_exception :CannotHandleAlignDirectionNil, "Cannot handle align: direction is nil or empty"
152
- make_exception :CannotHandleAlignInvalidDirection, "Cannot handle align: invalid direction '%1' (must be 'left', 'center', or 'right')"
153
- make_exception :CannotHandleAlignArgEmpty, "Cannot handle align: argument %1 is empty or whitespace-only"
154
-
155
- make_exception :CannotHandleColorNoArgs, "Cannot handle color: no arguments provided"
156
- make_exception :CannotHandleColorFirstArgNil, "Cannot handle color: first argument is nil"
157
- make_exception :CannotHandleColorFirstArgEmpty, "Cannot handle color: first argument is empty or whitespace-only"
158
-
159
-
160
-
125
+ make_exception :BackgroundNoArgs, "Cannot handle background: no arguments provided"
126
+ make_exception :BackgroundFirstArgNil, "Cannot handle background: first argument is nil"
127
+ make_exception :BackgroundFirstArgEmpty, "Cannot handle background: first argument is empty or whitespace-only"
128
+
129
+ make_exception :LinearGradientNoArgs, "Cannot handle linear gradient: no arguments provided"
130
+ make_exception :LinearGradientStartColorNil, "Cannot handle linear gradient: start color is nil or empty"
131
+ make_exception :LinearGradientArgEmpty, "Cannot handle linear gradient: argument %1 is empty or whitespace-only"
132
+
133
+ make_exception :RadialGradientNoArgs, "Cannot handle radial gradient: no arguments provided"
134
+ make_exception :RadialGradientStartColorNil, "Cannot handle radial gradient: start color is nil or empty"
135
+ make_exception :RadialGradientArgEmpty, "Cannot handle radial gradient: argument %1 is empty or whitespace-only"
136
+
137
+ make_exception :ImageBackgroundNoArgs, "Cannot handle image background: no arguments provided"
138
+ make_exception :ImageBackgroundFirstArgNil, "Cannot handle image background: first argument is nil"
139
+ make_exception :ImageBackgroundFirstArgEmpty, "Cannot handle image background: first argument is empty or whitespace-only"
140
+
141
+ make_exception :AspectNoArgs, "Cannot handle aspect: no arguments provided"
142
+ make_exception :AspectFirstArgNil, "Cannot handle aspect: first argument is nil"
143
+ make_exception :AspectFirstArgEmpty, "Cannot handle aspect: first argument is empty or whitespace-only"
144
+ make_exception :AspectInvalidValue, "Cannot handle aspect: invalid aspect value '%1' (must be numeric)"
145
+
146
+ make_exception :FontArgsNil, "Cannot handle font: arguments are nil"
147
+ make_exception :FontArgNil, "Cannot handle font: argument %1 is nil"
148
+ make_exception :FontArgEmpty, "Cannot handle font: argument %1 is empty or whitespace-only"
149
+
150
+ make_exception :TextColorNoArgs, "Cannot handle text color: no arguments provided"
151
+ make_exception :TextColorFirstArgNil, "Cannot handle text color: first argument is nil"
152
+ make_exception :TextColorFirstArgEmpty, "Cannot handle text color: first argument is empty or whitespace-only"
153
+
154
+ make_exception :XYWhichNil, "Cannot handle xy: which is nil"
155
+ make_exception :XYWhichEmpty, "Cannot handle xy: which is empty or whitespace-only"
156
+ make_exception :XYInvalidWhich, "Cannot handle xy: invalid which '%1' (must be 'title' or 'subtitle')"
157
+
158
+ make_exception :AlignNoArgs, "Cannot handle align: no arguments provided"
159
+ make_exception :AlignDirectionNil, "Cannot handle align: direction is nil or empty"
160
+ make_exception :AlignInvalidDirection, "Cannot handle align: invalid direction '%1' (must be 'left', 'center', or 'right')"
161
+ make_exception :AlignArgEmpty, "Cannot handle align: argument %1 is empty or whitespace-only"
162
+
163
+ make_exception :ColorNoArgs, "Cannot handle color: no arguments provided"
164
+ make_exception :ColorFirstArgNil, "Cannot handle color: first argument is nil"
165
+ make_exception :ColorFirstArgEmpty, "Cannot handle color: first argument is empty or whitespace-only"
166
+
161
167
  # Command errors
162
168
  make_exception :CommandFailed, "Command failed: %1"
163
169
  make_exception :CannotExecuteCommand, "Cannot execute command: %1"
164
170
 
165
171
  # Specific command errors
166
- make_exception :CannotExecuteCommandNil, "Cannot execute command: command is nil"
167
- make_exception :CannotExecuteCommandEmpty, "Cannot execute command: command is empty or whitespace-only"
172
+ make_exception :CommandNil, "Cannot execute command: command is nil"
173
+ make_exception :CommandEmpty, "Cannot execute command: command is empty or whitespace-only"
168
174
  make_exception :CommandFailedWithDesc, "Command failed%1: %2"
169
175
 
170
176
  # Section/Output errors
171
177
  make_exception :SectionOutputError, "Section output error: %1 (section: %2) - %3"
172
- make_exception :FailedToWriteFrontPage, "Failed to write front page: %1"
178
+ make_exception :WriteFrontPageError, "Failed to write front page: %1"
179
+
180
+ # Theme management errors
181
+ make_exception :ThemeNotFound, "Theme not found: %1"
182
+ make_exception :ThemeAlreadyExists, "Theme already exists: %1"
183
+ make_exception :ThemeNameInvalid, "Theme name must contain only letters, numbers, hyphens, and underscores: %1"
184
+
185
+ # Draft management errors
186
+ make_exception :DraftPathNil, "Draft path cannot be nil"
187
+ make_exception :DraftPathEmpty, "Draft path cannot be empty"
188
+ make_exception :DraftFileInvalid, "Not a valid draft file: %1"
189
+ make_exception :DraftFileNotFound, "Draft file not found: %1"
190
+
191
+ # Search/Query errors
192
+ make_exception :UnknownSearchField, "Unknown search field: %1"
193
+
194
+ # Deployment errors
195
+ make_exception :DeploymentNotReady, "View '%1' is not ready for deployment. Check status and configuration."
196
+ make_exception :DeploymentFieldsMissing, "Missing required deployment fields: %1"
197
+ make_exception :DeploymentFailed, "Deployment failed with exit code %1"
198
+
199
+ # Backup errors
200
+ make_exception :BackupNotFound, "Backup not found: %1"
201
+ make_exception :BackupCreationFailed, "Failed to create backup: %1"
202
+ make_exception :BackupRestoreFailed, "Failed to restore backup: %1"
203
+ make_exception :BackupDeleteFailed, "Failed to delete backup: %1"
173
204
 
174
205
  end