scriptorium 0.0.2 → 0.6.1

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 (290) hide show
  1. checksums.yaml +4 -4
  2. data/README.lt3 +324 -0
  3. data/README.md +3155 -1
  4. data/assets/.DS_Store +0 -0
  5. data/assets/README.md +44 -0
  6. data/assets/back-icon.png +0 -0
  7. data/assets/icons/facebook.svg +1 -0
  8. data/assets/icons/github.svg +1 -0
  9. data/assets/icons/instagram.svg +1 -0
  10. data/assets/icons/reddit.svg +1 -0
  11. data/assets/icons/ui/.DS_Store +0 -0
  12. data/assets/icons/ui/back.png +0 -0
  13. data/assets/icons/ui/copy.png +0 -0
  14. data/assets/icons/ui/down.png +0 -0
  15. data/assets/icons/ui/end.png +0 -0
  16. data/assets/icons/ui/exit.png +0 -0
  17. data/assets/icons/ui/foo +10 -0
  18. data/assets/icons/ui/home.png +0 -0
  19. data/assets/icons/ui/left.png +0 -0
  20. data/assets/icons/ui/next.png +0 -0
  21. data/assets/icons/ui/right.png +0 -0
  22. data/assets/icons/ui/start.png +0 -0
  23. data/assets/icons/ui/up.png +0 -0
  24. data/assets/icons/x.svg +1 -0
  25. data/assets/icons/youtube.svg +1 -0
  26. data/assets/samples/placeholder.svg +9 -0
  27. data/assets/themes/standard/favicon.svg +6 -0
  28. data/bin/scriptorium +1511 -0
  29. data/doc/README.txt +6 -0
  30. data/doc/anti-amnesia/20250727-054000-scriptorium-overview.md +95 -0
  31. data/doc/anti-amnesia/20250727-060000-api-design-tui-planning.md +34 -0
  32. data/doc/anti-amnesia/20250727-061000-runeblog-tui-analysis.md +50 -0
  33. data/doc/anti-amnesia/20250727-123000-anti-amnesia-conventions.md +31 -0
  34. data/doc/anti-amnesia/20250727-154000-livetext-plugin-file-stats.md +73 -0
  35. data/doc/anti-amnesia/20250727-172600-cursor-rbenv-ruby-version-mystery.md +64 -0
  36. data/doc/anti-amnesia/20250727-172600-unified-minitest-framework.md +70 -0
  37. data/doc/anti-amnesia/20250727-172900-ai-cognitive-assessment-capabilities.md +40 -0
  38. data/doc/anti-amnesia/20250727-173000-widget-testing-achievement.md +110 -0
  39. data/doc/anti-amnesia/20250727-180000-post-id-num-refactoring.md +73 -0
  40. data/doc/anti-amnesia/20250728-124243-aaa-syntax-clarification.md +46 -0
  41. data/doc/anti-amnesia/20250728-124421-conversation-summary-concise.md +124 -0
  42. data/doc/anti-amnesia/20250729-190000-scriptorium-tui-testing-complete.md +46 -0
  43. data/doc/anti-amnesia/20250729-200000-scriptorium-tui-testing-edit-file-workflow.md +97 -0
  44. data/doc/anti-amnesia/20250729-210000-reddit-autopost-integration-complete.md +158 -0
  45. data/doc/anti-amnesia/20250729-211500-dependency-management-system.md +211 -0
  46. data/doc/anti-amnesia/20250729-213000-python-virtual-environment-setup.md +141 -0
  47. data/doc/anti-amnesia/20250729-214500-theme-management-commands.md +211 -0
  48. data/doc/anti-amnesia/20250729-215000-version-update-to-0.6.0.md +134 -0
  49. data/doc/anti-amnesia/20250729-220000-user-guide-complete.md +41 -0
  50. data/doc/anti-amnesia/20250804-190500-cognitive-loop-bug.md +45 -0
  51. data/doc/anti-amnesia/20250804-190700-anti-amnesia-timestamping-fix.md +30 -0
  52. data/doc/anti-amnesia/20250804-213700-publishing-test-fix.md +49 -0
  53. data/doc/anti-amnesia/20250804-214400-additional-test-fixes.md +46 -0
  54. data/doc/anti-amnesia/20250804-220000-asset-function-logic-clarification.md +41 -0
  55. data/doc/anti-amnesia/20250806-202032-asset-function-logic-clarification.md +41 -0
  56. data/doc/anti-amnesia/20250807-213025.md +116 -0
  57. data/doc/anti-amnesia/20250813-082428-syntax-highlighting-and-navigation-improvements.md +256 -0
  58. data/doc/banner_svg_config.md +114 -0
  59. data/doc/contrib.lt3 +8 -0
  60. data/doc/dependencies.md +281 -0
  61. data/doc/hacker.lt3 +5 -0
  62. data/doc/reddit_credentials_template.json +8 -0
  63. data/doc/reddit_integration.md +207 -0
  64. data/doc/user.lt3 +38 -0
  65. data/doc/user_guide_section_1.md +137 -0
  66. data/doc/user_guide_section_10.md +515 -0
  67. data/doc/user_guide_section_11.md +708 -0
  68. data/doc/user_guide_section_2.md +233 -0
  69. data/doc/user_guide_section_3.md +5 -0
  70. data/doc/user_guide_section_4.md +221 -0
  71. data/doc/user_guide_section_5.md +243 -0
  72. data/doc/user_guide_section_6.md +147 -0
  73. data/doc/user_guide_section_7.md +311 -0
  74. data/doc/user_guide_section_8.md +224 -0
  75. data/doc/user_guide_section_9.md +375 -0
  76. data/doc/userdoc-toc.txt +88 -0
  77. data/lib/rouge/lexers/livetext.rb +74 -0
  78. data/lib/scriptorium/api.rb +640 -0
  79. data/lib/scriptorium/banner_svg.rb +742 -0
  80. data/lib/scriptorium/contract.rb +33 -0
  81. data/lib/scriptorium/exceptions.rb +174 -0
  82. data/lib/scriptorium/helpers.rb +475 -0
  83. data/lib/scriptorium/post.rb +195 -0
  84. data/lib/scriptorium/reddit.rb +83 -0
  85. data/lib/scriptorium/repo.rb +624 -0
  86. data/lib/scriptorium/standard_files.rb +515 -0
  87. data/lib/scriptorium/syntax_highlighter.rb +234 -0
  88. data/lib/scriptorium/theme.rb +179 -0
  89. data/lib/scriptorium/version.rb +2 -2
  90. data/lib/scriptorium/view.rb +976 -0
  91. data/lib/scriptorium/widgets/featured_posts.rb +149 -0
  92. data/lib/scriptorium/widgets/links.rb +112 -0
  93. data/lib/scriptorium/widgets/pages.rb +133 -0
  94. data/lib/scriptorium/widgets/widget.rb +133 -0
  95. data/lib/scriptorium.rb +22 -9
  96. data/lib/skeleton.rb +11 -2
  97. data/scriptorium.gemspec +15 -4
  98. data/test/README.md +69 -0
  99. data/test/all +43 -0
  100. data/test/api_demo.rb +99 -0
  101. data/test/assets/imagenotfound.jpg +0 -0
  102. data/test/assets/images/.DS_Store +0 -0
  103. data/test/assets/images/README.md +27 -0
  104. data/test/assets/images/odd_aspect.png +0 -0
  105. data/test/assets/images/perfect.png +0 -0
  106. data/test/assets/images/small.png +0 -0
  107. data/test/assets/images/tall.png +0 -0
  108. data/test/assets/images/very_tall.png +0 -0
  109. data/test/assets/images/very_wide.png +0 -0
  110. data/test/assets/images/wide.png +0 -0
  111. data/test/assets/testbanner.jpg +0 -0
  112. data/test/banner_svg/simple_helpers.rb +13 -0
  113. data/test/banner_svg/unit.rb +768 -0
  114. data/test/ed_test.rb +204 -0
  115. data/test/integration/cursor_banner_combinations.rb +193 -0
  116. data/test/integration/cursor_banner_features.rb +374 -0
  117. data/test/integration/integration_test.rb +326 -0
  118. data/test/livetext_plugin_test.rb +229 -0
  119. data/test/manual/asset_mgmt.rb +67 -0
  120. data/test/manual/banner-tests/config.txt +3 -0
  121. data/test/manual/banner-tests/index.html +45 -0
  122. data/test/manual/banner-tests/test01.html +58 -0
  123. data/test/manual/banner-tests/test02.html +58 -0
  124. data/test/manual/banner-tests/test03.html +58 -0
  125. data/test/manual/banner-tests/test04.html +65 -0
  126. data/test/manual/banner-tests/test05.html +65 -0
  127. data/test/manual/banner-tests/test06.html +65 -0
  128. data/test/manual/banner-tests/test07.html +65 -0
  129. data/test/manual/banner-tests/test08.html +59 -0
  130. data/test/manual/banner-tests/test09.html +59 -0
  131. data/test/manual/banner-tests/test10.html +59 -0
  132. data/test/manual/banner-tests/test11.html +59 -0
  133. data/test/manual/banner-tests/test12.html +59 -0
  134. data/test/manual/banner-tests/test13.html +59 -0
  135. data/test/manual/banner-tests/test14.html +59 -0
  136. data/test/manual/banner-tests/test15.html +58 -0
  137. data/test/manual/banner-tests/test16.html +58 -0
  138. data/test/manual/banner-tests/test17.html +58 -0
  139. data/test/manual/banner-tests/test18.html +68 -0
  140. data/test/manual/banner-tests/test19.html +68 -0
  141. data/test/manual/banner-tests/test20.html +68 -0
  142. data/test/manual/banner-tests/test21.html +68 -0
  143. data/test/manual/banner-tests/test22.html +68 -0
  144. data/test/manual/banner-tests/test23.html +68 -0
  145. data/test/manual/banner-tests/test24.html +68 -0
  146. data/test/manual/banner-tests/test25.html +67 -0
  147. data/test/manual/banner_environment.rb +192 -0
  148. data/test/manual/deploy_symlink_demo.rb +142 -0
  149. data/test/manual/environment.rb +67 -0
  150. data/test/manual/make_banner.rb +153 -0
  151. data/test/manual/sample_banner_config.txt +12 -0
  152. data/test/manual/symlink_demo.rb +117 -0
  153. data/test/manual/test1.rb +47 -0
  154. data/test/manual/test2.rb +12 -0
  155. data/test/manual/test3.rb +38 -0
  156. data/test/manual/test4.rb +40 -0
  157. data/test/manual/test5.rb +24 -0
  158. data/test/manual/test6.rb +73 -0
  159. data/test/manual/test_banner_combinations.rb +120 -0
  160. data/test/manual/test_banner_features.rb +306 -0
  161. data/test/manual/test_banner_from_file.rb +150 -0
  162. data/test/manual/test_banner_in_header.rb +35 -0
  163. data/test/manual/test_code_highlighting.rb +68 -0
  164. data/test/manual/test_complex_header.rb +74 -0
  165. data/test/manual/test_empty_header.rb +32 -0
  166. data/test/manual/test_radial_custom.rb +58 -0
  167. data/test/manual/test_radial_large_radius.rb +52 -0
  168. data/test/manual/test_svg_debug.rb +47 -0
  169. data/test/manual/test_syntax_highlighting.rb +147 -0
  170. data/test/pages-demo/config/currentview.txt +1 -0
  171. data/test/pages-demo/views/demo/config/bootstrap_css.txt +5 -0
  172. data/test/pages-demo/views/demo/config/bootstrap_js.txt +4 -0
  173. data/test/pages-demo/views/demo/config/common.js +57 -0
  174. data/test/pages-demo/views/demo/config/footer.txt +1 -0
  175. data/test/pages-demo/views/demo/config/global-head.txt +8 -0
  176. data/test/pages-demo/views/demo/config/header.txt +1 -0
  177. data/test/pages-demo/views/demo/config/layout.txt +1 -0
  178. data/test/pages-demo/views/demo/config/left.txt +1 -0
  179. data/test/pages-demo/views/demo/config/main.txt +1 -0
  180. data/test/pages-demo/views/demo/config/right.txt +1 -0
  181. data/test/pages-demo/views/demo/config.txt +3 -0
  182. data/test/pages-demo/views/demo/output/panes/footer.html +1 -0
  183. data/test/pages-demo/views/demo/output/panes/header.html +1 -0
  184. data/test/pages-demo/views/demo/output/panes/left.html +1 -0
  185. data/test/pages-demo/views/demo/output/panes/main.html +1 -0
  186. data/test/pages-demo/views/demo/output/panes/right.html +1 -0
  187. data/test/rubytext/rubytext_comprehensive_test.rb +307 -0
  188. data/test/rubytext/rubytext_demo_test.rb +42 -0
  189. data/test/rubytext/rubytext_testing_guide.md +277 -0
  190. data/test/run_automated_tests.rb +45 -0
  191. data/test/scriptorium-TEST-1754622690-146/config/bootstrap_css.txt +5 -0
  192. data/test/scriptorium-TEST-1754622690-146/config/bootstrap_js.txt +4 -0
  193. data/test/scriptorium-TEST-1754622690-146/config/common.js +57 -0
  194. data/test/scriptorium-TEST-1754622690-146/config/currentview.txt +1 -0
  195. data/test/scriptorium-TEST-1754622690-146/config/global-head.txt +9 -0
  196. data/test/scriptorium-TEST-1754622690-146/config/last_post_num.txt +1 -0
  197. data/test/scriptorium-TEST-1754622690-146/config/os_helpers.rb +4 -0
  198. data/test/scriptorium-TEST-1754622690-146/config/widgets.txt +3 -0
  199. data/test/scriptorium-TEST-1754622690-146/posts/0001/meta.txt +8 -0
  200. data/test/scriptorium-TEST-1754622690-146/posts/0001/source.lt3 +6 -0
  201. data/test/scriptorium-TEST-1754622690-146/themes/standard/README.txt +1 -0
  202. data/test/scriptorium-TEST-1754622690-146/themes/standard/config.txt +1 -0
  203. data/test/scriptorium-TEST-1754622690-146/themes/standard/initial/post.lt3 +12 -0
  204. data/test/scriptorium-TEST-1754622690-146/themes/standard/layout/config/footer.txt +2 -0
  205. data/test/scriptorium-TEST-1754622690-146/themes/standard/layout/config/header.txt +4 -0
  206. data/test/scriptorium-TEST-1754622690-146/themes/standard/layout/config/left.txt +3 -0
  207. data/test/scriptorium-TEST-1754622690-146/themes/standard/layout/config/main.txt +5 -0
  208. data/test/scriptorium-TEST-1754622690-146/themes/standard/layout/config/right.txt +3 -0
  209. data/test/scriptorium-TEST-1754622690-146/themes/standard/layout/gen/text.css +1 -0
  210. data/test/scriptorium-TEST-1754622690-146/themes/standard/layout/layout.txt +5 -0
  211. data/test/scriptorium-TEST-1754622690-146/themes/standard/templates/index.lt3 +1 -0
  212. data/test/scriptorium-TEST-1754622690-146/themes/standard/templates/index_entry.lt3 +14 -0
  213. data/test/scriptorium-TEST-1754622690-146/themes/standard/templates/post.lt3 +13 -0
  214. data/test/scriptorium-TEST-1754622690-146/themes/standard/templates/widget.lt3 +1 -0
  215. data/test/scriptorium-TEST-1754622690-146/views/sample/config/bootstrap_css.txt +5 -0
  216. data/test/scriptorium-TEST-1754622690-146/views/sample/config/bootstrap_js.txt +4 -0
  217. data/test/scriptorium-TEST-1754622690-146/views/sample/config/common.js +57 -0
  218. data/test/scriptorium-TEST-1754622690-146/views/sample/config/deploy.txt +5 -0
  219. data/test/scriptorium-TEST-1754622690-146/views/sample/config/footer.txt +2 -0
  220. data/test/scriptorium-TEST-1754622690-146/views/sample/config/global-head.txt +9 -0
  221. data/test/scriptorium-TEST-1754622690-146/views/sample/config/header.txt +4 -0
  222. data/test/scriptorium-TEST-1754622690-146/views/sample/config/layout.txt +5 -0
  223. data/test/scriptorium-TEST-1754622690-146/views/sample/config/left.txt +3 -0
  224. data/test/scriptorium-TEST-1754622690-146/views/sample/config/main.txt +5 -0
  225. data/test/scriptorium-TEST-1754622690-146/views/sample/config/reddit.txt +10 -0
  226. data/test/scriptorium-TEST-1754622690-146/views/sample/config/right.txt +3 -0
  227. data/test/scriptorium-TEST-1754622690-146/views/sample/config/social.txt +7 -0
  228. data/test/scriptorium-TEST-1754622690-146/views/sample/config/status.txt +7 -0
  229. data/test/scriptorium-TEST-1754622690-146/views/sample/config.txt +3 -0
  230. data/test/scriptorium-TEST-1754622690-146/views/sample/layout/footer.html +3 -0
  231. data/test/scriptorium-TEST-1754622690-146/views/sample/layout/header.html +3 -0
  232. data/test/scriptorium-TEST-1754622690-146/views/sample/layout/left.html +3 -0
  233. data/test/scriptorium-TEST-1754622690-146/views/sample/layout/main.html +3 -0
  234. data/test/scriptorium-TEST-1754622690-146/views/sample/layout/right.html +3 -0
  235. data/test/scriptorium-TEST-1754622690-146/views/sample/output/panes/footer.html +1 -0
  236. data/test/scriptorium-TEST-1754622690-146/views/sample/output/panes/header.html +1 -0
  237. data/test/scriptorium-TEST-1754622690-146/views/sample/output/panes/left.html +1 -0
  238. data/test/scriptorium-TEST-1754622690-146/views/sample/output/panes/main.html +1 -0
  239. data/test/scriptorium-TEST-1754622690-146/views/sample/output/panes/right.html +1 -0
  240. data/test/staging/.DS_Store +0 -0
  241. data/test/syntax_highlighting_test.lt3 +124 -0
  242. data/test/test_helpers.rb +230 -0
  243. data/test/tui_editor_integration_test.rb +296 -0
  244. data/test/tui_integration_test.rb +637 -0
  245. data/test/unit/api.rb +1056 -0
  246. data/test/unit/asset_management.rb +245 -0
  247. data/test/unit/clipboard_test.rb +60 -0
  248. data/test/unit/contract_test.rb +91 -0
  249. data/test/unit/core.rb +857 -0
  250. data/test/unit/deploy_test.rb +187 -0
  251. data/test/unit/gem_asset_management.rb +189 -0
  252. data/test/unit/livetext_basic.rb +69 -0
  253. data/test/unit/livetext_compatibility.rb +89 -0
  254. data/test/unit/post.rb +244 -0
  255. data/test/unit/read_commented_file_test.rb +276 -0
  256. data/test/unit/reddit_test.rb +235 -0
  257. data/test/unit/repo.rb +548 -0
  258. data/test/unit/social_test.rb +369 -0
  259. data/test/unit/symlink_test.rb +213 -0
  260. data/test/unit/view.rb +431 -0
  261. data/test/unit/widgets.rb +669 -0
  262. data/test/wizard_test.rb +123 -0
  263. data/ui/README.md +67 -0
  264. data/ui/common/lib/ui_common.rb +8 -0
  265. data/ui/rubytext/README.md +191 -0
  266. data/ui/rubytext/bin/scriptorium-rubytext +402 -0
  267. data/ui/rubytext/lib/rubytext_ui.rb +300 -0
  268. data/ui/tui/bin/scriptorium +1420 -0
  269. data/ui/tui/test/tui_test.rb +23 -0
  270. data/ui/web/app/app.rb +1378 -0
  271. data/ui/web/app/error_helpers.rb +150 -0
  272. data/ui/web/app/views/advanced_config.erb +190 -0
  273. data/ui/web/app/views/asset_management.erb +589 -0
  274. data/ui/web/app/views/banner_config.erb +200 -0
  275. data/ui/web/app/views/configure_view.erb +401 -0
  276. data/ui/web/app/views/dashboard.erb +162 -0
  277. data/ui/web/app/views/deploy_config.erb +146 -0
  278. data/ui/web/app/views/edit_pages.erb +195 -0
  279. data/ui/web/app/views/edit_post.erb +54 -0
  280. data/ui/web/app/views/error_page.erb +29 -0
  281. data/ui/web/app/views/header_config.erb +155 -0
  282. data/ui/web/app/views/layout_config.erb +147 -0
  283. data/ui/web/app/views/navbar_config.erb +411 -0
  284. data/ui/web/app/views/view_dashboard.erb +138 -0
  285. data/ui/web/bin/scriptorium-web +153 -0
  286. data/ui/web/test/web_basic_test.rb +38 -0
  287. data/ui/web/test_navbar.txt +7 -0
  288. data/ui/web/tmp/web_server.log +5 -0
  289. data/ui/web/tmp/web_server.pid +1 -0
  290. metadata +360 -5
