ratatui_ruby 0.4.0 → 0.6.0

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 (441) hide show
  1. checksums.yaml +4 -4
  2. data/.builds/ruby-3.2.yml +1 -1
  3. data/.builds/ruby-3.3.yml +1 -1
  4. data/.builds/ruby-3.4.yml +1 -1
  5. data/.builds/ruby-4.0.0.yml +1 -1
  6. data/AGENTS.md +98 -176
  7. data/CHANGELOG.md +80 -6
  8. data/README.md +19 -7
  9. data/REUSE.toml +15 -0
  10. data/doc/application_architecture.md +179 -45
  11. data/doc/application_testing.md +80 -32
  12. data/doc/contributors/design/ruby_frontend.md +48 -8
  13. data/doc/contributors/design/rust_backend.md +1 -0
  14. data/doc/contributors/developing_examples.md +191 -48
  15. data/doc/contributors/documentation_style.md +7 -0
  16. data/doc/contributors/examples_audit/p1_high.md +21 -0
  17. data/doc/contributors/examples_audit/p2_moderate.md +81 -0
  18. data/doc/contributors/examples_audit.md +41 -0
  19. data/doc/contributors/index.md +2 -0
  20. data/doc/event_handling.md +21 -7
  21. data/doc/images/app_all_events.png +0 -0
  22. data/doc/images/app_color_picker.png +0 -0
  23. data/doc/images/app_login_form.png +0 -0
  24. data/doc/images/app_stateful_interaction.png +0 -0
  25. data/doc/images/verify_quickstart_dsl.png +0 -0
  26. data/doc/images/verify_quickstart_layout.png +0 -0
  27. data/doc/images/verify_quickstart_lifecycle.png +0 -0
  28. data/doc/images/verify_readme_usage.png +0 -0
  29. data/doc/images/widget_barchart_demo.png +0 -0
  30. data/doc/images/widget_block_demo.png +0 -0
  31. data/doc/images/widget_box_demo.png +0 -0
  32. data/doc/images/widget_calendar_demo.png +0 -0
  33. data/doc/images/widget_canvas_demo.png +0 -0
  34. data/doc/images/widget_cell_demo.png +0 -0
  35. data/doc/images/widget_center_demo.png +0 -0
  36. data/doc/images/widget_chart_demo.png +0 -0
  37. data/doc/images/widget_gauge_demo.png +0 -0
  38. data/doc/images/widget_layout_split.png +0 -0
  39. data/doc/images/widget_line_gauge_demo.png +0 -0
  40. data/doc/images/widget_list_demo.png +0 -0
  41. data/doc/images/widget_overlay_demo.png +0 -0
  42. data/doc/images/widget_ratatui_logo_demo.png +0 -0
  43. data/doc/images/widget_ratatui_mascot_demo.png +0 -0
  44. data/doc/images/widget_render.png +0 -0
  45. data/doc/images/widget_rich_text.png +0 -0
  46. data/doc/images/widget_scroll_text.png +0 -0
  47. data/doc/images/widget_scrollbar_demo.png +0 -0
  48. data/doc/images/widget_sparkline_demo.png +0 -0
  49. data/doc/images/widget_style_colors.png +0 -0
  50. data/doc/images/widget_table_demo.png +0 -0
  51. data/doc/images/widget_table_flex.png +0 -0
  52. data/doc/images/widget_tabs_demo.png +0 -0
  53. data/doc/images/widget_text_width.png +0 -0
  54. data/doc/interactive_design.md +25 -30
  55. data/doc/quickstart.md +150 -130
  56. data/doc/terminal_limitations.md +92 -0
  57. data/examples/app_all_events/README.md +99 -0
  58. data/examples/app_all_events/app.rb +96 -0
  59. data/examples/app_all_events/model/app_model.rb +157 -0
  60. data/examples/app_all_events/model/event_color_cycle.rb +41 -0
  61. data/examples/app_all_events/model/event_entry.rb +92 -0
  62. data/examples/app_all_events/model/msg.rb +37 -0
  63. data/examples/app_all_events/model/timestamp.rb +54 -0
  64. data/examples/app_all_events/update.rb +73 -0
  65. data/examples/app_all_events/view/app_view.rb +78 -0
  66. data/examples/app_all_events/view/controls_view.rb +52 -0
  67. data/examples/app_all_events/view/counts_view.rb +59 -0
  68. data/examples/app_all_events/view/live_view.rb +70 -0
  69. data/examples/app_all_events/view/log_view.rb +55 -0
  70. data/examples/app_all_events/view.rb +7 -0
  71. data/examples/app_color_picker/README.md +134 -0
  72. data/examples/app_color_picker/app.rb +74 -0
  73. data/examples/app_color_picker/clipboard.rb +84 -0
  74. data/examples/app_color_picker/color.rb +191 -0
  75. data/examples/app_color_picker/controls.rb +90 -0
  76. data/examples/app_color_picker/copy_dialog.rb +166 -0
  77. data/examples/app_color_picker/export_pane.rb +126 -0
  78. data/examples/app_color_picker/harmony.rb +56 -0
  79. data/examples/app_color_picker/input.rb +174 -0
  80. data/examples/app_color_picker/main_container.rb +178 -0
  81. data/examples/app_color_picker/palette.rb +109 -0
  82. data/examples/app_login_form/README.md +47 -0
  83. data/examples/{login_form → app_login_form}/app.rb +38 -42
  84. data/examples/app_stateful_interaction/README.md +31 -0
  85. data/examples/app_stateful_interaction/app.rb +272 -0
  86. data/examples/timeout_demo.rb +43 -0
  87. data/examples/verify_quickstart_dsl/README.md +48 -0
  88. data/examples/{quickstart_dsl → verify_quickstart_dsl}/app.rb +17 -6
  89. data/examples/verify_quickstart_layout/README.md +71 -0
  90. data/examples/verify_quickstart_layout/app.rb +71 -0
  91. data/examples/verify_quickstart_lifecycle/README.md +56 -0
  92. data/examples/verify_quickstart_lifecycle/app.rb +54 -0
  93. data/examples/verify_readme_usage/README.md +43 -0
  94. data/examples/verify_readme_usage/app.rb +40 -0
  95. data/examples/widget_barchart_demo/README.md +49 -0
  96. data/examples/widget_barchart_demo/app.rb +238 -0
  97. data/examples/widget_block_demo/README.md +34 -0
  98. data/examples/widget_block_demo/app.rb +256 -0
  99. data/examples/widget_box_demo/README.md +45 -0
  100. data/examples/{box_demo → widget_box_demo}/app.rb +99 -65
  101. data/examples/widget_calendar_demo/README.md +39 -0
  102. data/examples/widget_calendar_demo/app.rb +109 -0
  103. data/examples/widget_canvas_demo/README.md +27 -0
  104. data/examples/widget_canvas_demo/app.rb +123 -0
  105. data/examples/widget_cell_demo/README.md +36 -0
  106. data/examples/widget_cell_demo/app.rb +111 -0
  107. data/examples/widget_center_demo/README.md +29 -0
  108. data/examples/widget_center_demo/app.rb +116 -0
  109. data/examples/widget_chart_demo/README.md +41 -0
  110. data/examples/widget_chart_demo/app.rb +218 -0
  111. data/examples/widget_gauge_demo/README.md +41 -0
  112. data/examples/widget_gauge_demo/app.rb +212 -0
  113. data/examples/widget_layout_split/README.md +44 -0
  114. data/examples/widget_layout_split/app.rb +246 -0
  115. data/examples/widget_line_gauge_demo/README.md +41 -0
  116. data/examples/widget_line_gauge_demo/app.rb +217 -0
  117. data/examples/widget_list_demo/README.md +49 -0
  118. data/examples/widget_list_demo/app.rb +366 -0
  119. data/examples/widget_map_demo/README.md +39 -0
  120. data/examples/{map_demo → widget_map_demo}/app.rb +24 -21
  121. data/examples/widget_overlay_demo/app.rb +248 -0
  122. data/examples/widget_popup_demo/README.md +36 -0
  123. data/examples/widget_popup_demo/app.rb +104 -0
  124. data/examples/widget_ratatui_logo_demo/README.md +34 -0
  125. data/examples/widget_ratatui_logo_demo/app.rb +103 -0
  126. data/examples/widget_ratatui_mascot_demo/README.md +34 -0
  127. data/examples/widget_ratatui_mascot_demo/app.rb +93 -0
  128. data/examples/widget_rect/README.md +38 -0
  129. data/examples/widget_rect/app.rb +205 -0
  130. data/examples/widget_render/README.md +37 -0
  131. data/examples/widget_render/app.rb +184 -0
  132. data/examples/widget_rich_text/README.md +35 -0
  133. data/examples/widget_rich_text/app.rb +166 -0
  134. data/examples/widget_scroll_text/README.md +37 -0
  135. data/examples/widget_scroll_text/app.rb +107 -0
  136. data/examples/widget_scrollbar_demo/README.md +37 -0
  137. data/examples/widget_scrollbar_demo/app.rb +153 -0
  138. data/examples/widget_sparkline_demo/README.md +42 -0
  139. data/examples/widget_sparkline_demo/app.rb +275 -0
  140. data/examples/widget_style_colors/README.md +34 -0
  141. data/examples/widget_style_colors/app.rb +19 -21
  142. data/examples/widget_table_demo/README.md +48 -0
  143. data/examples/widget_table_demo/app.rb +239 -0
  144. data/examples/widget_tabs_demo/README.md +41 -0
  145. data/examples/widget_tabs_demo/app.rb +181 -0
  146. data/examples/widget_text_width/README.md +35 -0
  147. data/examples/widget_text_width/app.rb +106 -0
  148. data/ext/ratatui_ruby/Cargo.lock +11 -4
  149. data/ext/ratatui_ruby/Cargo.toml +2 -1
  150. data/ext/ratatui_ruby/src/events.rs +359 -62
  151. data/ext/ratatui_ruby/src/frame.rs +227 -0
  152. data/ext/ratatui_ruby/src/lib.rs +110 -27
  153. data/ext/ratatui_ruby/src/rendering.rs +8 -4
  154. data/ext/ratatui_ruby/src/string_width.rs +101 -0
  155. data/ext/ratatui_ruby/src/style.rs +138 -57
  156. data/ext/ratatui_ruby/src/terminal.rs +42 -22
  157. data/ext/ratatui_ruby/src/text.rs +14 -7
  158. data/ext/ratatui_ruby/src/widgets/barchart.rs +74 -54
  159. data/ext/ratatui_ruby/src/widgets/block.rs +7 -6
  160. data/ext/ratatui_ruby/src/widgets/canvas.rs +21 -3
  161. data/ext/ratatui_ruby/src/widgets/chart.rs +20 -10
  162. data/ext/ratatui_ruby/src/widgets/gauge.rs +9 -2
  163. data/ext/ratatui_ruby/src/widgets/layout.rs +9 -4
  164. data/ext/ratatui_ruby/src/widgets/line_gauge.rs +9 -2
  165. data/ext/ratatui_ruby/src/widgets/list.rs +211 -12
  166. data/ext/ratatui_ruby/src/widgets/list_state.rs +137 -0
  167. data/ext/ratatui_ruby/src/widgets/mod.rs +3 -0
  168. data/ext/ratatui_ruby/src/widgets/overlay.rs +2 -1
  169. data/ext/ratatui_ruby/src/widgets/paragraph.rs +1 -1
  170. data/ext/ratatui_ruby/src/widgets/ratatui_logo.rs +19 -8
  171. data/ext/ratatui_ruby/src/widgets/ratatui_mascot.rs +17 -10
  172. data/ext/ratatui_ruby/src/widgets/scrollbar.rs +97 -3
  173. data/ext/ratatui_ruby/src/widgets/scrollbar_state.rs +169 -0
  174. data/ext/ratatui_ruby/src/widgets/sparkline.rs +14 -11
  175. data/ext/ratatui_ruby/src/widgets/table.rs +121 -5
  176. data/ext/ratatui_ruby/src/widgets/table_state.rs +121 -0
  177. data/ext/ratatui_ruby/src/widgets/tabs.rs +11 -11
  178. data/lib/ratatui_ruby/cell.rb +7 -7
  179. data/lib/ratatui_ruby/event/key/character.rb +35 -0
  180. data/lib/ratatui_ruby/event/key/media.rb +44 -0
  181. data/lib/ratatui_ruby/event/key/modifier.rb +95 -0
  182. data/lib/ratatui_ruby/event/key/navigation.rb +55 -0
  183. data/lib/ratatui_ruby/event/key/system.rb +45 -0
  184. data/lib/ratatui_ruby/event/key.rb +112 -52
  185. data/lib/ratatui_ruby/event/mouse.rb +3 -3
  186. data/lib/ratatui_ruby/event/none.rb +43 -0
  187. data/lib/ratatui_ruby/event/paste.rb +1 -1
  188. data/lib/ratatui_ruby/event.rb +56 -4
  189. data/lib/ratatui_ruby/frame.rb +183 -0
  190. data/lib/ratatui_ruby/list_state.rb +88 -0
  191. data/lib/ratatui_ruby/schema/bar_chart/bar.rb +13 -13
  192. data/lib/ratatui_ruby/schema/bar_chart/bar_group.rb +1 -5
  193. data/lib/ratatui_ruby/schema/bar_chart.rb +217 -217
  194. data/lib/ratatui_ruby/schema/block.rb +163 -168
  195. data/lib/ratatui_ruby/schema/calendar.rb +66 -67
  196. data/lib/ratatui_ruby/schema/canvas.rb +63 -63
  197. data/lib/ratatui_ruby/schema/center.rb +46 -46
  198. data/lib/ratatui_ruby/schema/chart.rb +135 -143
  199. data/lib/ratatui_ruby/schema/clear.rb +42 -42
  200. data/lib/ratatui_ruby/schema/constraint.rb +76 -76
  201. data/lib/ratatui_ruby/schema/cursor.rb +30 -25
  202. data/lib/ratatui_ruby/schema/gauge.rb +54 -52
  203. data/lib/ratatui_ruby/schema/layout.rb +87 -87
  204. data/lib/ratatui_ruby/schema/line_gauge.rb +62 -62
  205. data/lib/ratatui_ruby/schema/list.rb +103 -80
  206. data/lib/ratatui_ruby/schema/list_item.rb +41 -0
  207. data/lib/ratatui_ruby/schema/overlay.rb +31 -31
  208. data/lib/ratatui_ruby/schema/paragraph.rb +80 -80
  209. data/lib/ratatui_ruby/schema/ratatui_logo.rb +10 -6
  210. data/lib/ratatui_ruby/schema/ratatui_mascot.rb +10 -5
  211. data/lib/ratatui_ruby/schema/rect.rb +99 -56
  212. data/lib/ratatui_ruby/schema/scrollbar.rb +119 -119
  213. data/lib/ratatui_ruby/schema/shape/label.rb +1 -1
  214. data/lib/ratatui_ruby/schema/sparkline.rb +111 -110
  215. data/lib/ratatui_ruby/schema/style.rb +66 -46
  216. data/lib/ratatui_ruby/schema/table.rb +126 -115
  217. data/lib/ratatui_ruby/schema/tabs.rb +66 -67
  218. data/lib/ratatui_ruby/schema/text.rb +69 -1
  219. data/lib/ratatui_ruby/scrollbar_state.rb +112 -0
  220. data/lib/ratatui_ruby/session/autodoc.rb +482 -0
  221. data/lib/ratatui_ruby/session.rb +55 -23
  222. data/lib/ratatui_ruby/table_state.rb +90 -0
  223. data/lib/ratatui_ruby/test_helper/event_injection.rb +169 -0
  224. data/lib/ratatui_ruby/test_helper/snapshot.rb +390 -0
  225. data/lib/ratatui_ruby/test_helper/style_assertions.rb +351 -0
  226. data/lib/ratatui_ruby/test_helper/terminal.rb +127 -0
  227. data/lib/ratatui_ruby/test_helper/test_doubles.rb +68 -0
  228. data/lib/ratatui_ruby/test_helper.rb +66 -193
  229. data/lib/ratatui_ruby/version.rb +1 -1
  230. data/lib/ratatui_ruby.rb +100 -51
  231. data/{examples/sparkline_demo → sig/examples/app_all_events}/app.rbs +3 -2
  232. data/sig/examples/app_all_events/model/event_entry.rbs +16 -0
  233. data/sig/examples/app_all_events/model/events.rbs +15 -0
  234. data/sig/examples/app_all_events/model/timestamp.rbs +11 -0
  235. data/sig/examples/app_all_events/view/app_view.rbs +8 -0
  236. data/sig/examples/app_all_events/view/controls_view.rbs +6 -0
  237. data/sig/examples/app_all_events/view/counts_view.rbs +6 -0
  238. data/sig/examples/app_all_events/view/live_view.rbs +6 -0
  239. data/sig/examples/app_all_events/view/log_view.rbs +6 -0
  240. data/sig/examples/app_all_events/view.rbs +8 -0
  241. data/sig/examples/app_all_events/view_state.rbs +15 -0
  242. data/{examples/list_demo → sig/examples/app_color_picker}/app.rbs +2 -2
  243. data/sig/examples/app_login_form/app.rbs +11 -0
  244. data/sig/examples/app_stateful_interaction/app.rbs +33 -0
  245. data/sig/examples/verify_quickstart_dsl/app.rbs +11 -0
  246. data/sig/examples/verify_quickstart_lifecycle/app.rbs +11 -0
  247. data/sig/examples/verify_readme_usage/app.rbs +11 -0
  248. data/sig/examples/widget_block_demo/app.rbs +32 -0
  249. data/sig/examples/widget_box_demo/app.rbs +11 -0
  250. data/sig/examples/widget_calendar_demo/app.rbs +11 -0
  251. data/sig/examples/widget_cell_demo/app.rbs +11 -0
  252. data/sig/examples/widget_chart_demo/app.rbs +11 -0
  253. data/{examples/gauge_demo → sig/examples/widget_gauge_demo}/app.rbs +4 -0
  254. data/sig/examples/widget_layout_split/app.rbs +10 -0
  255. data/sig/examples/widget_line_gauge_demo/app.rbs +11 -0
  256. data/sig/examples/widget_list_demo/app.rbs +12 -0
  257. data/sig/examples/widget_map_demo/app.rbs +11 -0
  258. data/sig/examples/widget_popup_demo/app.rbs +11 -0
  259. data/sig/examples/widget_ratatui_logo_demo/app.rbs +11 -0
  260. data/sig/examples/widget_ratatui_mascot_demo/app.rbs +11 -0
  261. data/sig/examples/widget_rect/app.rbs +12 -0
  262. data/sig/examples/widget_render/app.rbs +10 -0
  263. data/sig/examples/widget_rich_text/app.rbs +11 -0
  264. data/sig/examples/widget_scroll_text/app.rbs +11 -0
  265. data/sig/examples/widget_scrollbar_demo/app.rbs +11 -0
  266. data/sig/examples/widget_sparkline_demo/app.rbs +10 -0
  267. data/{examples → sig/examples}/widget_style_colors/app.rbs +1 -1
  268. data/sig/examples/widget_table_demo/app.rbs +11 -0
  269. data/sig/examples/widget_text_width/app.rbs +10 -0
  270. data/sig/ratatui_ruby/event.rbs +11 -1
  271. data/sig/ratatui_ruby/frame.rbs +11 -0
  272. data/sig/ratatui_ruby/list_state.rbs +13 -0
  273. data/sig/ratatui_ruby/ratatui_ruby.rbs +5 -4
  274. data/sig/ratatui_ruby/schema/bar_chart/bar.rbs +3 -3
  275. data/sig/ratatui_ruby/schema/draw.rbs +4 -0
  276. data/sig/ratatui_ruby/schema/gauge.rbs +2 -2
  277. data/sig/ratatui_ruby/schema/layout.rbs +1 -1
  278. data/sig/ratatui_ruby/schema/line_gauge.rbs +2 -2
  279. data/sig/ratatui_ruby/schema/list.rbs +4 -2
  280. data/sig/ratatui_ruby/schema/list_item.rbs +10 -0
  281. data/sig/ratatui_ruby/schema/rect.rbs +3 -0
  282. data/sig/ratatui_ruby/schema/style.rbs +3 -3
  283. data/sig/ratatui_ruby/schema/table.rbs +3 -1
  284. data/sig/ratatui_ruby/schema/text.rbs +8 -6
  285. data/sig/ratatui_ruby/scrollbar_state.rbs +18 -0
  286. data/sig/ratatui_ruby/session.rbs +107 -0
  287. data/sig/ratatui_ruby/table_state.rbs +15 -0
  288. data/sig/ratatui_ruby/test_helper/event_injection.rbs +16 -0
  289. data/sig/ratatui_ruby/test_helper/snapshot.rbs +12 -0
  290. data/sig/ratatui_ruby/test_helper/style_assertions.rbs +64 -0
  291. data/sig/ratatui_ruby/test_helper/terminal.rbs +14 -0
  292. data/sig/ratatui_ruby/test_helper/test_doubles.rbs +22 -0
  293. data/sig/ratatui_ruby/test_helper.rbs +5 -4
  294. data/tasks/autodoc/examples.rb +79 -0
  295. data/tasks/autodoc/inventory.rb +63 -0
  296. data/tasks/autodoc/member.rb +56 -0
  297. data/tasks/autodoc/name.rb +19 -0
  298. data/tasks/autodoc/notice.rb +26 -0
  299. data/tasks/autodoc/rbs.rb +38 -0
  300. data/tasks/autodoc/rdoc.rb +45 -0
  301. data/tasks/autodoc.rake +53 -0
  302. data/tasks/bump/changelog.rb +3 -3
  303. data/tasks/bump/history.rb +2 -2
  304. data/tasks/bump/links.rb +67 -0
  305. data/tasks/doc.rake +600 -6
  306. data/tasks/example_viewer.html.erb +172 -0
  307. data/tasks/lint.rake +8 -4
  308. data/tasks/resources/index.html.erb +6 -0
  309. data/tasks/sourcehut.rake +70 -30
  310. data/tasks/terminal_preview/app_screenshot.rb +14 -6
  311. data/tasks/terminal_preview/crash_report.rb +7 -9
  312. data/tasks/terminal_preview/launcher_script.rb +4 -6
  313. data/tasks/terminal_preview/preview_collection.rb +4 -6
  314. data/tasks/terminal_preview/safety_confirmation.rb +3 -5
  315. data/tasks/terminal_preview/saved_screenshot.rb +10 -11
  316. data/tasks/terminal_preview/terminal_window.rb +7 -9
  317. data/tasks/test.rake +1 -1
  318. data/tasks/website/index_page.rb +3 -3
  319. data/tasks/website/version.rb +10 -10
  320. data/tasks/website/version_menu.rb +10 -12
  321. data/tasks/website/versioned_documentation.rb +49 -17
  322. data/tasks/website/website.rb +6 -8
  323. data/tasks/website.rake +4 -4
  324. metadata +232 -127
  325. data/LICENSES/BSD-2-Clause.txt +0 -9
  326. data/doc/contributors/better_dx.md +0 -543
  327. data/doc/contributors/example_analysis.md +0 -82
  328. data/doc/images/all_events.png +0 -0
  329. data/doc/images/block_padding.png +0 -0
  330. data/doc/images/block_titles.png +0 -0
  331. data/doc/images/box_demo.png +0 -0
  332. data/doc/images/calendar_demo.png +0 -0
  333. data/doc/images/cell_demo.png +0 -0
  334. data/doc/images/chart_demo.png +0 -0
  335. data/doc/images/flex_layout.png +0 -0
  336. data/doc/images/gauge_demo.png +0 -0
  337. data/doc/images/line_gauge_demo.png +0 -0
  338. data/doc/images/list_demo.png +0 -0
  339. data/doc/images/list_styles.png +0 -0
  340. data/doc/images/login_form.png +0 -0
  341. data/doc/images/quickstart_dsl.png +0 -0
  342. data/doc/images/quickstart_lifecycle.png +0 -0
  343. data/doc/images/readme_usage.png +0 -0
  344. data/doc/images/rich_text.png +0 -0
  345. data/doc/images/scroll_text.png +0 -0
  346. data/doc/images/scrollbar_demo.png +0 -0
  347. data/doc/images/sparkline_demo.png +0 -0
  348. data/doc/images/table_flex.png +0 -0
  349. data/doc/images/table_select.png +0 -0
  350. data/examples/all_events/app.rb +0 -169
  351. data/examples/all_events/app.rbs +0 -7
  352. data/examples/all_events/test_app.rb +0 -139
  353. data/examples/analytics/app.rb +0 -258
  354. data/examples/analytics/app.rbs +0 -7
  355. data/examples/analytics/test_app.rb +0 -132
  356. data/examples/block_padding/app.rb +0 -63
  357. data/examples/block_padding/app.rbs +0 -7
  358. data/examples/block_padding/test_app.rb +0 -31
  359. data/examples/block_titles/app.rb +0 -61
  360. data/examples/block_titles/app.rbs +0 -7
  361. data/examples/block_titles/test_app.rb +0 -34
  362. data/examples/box_demo/app.rbs +0 -7
  363. data/examples/box_demo/test_app.rb +0 -88
  364. data/examples/calendar_demo/app.rb +0 -101
  365. data/examples/calendar_demo/app.rbs +0 -7
  366. data/examples/calendar_demo/test_app.rb +0 -108
  367. data/examples/cell_demo/app.rb +0 -108
  368. data/examples/cell_demo/app.rbs +0 -7
  369. data/examples/cell_demo/test_app.rb +0 -36
  370. data/examples/chart_demo/app.rb +0 -203
  371. data/examples/chart_demo/app.rbs +0 -7
  372. data/examples/chart_demo/test_app.rb +0 -102
  373. data/examples/custom_widget/app.rb +0 -51
  374. data/examples/custom_widget/app.rbs +0 -7
  375. data/examples/custom_widget/test_app.rb +0 -30
  376. data/examples/flex_layout/app.rb +0 -156
  377. data/examples/flex_layout/app.rbs +0 -7
  378. data/examples/flex_layout/test_app.rb +0 -65
  379. data/examples/gauge_demo/app.rb +0 -182
  380. data/examples/gauge_demo/test_app.rb +0 -120
  381. data/examples/hit_test/app.rb +0 -175
  382. data/examples/hit_test/app.rbs +0 -7
  383. data/examples/hit_test/test_app.rb +0 -102
  384. data/examples/line_gauge_demo/app.rb +0 -190
  385. data/examples/line_gauge_demo/app.rbs +0 -7
  386. data/examples/line_gauge_demo/test_app.rb +0 -129
  387. data/examples/list_demo/app.rb +0 -253
  388. data/examples/list_demo/test_app.rb +0 -237
  389. data/examples/list_styles/app.rb +0 -140
  390. data/examples/list_styles/app.rbs +0 -7
  391. data/examples/list_styles/test_app.rb +0 -157
  392. data/examples/login_form/app.rbs +0 -7
  393. data/examples/login_form/test_app.rb +0 -51
  394. data/examples/map_demo/app.rbs +0 -7
  395. data/examples/map_demo/test_app.rb +0 -149
  396. data/examples/mouse_events/app.rb +0 -97
  397. data/examples/mouse_events/app.rbs +0 -7
  398. data/examples/mouse_events/test_app.rb +0 -53
  399. data/examples/popup_demo/app.rb +0 -103
  400. data/examples/popup_demo/app.rbs +0 -7
  401. data/examples/popup_demo/test_app.rb +0 -54
  402. data/examples/quickstart_dsl/app.rbs +0 -7
  403. data/examples/quickstart_dsl/test_app.rb +0 -29
  404. data/examples/quickstart_lifecycle/app.rb +0 -39
  405. data/examples/quickstart_lifecycle/app.rbs +0 -7
  406. data/examples/quickstart_lifecycle/test_app.rb +0 -29
  407. data/examples/ratatui_logo_demo/app.rb +0 -79
  408. data/examples/ratatui_logo_demo/app.rbs +0 -7
  409. data/examples/ratatui_logo_demo/test_app.rb +0 -51
  410. data/examples/ratatui_mascot_demo/app.rb +0 -84
  411. data/examples/ratatui_mascot_demo/app.rbs +0 -7
  412. data/examples/ratatui_mascot_demo/test_app.rb +0 -47
  413. data/examples/readme_usage/app.rb +0 -29
  414. data/examples/readme_usage/app.rbs +0 -7
  415. data/examples/readme_usage/test_app.rb +0 -29
  416. data/examples/rich_text/app.rb +0 -141
  417. data/examples/rich_text/app.rbs +0 -7
  418. data/examples/rich_text/test_app.rb +0 -166
  419. data/examples/scroll_text/app.rb +0 -103
  420. data/examples/scroll_text/app.rbs +0 -7
  421. data/examples/scroll_text/test_app.rb +0 -110
  422. data/examples/scrollbar_demo/app.rb +0 -143
  423. data/examples/scrollbar_demo/app.rbs +0 -7
  424. data/examples/scrollbar_demo/test_app.rb +0 -77
  425. data/examples/sparkline_demo/app.rb +0 -240
  426. data/examples/sparkline_demo/test_app.rb +0 -107
  427. data/examples/table_flex/app.rb +0 -65
  428. data/examples/table_flex/app.rbs +0 -7
  429. data/examples/table_flex/test_app.rb +0 -36
  430. data/examples/table_select/app.rb +0 -198
  431. data/examples/table_select/app.rbs +0 -7
  432. data/examples/table_select/test_app.rb +0 -180
  433. data/examples/widget_style_colors/test_app.rb +0 -48
  434. data/tasks/bump/comparison_links.rb +0 -41
  435. /data/doc/images/{analytics.png → app_analytics.png} +0 -0
  436. /data/doc/images/{custom_widget.png → app_custom_widget.png} +0 -0
  437. /data/doc/images/{mouse_events.png → app_mouse_events.png} +0 -0
  438. /data/doc/images/{map_demo.png → widget_map_demo.png} +0 -0
  439. /data/doc/images/{popup_demo.png → widget_popup_demo.png} +0 -0
  440. /data/doc/images/{hit_test.png → widget_rect.png} +0 -0
  441. /data/{doc/images/ratatui_logo_demo.png → exe/.gitkeep} +0 -0
@@ -18,11 +18,12 @@ require "ratatui_ruby"
18
18
 
19
19
  class MyExampleApp
20
20
  def initialize
21
- # Initialize state
21
+ # Initialize state (styles must be initialized in run when @tui is available)
22
22
  end
23
23
 
24
24
  def run
25
- RatatuiRuby.run do
25
+ RatatuiRuby.run do |tui|
26
+ @tui = tui # Store for use in private methods
26
27
  loop do
27
28
  render
28
29
  break if handle_input == :quit
@@ -33,13 +34,24 @@ class MyExampleApp
33
34
  private
34
35
 
35
36
  def render
36
- # Build and draw UI
37
- RatatuiRuby.draw(layout)
37
+ @tui.draw do |frame|
38
+ # 1. Split layout using Session helpers
39
+ areas = @tui.layout_split(frame.area, constraints: [@tui.constraint_fill(1)])
40
+ # 2. Create and render widgets
41
+ widget = @tui.paragraph(text: "Hello", block: @tui.block(borders: [:all]))
42
+ frame.render_widget(widget, areas[0])
43
+ end
38
44
  end
39
45
 
40
46
  def handle_input
41
- event = RatatuiRuby.poll_event
42
- # Process event, return :quit to exit
47
+ case @tui.poll_event
48
+ in { type: :key, code: "q" }
49
+ :quit
50
+ in { type: :key, code: code }
51
+ # Handle other keys
52
+ else
53
+ # Ignore unhandled events
54
+ end
43
55
  end