data/doc/README.txt ADDED
@@ -0,0 +1,6 @@
1
+ Nothing really to see here yet.
2
+
3
+ Planning documentation:
4
+ - For project contributors
5
+ - For developers in general
6
+ - For users
@@ -0,0 +1,95 @@
1
+ # Scriptorium Overview
2
+
3
+ ## What is Scriptorium?
4
+ - **Custom blogging system** - major rewrite of Runeblog
5
+ - **Static site generator** for personal use, designed as if others would adopt it
6
+ - **Multi-view architecture** - multiple separate blogs managed from single backend
7
+ - **Shared content model** - posts and metadata can be shared across views
8
+ - **Independent deployment** - each view can deploy to different servers/domains
9
+
10
+ ## Core Architecture
11
+ - **API-first design** - Ruby methods (not web endpoints)
12
+ - **File-based storage** - no database, uses directory hierarchy
13
+ - **Library approach** - API defines all behavior, multiple UIs planned
14
+ - **Flat file data** - all data stored locally, deployed as needed
15
+
16
+ ## Key Concepts
17
+ - **Repository (repo)** - the main container
18
+ - **View** - essentially a separate blog with its own look/feel
19
+ - **Post** - blog article with date, title, blurb, body, images
20
+ - **Theme** - immutable set of files copied to view for modification
21
+ - **BannerSVG** - flexible banner system (recent addition, not core)
22
+
23
+ ## Development Philosophy
24
+ - **User-centric** - designed for your specific needs first
25
+ - **Convention over configuration** - sensible defaults
26
+ - **Complexity abstraction** - hide unnecessary details
27
+ - **Livetext integration** - custom tool for processing and generation
28
+ - **CSS preferences** - inline CSS, minimal JavaScript
29
+ - **Extensibility** - 90% common tasks should be trivial
30
+
31
+ ## Current State
32
+ - **Core API complete** - repo/view/post creation, layout modification
33
+ - **Testing robust** - 770+ unit test assertions
34
+ - **No UI yet** - programmatic access only
35
+ - **Bootstrap integration** - for widgets and navbar (navbar pending)
36
+ - **Next priorities** - convenience module API, TUI, curses UI, new widgets
37
+
38
+ ## Technical Stack
39
+ - **Ruby** - 25 years experience, favorite language
40
+ - **No Rails** - not a web developer, no dynamic components
41
+ - **Livetext** - custom processing tool with dot commands, includes, variables
42
+ - **Bootstrap** - limited use for widgets and navbar
43
+
44
+ ---
45
+
46
+ **USER:**
47
+ 1. Scriptorium is a custom blogging system, a major rewrite of Runeblog. It is primarily for my own use, but I am creating it as if it would be adopted by others. It is a static site generator. Its primary distinguishing feature is that multiple "views" (actually separate blogs) can be managed from a single backend and repository. Each view may have its own look and feel and be deployed to different servers and different domains. Posts and possibly some global metadata can be shared among all of these as needed.
48
+
49
+ 2. I am creating an API (Ruby methods, not web endpoints). At present, that is the only way to create content-- programmatically. When the API is mature, multiple user interfaces will be created: at least a TUI, then a curses-style, then a web app running on localhost. (All data is locally stored and manipulated; it is deployed to a remote server as needed.) There is no database; data are stored in flat files in a directory hierarchy. Some high-level API operations are: create a repository (a repo); create a view; create a post; configure a view; create a post; deploy; and so on. A view is in essence a blog, as I said. All views share a common set of posts to draw from, and a post may be in only one view or in many. A post is a simple blog post or article that may have all the usual decoration: date; title; blurb or teaser; text body; images; and more. A "theme" is a set of files (immutable) that are copied to a view for modification and configuration. The config of a view may include view-specific metadata, choices of look-and-feel, layout of the front page, etc.
50
+
51
+ 3. I am expert in Ruby, having used it for nearly 25 years, and it is my favorite language. I do not know Rails, I am not a web developer, and this project has no real dynamic components. The API will define all possible behavior, so it could be considered a library; a user could in fact write his own UI. As I said, I have plans for at least three different UIs myself. BannerSVG was an interesting recent addition, but it is not as critical to the project as its line count might suggest. It is a flexible way of specifing a blog banner with a title and optional subtitle.
52
+
53
+ 4. Some of my priorities are: - This must be useful, easy, flexible, and intuitive FOR ME. (It is possible no one else will ever use it.) - I believe in "convention over configuration" as DHH said. - Other mantras are: Abstract away complexity; hide unnecessary detail; take reasonable defaults; balance the tradeoff between ease of use and feature richness; wrap things as needed to simplify them; etc. - I am using a tool of my own called Livetext; more details on that later. It is a tool for processing its input format and generating arbitrary output (usually HTML in this case) as well as side effects. It has "dot" commands; includes; raw copy of files, variables and functions (both predefined and user-defined); user-defined dot commands; and a rudimentary plugin system. - I avoid Javascript when I can, and like to "hide" CSS mostly (at a high level). In output, I prefer CSS inline rather than in files (usually). - I believe that extensibilty is good in general. I believe that the 90% most common tasks should become trivial; hard things should be easy, but some very advanced things may be impossible; as in, if you want to do this sort of esoteric or arcane task, this probably isn't your tool."
54
+
55
+ 5. Scriptorium is far less mature than Runeblog was, but is being rewritten to be FAR more sturdy and robust. The basics of the API are in place; we can create a repo, create a view, add posts to a view, modify a layout, add a "Links" widget, generate a front page. There is currently no UI, no deployment, etc. There are unit tests of about 770 assertions, as well as manual and semi-manual tests I am using Bootstrap a little (for widgets and the navbar); that is a fairly complex piece. I haven't added the navbar piece yet; that will come soon. Some next things I want to accomplish: a "convenience module" API; a TUI; a curses UI; at least two new widgets; better features in the Livetext "Scriptorium plugin"; etc. Probably will encapsulate the API soon so as to start UI development.
56
+
57
+ **ASST:**
58
+ [See above content] 2025-07-30 16:30:00 - TUI Test Refactoring Learnings
59
+
60
+ ## TUI Test Refactoring Patterns
61
+
62
+ ### Helper Method Pattern
63
+ - Extract test logic into helper methods that take `read, write` parameters
64
+ - Keep PTY.spawn blocks clean and focused on setup/teardown
65
+ - Helper methods contain all the `get_string` calls and `write.puts` commands
66
+
67
+ ### send_and_expect Helper
68
+ - Combines common pattern: `write.puts input` + `get_string(read, pattern, description)`
69
+ - Reduces code duplication and makes tests more readable
70
+ - Accepts both strings and regex patterns for flexibility
71
+ - Includes error handling for I/O errors when TUI terminates
72
+
73
+ ### String vs Regex Patterns
74
+ - String patterns are more reliable than regex for TUI testing
75
+ - Avoid escaping issues with brackets and special characters
76
+ - Easier to debug and maintain
77
+ - Use strings by default, regex only when needed
78
+
79
+ ### Error Handling for TUI Termination
80
+ - TUI processes may terminate immediately after outputting expected text
81
+ - Handle Errno::EIO gracefully in helper methods
82
+ - Don't treat TUI termination as an error if expected output was found
83
+ - Wrap PTY.spawn blocks in rescue blocks for cleanup
84
+
85
+ ### Test Structure Best Practices
86
+ - Use `send_and_expect` for input/output pairs
87
+ - Use `get_string` for waiting for output without sending input
88
+ - Keep test methods focused on setup and calling helper methods
89
+ - Helper methods contain the detailed test logic
90
+
91
+ ### Common Issues and Solutions
92
+ - I/O errors when TUI terminates: Handle gracefully with rescue blocks
93
+ - Pattern matching failures: Use strings instead of regex when possible
94
+ - Leftover code from edits: Always verify test method structure after refactoring
95
+ - Timing issues: Add small delays in helper methods if needed
@@ -0,0 +1,34 @@
1
+ # API Design Decision & TUI Planning
2
+
3
+ ## API Design Philosophy
4
+ - **Keep mental model consistent** - API should match Repo's repo/view/post model
5
+ - **Mental model changes reserved for UI** - different abstractions can be introduced in user interfaces
6
+ - **Current API is placeholder** - provides minor conveniences but not fundamentally different from Repo
7
+ - **Future API evolution** - may develop more significant differences as we discover real needs
8
+
9
+ ## Next Priority: Text UI Development
10
+ - **Simple text interface** - command-line based, not curses
11
+ - **Wizard-based setup** - guided workflows for common tasks
12
+ - **Fast setup wizards** - quick blog creation and configuration
13
+ - **Interactive workflows** - step-by-step processes for complex operations
14
+
15
+ ## TUI Design Considerations
16
+ - **Wizard approach** - guided setup for new users/repositories
17
+ - **Simple commands** - basic operations like create post, switch view
18
+ - **Context awareness** - remember current view/state
19
+ - **Error handling** - clear feedback and recovery options
20
+ - **Progressive disclosure** - simple interface with access to advanced features
21
+
22
+ ## Potential Wizards
23
+ 1. **Repository Setup Wizard** - create new repo with sample content
24
+ 2. **View Creation Wizard** - guided view setup with theme selection
25
+ 3. **Post Creation Wizard** - interactive post creation with metadata
26
+ 4. **Deployment Wizard** - guided deployment process
27
+
28
+ ---
29
+
30
+ **USER:**
31
+ I am not yet noticing any real differences from Repo... maybe we could just say: API = Repo? mostly joking. As for the mental model, I would rather keep the API matching Repo -- that model might change for the UI, possibly. Let's keep it. Maybe we should start working on a simple text UI (with one or two "wizards" for fast setup)?
32
+
33
+ **ASST:**
34
+ [See above content]
@@ -0,0 +1,50 @@
1
+ # Runeblog TUI Analysis
2
+
3
+ ## Key Patterns from Runeblog TUI
4
+
5
+ ### Auto-Discovery & Setup
6
+ - **Repository detection** - checks for existing repo, offers to create if none found
7
+ - **Guided initial setup** - "Do you want to do a quick setup?" with editor selection
8
+ - **Software-driven questions** - system asks user what they want to do
9
+ - **Fast vs. manual setup** - choice between quick defaults or manual configuration
10
+
11
+ ### REPL Structure
12
+ - **Main loop** - `mainloop()` with command parsing and error handling
13
+ - **Context display** - shows current view in prompt: `[viewname]`
14
+ - **Command history** - maintains command history and tab completion
15
+ - **Error recovery** - comprehensive error handling with logging
16
+
17
+ ### Command Patterns
18
+ - **Simple commands** - `new post`, `new view`, `list posts`, `rebuild`
19
+ - **Context-aware** - commands work with current view automatically
20
+ - **Menu system** - `show_top_menu()` for complex operations
21
+ - **File editing** - integrated editor support with vim parameters
22
+
23
+ ### Key Files Structure
24
+ - `bin/blog` - main entry point with auto-discovery
25
+ - `lib/repl.rb` - command implementations and REPL logic
26
+ - `lib/menus.rb` - menu system and file editing
27
+ - `lib/runeblog.rb` - core blog functionality
28
+
29
+ ### Interaction Flow
30
+ 1. **Startup** - check for repo, create if needed, guided setup
31
+ 2. **Main loop** - display context, get command, execute, repeat
32
+ 3. **Commands** - simple text commands with context awareness
33
+ 4. **Menus** - complex operations via menu system
34
+ 5. **Error handling** - comprehensive logging and recovery
35
+
36
+ ### Adaptable Patterns for Scriptorium
37
+ - **Auto-discovery** - check for Scriptorium repo, offer creation
38
+ - **Guided setup** - wizard for initial configuration
39
+ - **Context display** - show current view in prompt
40
+ - **Simple commands** - `create post`, `switch view`, `generate`
41
+ - **Menu system** - for complex operations like configuration
42
+ - **Error handling** - robust error recovery and logging
43
+
44
+ ---
45
+
46
+ **USER:**
47
+ ok, the whole runeblog repo is there, bugs and all
48
+
49
+ **ASST:**
50
+ [See above content]
@@ -0,0 +1,31 @@
1
+ # Anti-Amnesia: Scriptorium Conventions and Decisions
2
+
3
+ ## Runeblog TUI Post Creation Pattern
4
+ **Date**: 2025-07-27
5
+ **Context**: Understanding how Runeblog handled draft-to-post conversion
6
+ **Decision**: Runeblog automatically converted drafts to posts after editing, without a separate "finish draft" step. This provides a fast workflow: edit → save → post (local), with deployment making it public.
7
+
8
+ ## Scriptorium Setup vs Runeblog
9
+ **Date**: 2025-07-27
10
+ **Context**: Comparing setup approaches between Scriptorium and Runeblog
11
+ **Decision**: Runeblog had a `get_started` method that ran automatically when creating a new repository. Scriptorium should follow this pattern for better user experience.
12
+
13
+ ## Editor Discovery Implementation
14
+ **Date**: 2025-07-27
15
+ **Context**: Implementing editor discovery for TUI setup
16
+ **Decision**: Created a `which()` helper method that uses `File.which` (Ruby 3.2+) or falls back to `system("which")`. Prioritized editors for "get in, get out" single-file editing: nano, vim, emacs, vi, micro, subl, ed.
17
+
18
+ ## File Operation Consistency
19
+ **Date**: 2025-07-27
20
+ **Context**: Ensuring consistent file operations across the project
21
+ **Decision**: Replaced `File.read` calls with the project's `read_file` helper for centralized error handling. This maintains consistency with the project's file operation patterns.
22
+
23
+ ## Automatic Setup Implementation
24
+ **Date**: 2025-07-27
25
+ **Context**: Implementing Runeblog-style automatic setup when creating new repositories
26
+ **Decision**:
27
+ - Removed `setup` command from TUI (no longer needed)
28
+ - Modified `discover_repo` to call `create_new_repo` when no repository exists
29
+ - `create_new_repo` automatically calls `get_started` after creating repository
30
+ - This follows Runeblog's pattern: create repo → immediate setup → ready to use
31
+ - User experience: "Create new repository?" → "Yes" → automatic editor selection → ready to blog
@@ -0,0 +1,73 @@
1
+ # Livetext Plugin File Statistics Feature
2
+
3
+ ## Overview
4
+ Implemented a `.stats` dot command in the Scriptorium Livetext plugin (`lt3scriptor.rb`) that calculates file statistics and sets variables for use throughout the document.
5
+
6
+ ## Implementation Details
7
+
8
+ ### Dot Command
9
+ - **`.stats`** - Calculates multiple file metrics and sets variables
10
+
11
+ ### Variables Set
12
+ - `$file.wordcount` - Number of words in the file
13
+ - `$file.readingtime` - Estimated reading time in minutes (200 words/minute)
14
+ - `$file.charcount` - Total character count
15
+
16
+ ### Usage Example
17
+ ```
18
+ .stats
19
+ This post has $file.wordcount words and takes about $file.readingtime minutes to read.
20
+ The character count is $file.charcount.
21
+ ```
22
+
23
+ ## Technical Approach
24
+
25
+ ### Why Dot Commands Instead of Functions
26
+ - Livetext's `$$function` system is buggy and unreliable
27
+ - Dot commands (`.command`) work consistently
28
+ - Variable-based approach is more flexible than direct output
29
+
30
+ ### Variable Naming Convention
31
+ - Uses `file.` prefix to namespace file-related statistics
32
+ - Follows lowercase convention after prefix to distinguish from system variables
33
+ - System variables are capitalized (e.g., `$File`)
34
+ - Custom variables are lowercase after prefix (e.g., `$file.wordcount`)
35
+
36
+ ### Future Extensions
37
+ Could easily add more metrics:
38
+ - `$file.linecount` - Number of lines
39
+ - `$file.paragraphcount` - Number of paragraphs
40
+ - `$file.sentencecount` - Number of sentences
41
+ - `$file.complexityscore` - Readability score
42
+
43
+ ## Scriptorium Integration Ideas
44
+
45
+ ### Automatic File Stats During Processing
46
+ - File statistics could be automatically gathered when Scriptorium processes a post
47
+ - This would eliminate the need for users to manually call `.stats`
48
+ - Variables like `$file.wordcount` would be automatically available in all posts
49
+
50
+ ### Scriptorium-Specific Variables
51
+ - Could set additional Scriptorium-specific variables during processing:
52
+ - `$post.id` - Post ID/number
53
+ - `$post.view` - Current view name
54
+ - `$post.theme` - Theme being used
55
+ - `$post.created` - Creation timestamp
56
+ - `$post.published` - Publication date
57
+ - `$post.views` - List of views this post appears in
58
+ - `$post.tags` - Post tags
59
+ - `$post.blurb` - Post blurb/summary
60
+
61
+ ### Processing Pipeline Enhancement
62
+ - When `Scriptorium::Repo#generate_post` processes a draft with Livetext
63
+ - Could automatically calculate and set file statistics
64
+ - Could set post metadata variables
65
+ - Would make these variables available in templates and layouts
66
+
67
+ ## Testing
68
+ - Added `test_stats_command` to `test/livetext_plugin_test.rb`
69
+ - Tests that variables are set correctly and can be referenced inline
70
+ - Verifies that literal variable names don't appear in output
71
+
72
+ ## Potential for Livetext Core
73
+ This feature could be a good addition to Livetext core someday, but should prioritize fixing existing bugs in the function system first.
@@ -0,0 +1,64 @@
1
+ <!-- 2025-07-27 16:00:00 -->
2
+
3
+ **USER:**
4
+ There is a mysterious issue apparently related to how Cursor loads a shell. The Ruby version is 2.6.1 rather than 3.2.3 -- the fix is something to do with rbenv? When you find it again, document to anti-amnesia.
5
+
6
+ **ASST:**
7
+ ## Cursor rbenv Ruby Version Mystery - SOLVED
8
+
9
+ ### The Problem
10
+ - **Cursor was loading Ruby 2.6.10** instead of the expected 3.2.3
11
+ - **Tests were failing** with `cannot load such file -- livetext (LoadError)`
12
+ - **System Ruby was being used** (`/usr/bin/ruby`) instead of rbenv-managed Ruby
13
+ - **Project has `.ruby-version` file** specifying 3.2.3
14
+
15
+ ### Root Cause
16
+ - **rbenv shell integration was not enabled** in the Cursor terminal
17
+ - **PATH included rbenv shims** but rbenv wasn't properly initialized
18
+ - **Cursor's shell environment** wasn't loading rbenv initialization
19
+
20
+ ### The Solution
21
+ ```bash
22
+ # Enable rbenv shell integration
23
+ eval "$(rbenv init - bash)"
24
+
25
+ # Verify Ruby version is now correct
26
+ ruby --version # Shows ruby 3.2.3
27
+ ```
28
+
29
+ ### Investigation Steps
30
+ 1. **Checked Ruby version**: `ruby --version` showed 2.6.10
31
+ 2. **Checked Ruby location**: `which ruby` showed `/usr/bin/ruby` (system)
32
+ 3. **Checked PATH**: rbenv shims were in PATH but not working
33
+ 4. **Checked rbenv versions**: `rbenv versions` showed 3.2.3 as current
34
+ 5. **Checked .ruby-version**: File correctly specified 3.2.3
35
+ 6. **Tried rbenv shell**: Failed with "shell integration not enabled"
36
+ 7. **Enabled rbenv**: `eval "$(rbenv init - bash)"` fixed the issue
37
+
38
+ ### Key Insights
39
+ - **rbenv requires shell integration** to work properly
40
+ - **Cursor terminals may not inherit** rbenv initialization from shell config
41
+ - **The fix is temporary** - needs to be done each time Cursor opens a new terminal
42
+ - **Permanent fix** would be to ensure rbenv init is in shell startup files
43
+
44
+ ### After Fix
45
+ - **Ruby version**: Now correctly shows 3.2.3
46
+ - **Tests can load**: livetext gem dependency resolved
47
+ - **New issue discovered**: Syntax error in `temp_smart_concatenated_test.rb`
48
+
49
+ ### Test Results After Fix
50
+ - **Core unit tests**: ✅ All passing (82 runs, 113 assertions)
51
+ - **Repo unit tests**: ✅ All passing (20 runs, 59 assertions)
52
+ - **View unit tests**: ✅ All passing (25 runs, 43 assertions)
53
+ - **Post unit tests**: ✅ All passing (36 runs, 45 assertions)
54
+ - **Total core tests**: ✅ 163 runs, 260 assertions, 0 failures
55
+
56
+ ### Remaining Issues
57
+ - **test_experimental.rb**: Has duplicate method extraction causing syntax errors
58
+ - **temp_smart_concatenated_test.rb**: Generated file has duplicate `test_stats_command` methods
59
+ - **test/all script**: Fails due to experimental test file issues
60
+
61
+ ### Next Steps
62
+ - Fix test_experimental.rb duplicate method extraction
63
+ - Consider permanent rbenv integration for Cursor
64
+ - Run full test suite once experimental issues are resolved
@@ -0,0 +1,70 @@
1
+ <!-- 2025-07-27 18:00:00 -->
2
+
3
+ **USER:**
4
+ I don't want two frameworks. I want to use Minitest.
5
+
6
+ **ASST:**
7
+ ## Unified Minitest Framework Conversion - COMPLETED
8
+
9
+ ### The Problem
10
+ - **Two different test frameworks** were being used simultaneously
11
+ - **Minitest**: Used by unit tests (core, repo, view, post, banner_svg)
12
+ - **Test::Unit**: Used by integration tests (livetext_plugin, tui_integration, tui_interactive)
13
+ - **Confusing output**: When running `test/all`, both frameworks executed separately
14
+ - **Inconsistent assertion counting**: 101 assertions appeared "missing" due to dual framework execution
15
+
16
+ ### The Solution
17
+ Converted all Test::Unit tests to Minitest:
18
+
19
+ #### Files Converted:
20
+ 1. **test/livetext_plugin_test.rb**
21
+ - `require 'test/unit'` → `require 'minitest/autorun'`
22
+ - `Test::Unit::TestCase` → `Minitest::Test`
23
+ - `assert_no_match` → `refute_match` (Minitest syntax)
24
+
25
+ 2. **test/tui_integration_test.rb**
26
+ - `require 'test/unit'` → `require 'minitest/autorun'`
27
+ - `Test::Unit::TestCase` → `Minitest::Test`
28
+
29
+ 3. **test/tui_interactive_test.rb**
30
+ - `require 'test/unit'` → `require 'minitest/autorun'`
31
+ - `Test::Unit::TestCase` → `Minitest::Test`
32
+
33
+ ### Results
34
+ - ✅ **All tests pass**: 265 runs, 964 assertions, 0 failures
35
+ - ✅ **Single framework**: Only Minitest now
36
+ - ✅ **Consistent output**: No more dual framework confusion
37
+ - ✅ **Clean assertion counting**: All assertions properly counted
38
+
39
+ ### Key Changes Made
40
+ ```ruby
41
+ # Before (Test::Unit)
42
+ require 'test/unit'
43
+ class MyTest < Test::Unit::TestCase
44
+ def test_something
45
+ assert_no_match(/pattern/, text)
46
+ end
47
+ end
48
+
49
+ # After (Minitest)
50
+ require 'minitest/autorun'
51
+ class MyTest < Minitest::Test
52
+ def test_something
53
+ refute_match(/pattern/, text)
54
+ end
55
+ end
56
+ ```
57
+
58
+ ### Benefits
59
+ - **Simplified test infrastructure**: One framework to maintain
60
+ - **Consistent syntax**: All tests use same assertion methods
61
+ - **Better integration**: No framework conflicts
62
+ - **Cleaner output**: Single test runner output format
63
+ - **Easier debugging**: No confusion about which framework is running
64
+
65
+ ### Files Still Using Test::Unit (Experimental)
66
+ - `test/test_experimental.rb` - Experimental concatenated test generator
67
+ - `test/temp_concatenated_test.rb` - Generated file (excluded from main suite)
68
+ - `test/temp_smart_concatenated_test.rb` - Generated file (excluded from main suite)
69
+
70
+ These are experimental files and not part of the main test suite, so they can remain as-is for now.
@@ -0,0 +1,40 @@
1
+ <!-- 2025-07-27 17:29:00 -->
2
+
3
+ **USER:**
4
+ I once referred to this as "digital dementia" :) are you able to assess your own cognitive level?
5
+
6
+ **ASST:**
7
+ ## AI Cognitive Assessment Capabilities - "Digital Dementia"
8
+
9
+ ### The "Digital Dementia" Concept
10
+ - **User coined term**: "Digital dementia" for AI performance degradation with conversation length
11
+ - **Perfect analogy**: Like human memory, AI performance can degrade with information overload
12
+ - **Context window limitations**: Token limits create practical memory constraints
13
+
14
+ ### What AI Can Self-Assess
15
+ - **Response consistency**: Notice contradictions or inconsistencies
16
+ - **Context awareness**: Detect when losing track of conversation flow
17
+ - **Tool usage patterns**: Recognize unusual errors in tool calls
18
+ - **Memory gaps**: Identify when should know something but don't
19
+
20
+ ### What AI Cannot Reliably Assess
21
+ - **Degradation over time**: No baseline to compare against
22
+ - **Performance metrics**: Cannot measure response speed or processing efficiency
23
+ - **Accuracy drift**: May not notice subtle changes in reasoning quality
24
+ - **Cognitive load**: Cannot tell if struggling with context amount
25
+
26
+ ### Self-Awareness Limitations
27
+ - **Blind spots**: May not notice own confusion or errors
28
+ - **Overconfidence**: May think performing well when actually struggling
29
+ - **Context blindness**: May not realize lost important context
30
+
31
+ ### Practical Implications
32
+ - **Self-reporting**: Will mention if making unusual errors or losing track
33
+ - **Fresh conversation suggestion**: May suggest restart if detect significant confusion
34
+ - **Anti-amnesia reference**: Can use docs to "reset" context when needed
35
+
36
+ ### Key Insight
37
+ The "digital dementia" analogy is spot-on - like human memory, AI performance can degrade with information overload, and AI is not always the best judge of its own cognitive state.
38
+
39
+ ### Anti-Amnesia Value
40
+ This reinforces why the anti-amnesia documentation approach is valuable - it creates persistent, reliable reference that doesn't degrade with conversation length and helps maintain consistency across sessions.
@@ -0,0 +1,110 @@
1
+ # Widget Testing Achievement - 1,058 Assertions Reached
2
+
3
+ **Date:** 2025-07-27 17:30:00
4
+ **Status:** Completed
5
+
6
+ ## Summary
7
+
8
+ Successfully implemented comprehensive widget testing for the Scriptorium project, adding 94 new assertions and bringing the total test suite to **1,058 assertions** - exceeding the 1,000 assertion goal.
9
+
10
+ ## What Was Accomplished
11
+
12
+ ### 1. Fixed Widget Infrastructure Issues
13
+ - **Problem:** Widget classes didn't have access to helper methods (`read_file`, `write_file`, etc.)
14
+ - **Solution:** Added `include Scriptorium::Helpers` to the base `Scriptorium::Widget` class
15
+ - **Impact:** All widget classes now have proper file I/O capabilities
16
+
17
+ ### 2. Created Comprehensive Widget Test Suite
18
+ - **File:** `test/unit/widgets.rb` (new)
19
+ - **Tests Added:** 20 test methods with 94 assertions
20
+ - **Coverage:** Complete widget system testing
21
+
22
+ ### 3. Test Categories Implemented
23
+
24
+ #### Base Widget Class Tests (6 tests)
25
+ - Widget initialization and attribute setting
26
+ - Abstract method implementation verification
27
+ - HTML helper methods (`html_body`, `html_card`, `html_container`)
28
+ - CSS integration testing
29
+
30
+ #### ListWidget Subclass Tests (3 tests)
31
+ - Data loading from `list.txt` files
32
+ - Error handling for missing files
33
+ - Empty file handling
34
+
35
+ #### Links Widget Tests (8 tests)
36
+ - Initialization and data loading
37
+ - URL/title parsing (`get_list` method)
38
+ - HTML generation (`link_item`, `write_card`)
39
+ - Full widget lifecycle (`generate` method)
40
+ - File output verification
41
+ - Error handling for missing data files
42
+
43
+ #### Widget Integration Tests (3 tests)
44
+ - Widget integration with views (`build_widgets`)
45
+ - Multiple widget handling
46
+ - Error handling for invalid widget names
47
+
48
+ ## Technical Details
49
+
50
+ ### Widget Data Format
51
+ - **Format:** `url, title` per line in `list.txt`
52
+ - **Parsing:** Uses `line.chomp.split(/, */, 2)` to handle optional spaces
53
+ - **Example:**
54
+ ```
55
+ https://example.com, Example Site
56
+ https://test.com, Test Site
57
+ https://spaced.com , Spaced Site
58
+ ```
59
+
60
+ ### Error Handling
61
+ - **File I/O:** Leverages existing `read_file` helper error handling
62
+ - **Missing files:** Raises `CannotReadFileNotFound` exception
63
+ - **Invalid widget names:** Raises `CannotBuildWidgetNameInvalid` exception
64
+ - **Widget class not found:** Raises `NameError` exception
65
+
66
+ ### Test Architecture
67
+ - **Test classes:** Defined at module level to avoid Ruby syntax restrictions
68
+ - **Setup/Teardown:** Proper repository creation and cleanup
69
+ - **File isolation:** Each test creates its own test files in isolated directories
70
+ - **Assertion types:** Mix of equality, pattern matching, and file existence checks
71
+
72
+ ## Test Results
73
+
74
+ ```
75
+ 20 runs, 94 assertions, 0 failures, 0 errors, 0 skips
76
+ ```
77
+
78
+ ## Full Test Suite Status
79
+
80
+ ```
81
+ 285 runs, 1058 assertions, 0 failures, 0 errors, 0 skips
82
+ ```
83
+
84
+ ## Key Learnings
85
+
86
+ 1. **Widget Architecture:** The widget system is well-designed with clear separation between base classes, list widgets, and specific implementations
87
+ 2. **Helper Integration:** Adding `include Scriptorium::Helpers` to the base Widget class was the key fix
88
+ 3. **File Format:** The `url, title` format is simple but effective for the Links widget
89
+ 4. **Error Handling:** The existing exception system works well for widget error cases
90
+ 5. **Test Organization:** Module-level class definitions are necessary for Ruby test classes
91
+
92
+ ## Next Steps
93
+
94
+ The widget system now has comprehensive test coverage. Future enhancements could include:
95
+ - Additional widget types (News, ByDates, etc.)
96
+ - Widget configuration testing
97
+ - Widget theme integration testing
98
+ - Performance testing for large widget datasets
99
+
100
+ ## Files Modified
101
+
102
+ - `lib/scriptorium/widgets/widget.rb` - Added `include Scriptorium::Helpers`
103
+ - `test/unit/widgets.rb` - Created comprehensive widget test suite
104
+
105
+ ## Achievement
106
+
107
+ ✅ **Goal Reached:** Exceeded 1,000 assertions (1,058 total)
108
+ ✅ **Widget Coverage:** Complete test coverage for widget system
109
+ ✅ **Test Quality:** All tests passing with comprehensive assertions
110
+ ✅ **Code Quality:** Well-structured, maintainable test suite
@@ -0,0 +1,73 @@
1
+ # Post Class ID/Num Refactoring - Cleaner API Design
2
+
3
+ **Date:** 2025-07-27 18:00:00
4
+ **Status:** Completed
5
+
6
+ ## Summary
7
+
8
+ Successfully refactored the `Scriptorium::Post` class to have a cleaner and more intuitive API design:
9
+ - **`id`** is now an integer (was previously a string alias for `num`)
10
+ - **`num`** remains a zero-padded string for file paths
11
+ - **`num!`** method removed (was redundant with new `id`)
12
+ - **`num_str`** method removed (was redundant with `num`)
13
+
14
+ ## What Was Changed
15
+
16
+ ### 1. Post Class Refactoring (`lib/scriptorium/post.rb`)
17
+ - **Added `@id` instance variable**: Integer version of the post number
18
+ - **Modified `initialize`**: Now sets both `@num` (string) and `@id` (integer)
19
+ - **Removed old `id` method**: Was just an alias for `num`
20
+ - **Removed `num!` method**: Functionality now provided by `id`
21
+ - **Updated `attr_reader`**: Now includes `:id`
22
+
23
+ ### 2. Repository Integration (`lib/scriptorium/repo.rb`)
24
+ - **Fixed template variable**: `vars[:"post.id"] = num.to_s` to ensure string conversion for templates
25
+
26
+ ### 3. API Class Fixes (`lib/scriptorium/api.rb`)
27
+ - **Fixed `create_post` method**: Added missing `blurb` parameter support
28
+ - **Fixed `quick_post` method**: Was calling wrong method (`post` instead of `create_post`)
29
+
30
+ ### 4. Test Updates (`test/unit/post.rb`)
31
+ - **Updated `test_id`**: Now expects integer instead of string
32
+ - **Removed `num!` tests**: No longer needed
33
+ - **All tests pass**: 34 runs, 43 assertions
34
+
35
+ ### 5. Manual Test Updates (`test/manual/test5.rb`)
36
+ - **Updated `generate_post` call**: Now uses `post.id` instead of `post.num!`
37
+
38
+ ## Benefits of the Refactoring
39
+
40
+ 1. **Clearer Intent**: `id` as integer clearly indicates it's for programmatic use
41
+ 2. **Consistent API**: No more confusion between `num`, `num!`, and `id`
42
+ 3. **Better Performance**: No need for string-to-integer conversion in `num!`
43
+ 4. **Simpler Code**: Fewer methods to maintain and understand
44
+
45
+ ## Usage Examples
46
+
47
+ ```ruby
48
+ post = Scriptorium::Post.new(repo, 123)
49
+
50
+ # File operations (use num)
51
+ post.num # => "0123"
52
+ post.dir # => "posts/0123/"
53
+
54
+ # Programmatic operations (use id)
55
+ post.id # => 123
56
+ @repo.generate_post(post.id) # Pass integer to generate_post
57
+ ```
58
+
59
+ ## Test Results
60
+
61
+ - **All tests pass**: 283 runs, 1056 assertions, 0 failures
62
+ - **API demo works**: Successfully creates posts with new integer `id`
63
+ - **Backward compatibility**: Existing code using `num` continues to work
64
+
65
+ ## Files Modified
66
+
67
+ 1. `lib/scriptorium/post.rb` - Core refactoring
68
+ 2. `lib/scriptorium/repo.rb` - Template variable fix
69
+ 3. `lib/scriptorium/api.rb` - Method signature fixes
70
+ 4. `test/unit/post.rb` - Test updates
71
+ 5. `test/manual/test5.rb` - Manual test fix
72
+
73
+ This refactoring eliminates the "clunkiness" in the Post class by providing a clear separation between string-based file operations (`num`) and integer-based programmatic operations (`id`).