44
56
  end
45
57
 
@@ -48,11 +60,12 @@ MyExampleApp.new.run if __FILE__ == $PROGRAM_NAME
48
60
 
49
61
  ### Naming Convention (Required)
50
62
 
51
- Example classes **must** follow the naming convention:
52
- - **Directory:** `examples/my_example/` (snake_case)
53
- - **Class:** `MyExampleApp` (PascalCase with `App` suffix)
63
+ Example directories **must** follow a prefixing convention to categorize them alphabetically:
64
+ - `app_`: Application showcases (e.g., `app_analytics`). Class name: `AppAnalytics`.
65
+ - `widget_`: Widget-focused demonstrations (e.g., `widget_gauge_demo`). Class name: `WidgetGaugeDemo`.
66
+ - `verify_`: Documentation verification examples (e.g., `verify_readme_usage`). Class name: `VerifyReadmeUsage`.
54
67
 
55
- The class name is derived from the directory name: `my_example` `MyExampleApp`.
68
+ The directory and class names must match (snake_case directory maps to PascalCase class).
56
69
 
57
70
  This convention enables the `terminal_preview:update` rake task to automatically capture terminal output for all examples without maintaining a manual registry.
58
71
 
@@ -71,9 +84,11 @@ All interactive examples must fit within an **80×24 terminal** (standard VT100
71
84
  - **Style hotkeys visually:** Use `modifiers: [:bold, :underlined]` on hotkey letters to make them stand out from descriptions. Example: `i` (bold, underlined) followed by `Items`.
72
85
  - Test early by running the example at 80×24 and verifying all content is visible without wrapping, scrolling, or clipping.
73
86
 
74
- Every example must also have an RBS file documenting its public methods:
87
+ ## Type Signatures
75
88
 
76
- `examples/my_example/app.rbs`:
89
+ Every example must also have an RBS file documenting its public methods. Type signatures live in a centralized location:
90
+
91
+ `sig/examples/my_example/app.rbs`:
77
92
  ```rbs
78
93
  class MyExampleApp
79
94
  # @public
@@ -84,19 +99,75 @@ class MyExampleApp
84
99
  end
85
100
  ```
86
101
 
102
+ ## Directory Structure
103
+
104
+ Examples are organized across three locations:
105
+
106
+ ```
107
+ examples/
108
+ my_example/
109
+ app.rb ← REQUIRED: The runnable example code
110
+ README.md ← REQUIRED: Purpose, architecture, hotkeys, usage
111
+
112
+ test/examples/
113
+ my_example/
114
+ test_app.rb ← REQUIRED: Tests (centralized, not local to example)
115
+ snapshots/ ← Auto-created by assert_snapshot
116
+ initial_render.txt
117
+
118
+ sig/examples/
119
+ my_example/
120
+ app.rbs ← REQUIRED: Type signatures (centralized, not local to example)
121
+ ```
122
+
87
123
  ### Key Requirements
88
124
 
89
125
  1. **Only `run` should be public.** All other methods (`render`, `handle_input`, helper methods) must be private. This prevents tests from calling internal methods directly.
90
126
 
91
127
  2. **Use `RatatuiRuby.run` for terminal management.** Never call `init_terminal` or `restore_terminal` directly. The `run` block handles terminal setup/teardown automatically and safely, even if an exception occurs.
92
128
 
93
- 3. **Use keyboard keys to cycle through widget attributes.** Users should be able to interactively explore all widget options. Common patterns:
129
+ 3. **Use the Session API (`tui`) for cleaner code.** Accept the `tui` block parameter from `RatatuiRuby.run` and use it throughout your app:
130
+ - `@tui.draw { |frame| ... }` instead of `RatatuiRuby.draw`
131
+ - `@tui.poll_event` instead of `RatatuiRuby.poll_event`
132
+ - `@tui.style(...)` instead of `RatatuiRuby::Style.new(...)`
133
+ - `@tui.paragraph(...)` instead of `RatatuiRuby::Paragraph.new(...)`
134
+ - `@tui.block(...)` instead of `RatatuiRuby::Block.new(...)`
135
+ - `@tui.layout_split(...)` instead of `RatatuiRuby::Layout.split(...)`
136
+ - `@tui.constraint_fill(...)` instead of `RatatuiRuby::Constraint.fill(...)`
137
+ - `@tui.text_line(...)` instead of `RatatuiRuby::Text::Line.new(...)`
138
+ - `@tui.text_span(...)` instead of `RatatuiRuby::Text::Span.new(...)`
139
+
140
+ 4. **Event handling must include a catch-all pattern.** When using pattern matching in `handle_input`, always include an `else` clause at the end to catch unmatched events (mouse events, resize events, focus events, etc.). Without it, unmatched events will raise `NoMatchingPatternError`:
141
+
142
+ ```ruby
143
+ def handle_input
144
+ case @tui.poll_event
145
+ in { type: :key, code: "q" }
146
+ :quit
147
+ in { type: :mouse, kind: "down", x:, y: }
148
+ handle_click(x, y)
149
+ else
150
+ # Ignore other events
151
+ end
152
+ end
153
+
154
+ 5. **Use keyboard keys to cycle through widget attributes.** Users should be able to interactively explore all widget options. Common patterns:
94
155
  - Arrow keys: Navigate or adjust values
95
156
  - Letter keys: Cycle through styles, modes, or variants. Prefer all lowercase keys to avoid confusion and simplify the UI description.
96
157
  - Space: Toggle or select
97
158
  - `q` or Ctrl+C: Quit
98
159
 
99
- ### Naming Conventions for Controls
160
+ 6. **All examples must include a README.md** explaining:
161
+ - What problem the example solves
162
+ - Architecture (if applicable)
163
+ - Hotkeys (if interactive): Document all keyboard/mouse controls
164
+ - Key concepts demonstrated
165
+ - Usage instructions
166
+ - Learning outcomes
167
+
168
+ See examples/app_color_picker/README.md and examples/app_all_events/README.md for patterns. Adhere to docs/contributors/documentation_style.md.
169
+
170
+ 7. **Naming Conventions for Controls**
100
171
 
101
172
  When documenting hotkeys and cycling options in the UI, use consistent naming:
102
173
 
@@ -105,11 +176,12 @@ When documenting hotkeys and cycling options in the UI, use consistent naming:
105
176
  - Use "Highlight Style" (not "Highlight") for the `highlight_style:` parameter
106
177
  - Use "Repeat Symbol" (not "Repeat") for the `repeat_highlight_symbol:` parameter
107
178
 
108
- - **Display names for cycled values:** Create a `name` field in your options hash to keep display names paired with values:
179
+ - **Display names for cycled values:** Create a `name` field in your options hash to keep display names paired with values. Initialize style arrays inside `run` when `@tui` is available:
109
180
  ```ruby
181
+ # In run method, after @tui = tui:
110
182
  @styles = [
111
- { name: "Yellow Bold", style: RatatuiRuby::Style.new(fg: :yellow, modifiers: [:bold]) },
112
- { name: "Blue on White", style: RatatuiRuby::Style.new(fg: :blue, bg: :white) }
183
+ { name: "Yellow Bold", style: @tui.style(fg: :yellow, modifiers: [:bold]) },
184
+ { name: "Blue on White", style: @tui.style(fg: :blue, bg: :white) }
113
185
  ]
114
186
 
115
187
  # In controls: "h: Highlight Style (#{@styles[@style_index][:name]})"
@@ -118,17 +190,21 @@ When documenting hotkeys and cycling options in the UI, use consistent naming:
118
190
 
119
191
  This keeps the UI self-documenting and users can see exact parameter names when they read the hotkey help.
120
192
 
121
- ### Hit Testing with the Cached Layout Pattern
193
+ 8. **Hit Testing**
122
194
 
123
- Examples with mouse interaction should implement the **Cached Layout Pattern** documented in `doc/interactive_design.md`. The `hit_test` example demonstrates this pattern.
195
+ Examples with mouse interaction should use the **Frame API**. By calling `@tui.layout_split` inside `@tui.draw`, you obtain the exact `Rect`s used for rendering. Store these rects in instance variables (e.g., `@sidebar_rect`) to use them in your `handle_input` method for hit testing:
124
196
 
125
- ## Testing Examples
197
+ ```ruby
198
+ if @sidebar_rect&.contains?(event.x, event.y)
199
+ # Handle click
200
+ end
201
+ ```
126
202
 
127
- Example tests live alongside examples as `test_app.rb` files in the same directory.
203
+ ## Testing Examples
128
204
 
129
- ### Testing Pattern
205
+ Example tests live in a centralized test tree:
130
206
 
131
- `examples/my_example/test_app.rb`:
207
+ `test/examples/my_example/test_app.rb`:
132
208
  ```ruby
133
209
  $LOAD_PATH.unshift File.expand_path("../../lib", __dir__)
134
210
  require "ratatui_ruby"
@@ -145,44 +221,75 @@ class TestMyExampleApp < Minitest::Test
145
221
 
146
222
  def test_initial_render
147
223
  with_test_terminal do
148
- inject_key(:q) # Queue quit event
149
- @app.run # Run the app loop
150
-
151
- content = buffer_content.join("\n")
152
- assert_includes content, "Expected Text"
224
+ inject_key(:q)
225
+ @app.run
226
+ assert_snapshot("initial_render")
153
227
  end
154
228
  end
229
+ end
230
+ ```
155
231
 
156
- def test_keyboard_interaction
157
- with_test_terminal do
158
- inject_key("s") # Press 's' to cycle something
159
- inject_key(:q) # Then quit
160
- @app.run
232
+ ## Snapshot Testing Pattern (REQUIRED)
161
233
 
162
- content = buffer_content.join("\n")
163
- assert_includes content, "Changed State"
164
- end
234
+ All example tests MUST use snapshot testing via the `assert_snapshot` API, not manual content assertions.
235
+
236
+ ### Why Snapshots
237
+
238
+ - **Exact verification:** Captures complete screen state, character-by-character
239
+ - **Auto-update:** `UPDATE_SNAPSHOTS=1 bin/agent_rake test` regenerates all snapshots
240
+ - **Auto-managed:** Snapshots live in `test/examples/{name}/snapshots/{test_name}.txt`
241
+ - **Maintainable:** No tedious manual string checks
242
+ - **Self-documenting:** Snapshots show exactly what output is expected
243
+
244
+ ### Basic Pattern
245
+
246
+ ```ruby
247
+ def test_initial_render
248
+ with_test_terminal do
249
+ inject_key(:q)
250
+ @app.run
251
+
252
+ assert_snapshot("initial_render")
165
253
  end
166
254
  end
167
255
  ```
168
256
 
169
- ### Testing Guidelines
257
+ Snapshot auto-saved to: `test/examples/widget_foo_demo/snapshots/initial_render.txt`
170
258
 
171
- 1. **Inject events, observe buffer.** Tests should only interact through:
172
- - `inject_key` / `inject_keys` / `inject_event` for input
173
- - `buffer_content` for output verification
259
+ ### With Normalization (for dynamic content)
174
260
 
175
- 2. **Never call internal methods.** Don't call `render`, `handle_input`, `__send__`, or access instance variables with `instance_variable_get`. Tests verify behavior through the public `run` method.
261
+ For examples with timestamps, random data, or other non-deterministic output:
176
262
 
177
- 3. **Use `inject_key(:q)` to exit.** All examples should support quitting with `q`, so inject this as the final event to terminate the loop.
263
+ ```ruby
264
+ private def assert_normalized_snapshot(snapshot_name)
265
+ assert_snapshot(snapshot_name) do |actual|
266
+ actual.map do |line|
267
+ line.gsub(/\d{2}:\d{2}:\d{2}/, "XX:XX:XX") # Mask timestamps
268
+ .gsub(/Random ID: \d+/, "Random ID: XXX") # Mask random values
269
+ end
270
+ end
271
+ end
178
272
 
179
- 4. **Assert and refute.** When testing which item was clicked/selected, also verify the opposite didn't happen:
180
- ```ruby
181
- assert_includes content, "Left Panel clicked"
182
- refute_includes content, "Right Panel clicked"
183
- ```
273
+ def test_after_event
274
+ with_test_terminal do
275
+ inject_key("a")
276
+ inject_key(:q)
277
+ @app.run
278
+
279
+ assert_normalized_snapshot("after_event")
280
+ end
281
+ end
282
+ ```
283
+
284
+ See `test/examples/app_all_events/test_app.rb` for a complete example.
285
+
286
+ ### Regenerating Snapshots
287
+
288
+ When UI changes are intentional, regenerate all snapshots:
184
289
 
185
- 5. **Test state cycling.** If an example cycles through options (styles, modes, etc.), test that pressing the key actually changes the rendered output.
290
+ ```bash
291
+ UPDATE_SNAPSHOTS=1 bin/agent_rake test
292
+ ```
186
293
 
187
294
  ## Widget Attribute Cycling
188
295
 
@@ -201,3 +308,39 @@ Examples should demonstrate widget configurability by allowing interactive cycli
201
308
  | Scrollbar | theme | s |
202
309
 
203
310
  Display the current state in the UI (e.g., in a title or status bar or paragraph) so users can see what changed. Display the hotkey in the UI as well, so users can see how to change it; the hotkey should not disappear as app state changes.
311
+
312
+ ## Data Quality
313
+
314
+ Examples must use **realistic, meaningful data**—not dummy placeholder text. This ensures examples:
315
+ - Demonstrate the widget's real-world usage
316
+ - Provide educational value to users reading the code
317
+ - Look professional and polished
318
+
319
+ ### Guidelines
320
+
321
+ **For small datasets (< 10 items):**
322
+ Use hardcoded realistic data. Examples:
323
+ - Geographic coordinates with city names (see `widget_map_demo/app.rb`)
324
+ - Real product names or person names
325
+ - Meaningful status values ("Completed", "Pending", "Failed")
326
+
327
+ **For large datasets (≥ 10 items):**
328
+ Use the [Faker](https://github.com/faker-ruby/faker) gem with **deterministic seeding** so data is consistent across runs:
329
+
330
+ ```ruby
331
+ require "faker"
332
+
333
+ # Seed Faker for reproducible output
334
+ Faker::Config.random = Random.new(12345)
335
+
336
+ # Generate realistic data
337
+ users = Array.new(50) { Faker::Name.name }
338
+ emails = Array.new(50) { Faker::Internet.email }
339
+ ```
340
+
341
+ In tests, set the same seed before each test to ensure snapshot consistency.
342
+
343
+ **Avoid:**
344
+ - Repeated placeholder text like "Lorem ipsum" or "Background Layer" × 20
345
+ - Generic numbered items like "Item 1", "Item 2" (unless the context demands it)
346
+ - Nonsensical or visually jarring content
@@ -1,3 +1,9 @@
1
+ <!--
2
+ SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
3
+
4
+ SPDX-License-Identifier: AGPL-3.0-or-later
5
+ -->
6
+
1
7
  # Documentation Style Guide
2
8
 
3
9
  This project follows a strict and specific documentation style designed to be helpful, readable, and consistent. It combines the structural clarity of Christopher Alexander's Pattern Language with the prose style of William Zinsser's *On Writing Well* and the usability of the U.S. Federal Plain Language Guidelines.
@@ -9,6 +15,7 @@ This project follows a strict and specific documentation style designed to be he
9
15
  * **Context, Problem, Solution (Alexandrian Form):** Do not just say *what* a class does. Explain *why* it exists. Start with the context, state the problem (the pain point without this tool), and then present the class as the solution.
10
16
  * **Prose Style (Zinsser/Klinkenborg):** Use short, punchy sentences. Use active voice. Cut unnecessary words. Avoid "allow," "enable," "provide," "support," "functionality," and "capability" where possible. Weak verbs hide the action. Strong verbs drive the sentence.
11
17
  * **User-Centric (Plain Language):** Speak directly to the user ("You"). Don't abstract them away ("The developer"). Focus on their goals and how this tool helps them achieve those goals.
18
+ * **Tone (Supportive and Authoritative, not Hostile or Prescriptive):** Avoid "must," "requires," "need to," or "mandatory." These words sound bossy. Treat the user as a capable peer. Instead of "You must do X," use imperative "Do X" or cause-and-effect "X ensures Y."
12
19
 
13
20
  ## 2. Class Documentation
14
21
 
@@ -0,0 +1,21 @@
1
+ <!--
2
+ SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
3
+ SPDX-License-Identifier: CC-BY-SA-4.0
4
+ -->
5
+
6
+ # Priority 1: High (Polish & Ecosystem)
7
+
8
+ Important for v1.0.0 quality and ecosystem goals. Not blocking release, but recommended before ship.
9
+
10
+ ---
11
+
12
+ ## 1. Ensure All Widgets Have Examples
13
+
14
+ **Status:** Done
15
+
16
+ Verified that all widget types shipped with ratatui_ruby have at least one example showing how to use them.
17
+
18
+ **Action:**
19
+ - [x] Check widget manifest against example inventory
20
+ - [x] Create `widget_canvas_demo`, `widget_center_demo`, and `widget_overlay_demo`
21
+
@@ -0,0 +1,81 @@
1
+ <!--
2
+ SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
3
+ SPDX-License-Identifier: CC-BY-SA-4.0
4
+ -->
5
+
6
+ # Priority 2: Moderate (Quality Gates)
7
+
8
+ These are v1.0.0 quality improvements that refine the example suite after P0 is complete. Not blocking, but recommended for maintainability and API consistency.
9
+
10
+ ---
11
+
12
+ ## 1. Add RDoc Cross-Links (Examples & Aliases)
13
+
14
+ **Status:** Important for API discoverability — Documentation should link library and examples
15
+
16
+ RDoc should cross-link between:
17
+ - **Library classes/methods** ↔ **Examples that use them** (See also: examples/widget_foo_demo)
18
+ - **Primary methods** ↔ **DWIM/TIMTOWTDI aliases** (See also: tui.foo_bar as alias for tui.foo(:bar))
19
+
20
+ ### Current Practice
21
+
22
+ Done for:
23
+ - `RatatuiRuby::Frame#set_cursor_position` ↔ `RatatuiRuby::Cursor` (cross-linking)
24
+ - Limited elsewhere
25
+
26
+ ### Gaps
27
+
28
+ - Most widget classes have no "See also: example_foo_demo" links
29
+ - Aliases/TIMTOWTDI variants are not documented as such
30
+ - Users can't easily find examples for a given class/method
31
+
32
+ ### Action
33
+
34
+ 1. Add `# See also: examples/widget_foo_demo/app.rb` to class/method RDoc
35
+ 2. Link DWIM methods to TIMTOWTDI variants: `# Also available as: tui.constraint_length (DWIM) vs tui.constraint(:length) (TIMTOWTDI)`
36
+ 3. Create consistent pattern across all public APIs in `lib/ratatui_ruby/`
37
+
38
+ ### Example Pattern
39
+
40
+ ```ruby
41
+ # Renders text with styling.
42
+ #
43
+ # See also: examples/widget_paragraph_demo/app.rb (basic paragraph rendering)
44
+ class Paragraph < Data.define(...)
45
+ # ...
46
+ end
47
+
48
+ # DWIM version of constraint creation
49
+ # Also available as: constraint(type, value) for explicit control
50
+ def constraint_length(length)
51
+ constraint(:length, length)
52
+ end
53
+ ```
54
+
55
+ ---
56
+
57
+ ## Dependencies
58
+
59
+ - P0 (developing_examples.md, README.md, tests) should be complete before consolidation
60
+
61
+ ---
62
+
63
+ ## 4. Enhance Widget Examples with Functional Context
64
+
65
+ **Status:** Recommended — Move beyond "parameter playgrounds" to "real-world patterns"
66
+
67
+ Current `widget_*` examples mostly focus on interactive parameter turning (changing colors, borders, etc.). While useful for API discovery, they don't show *how* to use the widget in a real application logic flow.
68
+
69
+ ### The Standard: widget_tabs_demo
70
+
71
+ The `widget_tabs_demo` was enhanced to show **conditional rendering** of content based on the selected tab in git commit `38ceed39a011d557cc66e11a4598d3341dc7a0cc`. It doesn't just highlight the tab; it changes the screen content. This connects the widget (the tabs) to the problem it solves (view segregation).
72
+
73
+ ### Action
74
+
75
+ Identify other widget examples that could benefit from this "functional context" treatment:
76
+
77
+ - **widget_popup_demo:** Show a multi-step modal flow (e.g., Confirm -> Success) rather than just a static overlay.
78
+ - **widget_list_demo:** Show a master-detail view where selecting a list item updates a detail pane.
79
+ - **widget_input_demo:** (If created) Show specific validation logic (email vs number).
80
+
81
+ **Goal:** Every widget example should answer "How do I build a feature with this?" not just "What does this parameter do?"
@@ -0,0 +1,41 @@
1
+ <!--
2
+ SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
3
+ SPDX-License-Identifier: CC-BY-SA-4.0
4
+ -->
5
+
6
+ # Examples Audit Report
7
+
8
+ Audit of ratatui_ruby `examples/` directory for v1.0.0 readiness.
9
+
10
+ ## P0: Critical (Completed ✓)
11
+
12
+ All P0 critical items have been completed:
13
+
14
+ 1. **Migrate Example Tests to Snapshot API** ✓
15
+ - Migrated 31 test files from manual `buffer_content` assertions to `assert_snapshot` and `assert_rich_snapshot`
16
+ - Added deterministic seeding for tests with random content (Faker, RATA_SEED)
17
+ - Generates `.txt` (plain) and `.ansi` (styled) snapshots for mutation-testing capability
18
+
19
+ ---
20
+
21
+ ## [P1: High (Polish)](./examples_audit/p1_high.md)
22
+
23
+ 1. **[Ensure All Widgets Have Examples](./examples_audit/p1_high.md#1-ensure-all-widgets-have-examples)** (Completeness)
24
+ - Check widget manifest against example inventory
25
+ - Create examples for any missing widgets
26
+
27
+ ---
28
+
29
+ ## [P2: Moderate (Quality)](./examples_audit/p2_moderate.md)
30
+
31
+ 1. **[Add RDoc Cross-Links](./examples_audit/p2_moderate.md#1-add-rdoc-cross-links-examples--aliases)** (Documentation discoverability)
32
+ - Link library classes/methods to examples
33
+ - Link DWIM/TIMTOWTDI aliases
34
+ - Create consistent pattern across public APIs
35
+
36
+ ---
37
+
38
+ ## Success Criteria for v1.0.0
39
+
40
+ - ✓ All P0 items are fixed
41
+ - ✓ All P1 items are mitigated (or time has run out)
@@ -11,6 +11,8 @@
11
11
  - [Documentation Guide](https://man.sr.ht/~kerrick/ratatui_ruby/documentation_guide.md)
12
12
  - [The Design of **ratatui_ruby**](./design.md)
13
13
 
14
+
15
+
14
16
  ## Documentation for Users
15
17
 
16
18
  - [README](../../README.md)
@@ -1,10 +1,24 @@
1
+ <!--
2
+ SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
3
+
4
+ SPDX-License-Identifier: AGPL-3.0-or-later
5
+ -->
6
+
1
7
  # Event Handling in RatatuiRuby
2
8
 
3
9
  `ratatui_ruby` provides a rich, object-oriented event system that supports multiple coding styles, from simple boolean predicates to modern Ruby pattern matching.
4
10
 
5
- Events are retrieved using `RatatuiRuby.poll_event`. This method returns an instance of a subclass of `RatatuiRuby::Event` (e.g., `RatatuiRuby::Event::Key`, `RatatuiRuby::Event::Mouse`) or `nil` if no event is available.
11
+ Events are retrieved using `RatatuiRuby.poll_event`. This method returns an instance of a subclass of `RatatuiRuby::Event` (e.g., `RatatuiRuby::Event::Key`, `RatatuiRuby::Event::Mouse`). When no event is available, it returns `RatatuiRuby::Event::None`—a [null object](https://martinfowler.com/eaaCatalog/specialCase.html) that safely responds to all event predicates with `false`.
12
+
13
+ ## 1. Blocking vs. Polling
14
+
15
+ Most applications run in a loop (e.g., a game loop or UI loop). To prevent high CPU usage, the loop should wait briefly for input.
16
+
17
+ * **Default (Polling):** `RatatuiRuby.poll_event` (no args) waits for **0.016s** (approx 60 FPS). If no event occurs, it returns `RatatuiRuby::Event::None`. This keeps the application responsive.
18
+ * **Blocking:** `RatatuiRuby.poll_event(timeout: nil)` waits **forever** until an event occurs. Use this for scripts that only react to input and do not need to update the UI on a timer.
19
+ * **Non-Blocking:** `RatatuiRuby.poll_event(timeout: 0.0)` returns immediately.
6
20
 
7
- ## 1. Symbol and String Comparison (Simplest)
21
+ ## 2. Symbol and String Comparison (Simplest)
8
22
 
9
23
  For simple key events, `RatatuiRuby::Event::Key` objects can be compared directly to Symbols or Strings. This is often the quickest way to get started.
10
24
 
@@ -18,7 +32,6 @@ For a complete list of supported keys, modifiers, and event types, please refer
18
32
 
19
33
  ```ruby
20
34
  event = RatatuiRuby.poll_event
21
- next unless event
22
35
 
23
36
  # 1. Check for quit keys
24
37
  if event == "q" || event == :ctrl_c
@@ -31,7 +44,7 @@ if event == :enter
31
44
  end
32
45
  ```
33
46
 
34
- ## 2. Predicate Methods (Intermediate)
47
+ ## 3. Predicate Methods (Intermediate)
35
48
 
36
49
  If you need more control or logic (e.g. `if/elsif`), or need to handle non-key events like Resize or Mouse, use the predicate methods.
37
50
 
@@ -77,7 +90,7 @@ if event.mouse? && event.scroll_up?
77
90
  end
78
91
  ```
79
92
 
80
- ## 3. Pattern Matching (Powerful)
93
+ ## 4. Pattern Matching (Powerful)
81
94
 
82
95
  For complex applications, Ruby 3.0+ Pattern Matching with the `type:` discriminator is the most idiomatic and concise approach.
83
96
 
@@ -101,8 +114,8 @@ loop do
101
114
  in type: :mouse, kind: "down", x:, y:
102
115
  handle_click(x, y)
103
116
 
104
- else
105
- # Ignore
117
+ in type: :none
118
+ # No event available, continue loop
106
119
  end
107
120
  end
108
121
  ```
@@ -117,3 +130,4 @@ end
117
130
  | `RatatuiRuby::Event::Paste` | `:paste` | `content` | `paste?` |
118
131
  | `RatatuiRuby::Event::FocusGained` | `:focus_gained` | (none) | `focus_gained?` |
119
132
  | `RatatuiRuby::Event::FocusLost` | `:focus_lost` | (none) | `focus_lost?` |
133
+ | `RatatuiRuby::Event::None` | `:none` | (none) | `none?` |
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file