ratatui_ruby 1.0.0 → 1.0.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 (236) hide show
  1. checksums.yaml +4 -4
  2. data/ext/ratatui_ruby/Cargo.lock +1 -1
  3. data/ext/ratatui_ruby/Cargo.toml +1 -1
  4. data/lib/ratatui_ruby/version.rb +1 -1
  5. metadata +1 -232
  6. data/.builds/ruby-3.2.yml +0 -54
  7. data/.builds/ruby-3.3.yml +0 -54
  8. data/.builds/ruby-3.4.yml +0 -54
  9. data/.builds/ruby-4.0.0.yml +0 -54
  10. data/.pre-commit-config.yaml +0 -16
  11. data/.rubocop.yml +0 -10
  12. data/AGENTS.md +0 -146
  13. data/CHANGELOG.md +0 -710
  14. data/README.md +0 -187
  15. data/README.rdoc +0 -302
  16. data/Rakefile +0 -11
  17. data/Steepfile +0 -49
  18. data/doc/concepts/application_architecture.md +0 -321
  19. data/doc/concepts/application_testing.md +0 -193
  20. data/doc/concepts/async.md +0 -190
  21. data/doc/concepts/custom_widgets.md +0 -247
  22. data/doc/concepts/debugging.md +0 -401
  23. data/doc/concepts/event_handling.md +0 -162
  24. data/doc/concepts/interactive_design.md +0 -146
  25. data/doc/contributors/auditing/parity.md +0 -239
  26. data/doc/contributors/design/ruby_frontend.md +0 -420
  27. data/doc/contributors/design/rust_backend.md +0 -422
  28. data/doc/contributors/design.md +0 -11
  29. data/doc/contributors/developing_examples.md +0 -400
  30. data/doc/contributors/documentation_style.md +0 -121
  31. data/doc/contributors/index.md +0 -21
  32. data/doc/contributors/todo/align/api_completeness_audit-finished.md +0 -375
  33. data/doc/contributors/todo/align/api_completeness_audit-unfinished.md +0 -206
  34. data/doc/contributors/todo/align/terminal.md +0 -647
  35. data/doc/contributors/todo/future_work.md +0 -169
  36. data/doc/contributors/upstream_requests/tab_rects.md +0 -173
  37. data/doc/contributors/upstream_requests/title_rects.md +0 -132
  38. data/doc/custom.css +0 -22
  39. data/doc/getting_started/quickstart.md +0 -291
  40. data/doc/getting_started/why.md +0 -93
  41. data/doc/images/app_all_events.png +0 -0
  42. data/doc/images/app_cli_rich_moments.gif +0 -0
  43. data/doc/images/app_color_picker.png +0 -0
  44. data/doc/images/app_debugging_showcase.gif +0 -0
  45. data/doc/images/app_debugging_showcase.png +0 -0
  46. data/doc/images/app_login_form.png +0 -0
  47. data/doc/images/app_stateful_interaction.png +0 -0
  48. data/doc/images/verify_quickstart_dsl.png +0 -0
  49. data/doc/images/verify_quickstart_layout.png +0 -0
  50. data/doc/images/verify_quickstart_lifecycle.png +0 -0
  51. data/doc/images/verify_readme_usage.png +0 -0
  52. data/doc/images/widget_barchart.png +0 -0
  53. data/doc/images/widget_block.png +0 -0
  54. data/doc/images/widget_box.png +0 -0
  55. data/doc/images/widget_calendar.png +0 -0
  56. data/doc/images/widget_canvas.png +0 -0
  57. data/doc/images/widget_cell.png +0 -0
  58. data/doc/images/widget_center.png +0 -0
  59. data/doc/images/widget_chart.png +0 -0
  60. data/doc/images/widget_gauge.png +0 -0
  61. data/doc/images/widget_layout_split.png +0 -0
  62. data/doc/images/widget_line_gauge.png +0 -0
  63. data/doc/images/widget_list.png +0 -0
  64. data/doc/images/widget_map.png +0 -0
  65. data/doc/images/widget_overlay.png +0 -0
  66. data/doc/images/widget_popup.png +0 -0
  67. data/doc/images/widget_ratatui_logo.png +0 -0
  68. data/doc/images/widget_ratatui_mascot.png +0 -0
  69. data/doc/images/widget_rect.png +0 -0
  70. data/doc/images/widget_render.png +0 -0
  71. data/doc/images/widget_rich_text.png +0 -0
  72. data/doc/images/widget_scroll_text.png +0 -0
  73. data/doc/images/widget_scrollbar.png +0 -0
  74. data/doc/images/widget_sparkline.png +0 -0
  75. data/doc/images/widget_style_colors.png +0 -0
  76. data/doc/images/widget_table.png +0 -0
  77. data/doc/images/widget_tabs.png +0 -0
  78. data/doc/images/widget_text_width.png +0 -0
  79. data/doc/index.md +0 -39
  80. data/doc/troubleshooting/async.md +0 -4
  81. data/doc/troubleshooting/terminal_limitations.md +0 -131
  82. data/doc/troubleshooting/tui_output.md +0 -197
  83. data/examples/app_all_events/README.md +0 -114
  84. data/examples/app_all_events/app.rb +0 -98
  85. data/examples/app_all_events/model/app_model.rb +0 -159
  86. data/examples/app_all_events/model/event_color_cycle.rb +0 -43
  87. data/examples/app_all_events/model/event_entry.rb +0 -94
  88. data/examples/app_all_events/model/msg.rb +0 -39
  89. data/examples/app_all_events/model/timestamp.rb +0 -56
  90. data/examples/app_all_events/update.rb +0 -75
  91. data/examples/app_all_events/view/app_view.rb +0 -80
  92. data/examples/app_all_events/view/controls_view.rb +0 -54
  93. data/examples/app_all_events/view/counts_view.rb +0 -61
  94. data/examples/app_all_events/view/live_view.rb +0 -72
  95. data/examples/app_all_events/view/log_view.rb +0 -57
  96. data/examples/app_all_events/view.rb +0 -9
  97. data/examples/app_cli_rich_moments/README.md +0 -81
  98. data/examples/app_cli_rich_moments/app.rb +0 -189
  99. data/examples/app_color_picker/README.md +0 -156
  100. data/examples/app_color_picker/app.rb +0 -76
  101. data/examples/app_color_picker/clipboard.rb +0 -86
  102. data/examples/app_color_picker/color.rb +0 -193
  103. data/examples/app_color_picker/controls.rb +0 -92
  104. data/examples/app_color_picker/copy_dialog.rb +0 -168
  105. data/examples/app_color_picker/export_pane.rb +0 -128
  106. data/examples/app_color_picker/harmony.rb +0 -58
  107. data/examples/app_color_picker/input.rb +0 -176
  108. data/examples/app_color_picker/main_container.rb +0 -180
  109. data/examples/app_color_picker/palette.rb +0 -111
  110. data/examples/app_debugging_showcase/README.md +0 -119
  111. data/examples/app_debugging_showcase/app.rb +0 -318
  112. data/examples/app_login_form/README.md +0 -58
  113. data/examples/app_login_form/app.rb +0 -109
  114. data/examples/app_stateful_interaction/README.md +0 -35
  115. data/examples/app_stateful_interaction/app.rb +0 -328
  116. data/examples/timeout_demo.rb +0 -45
  117. data/examples/verify_quickstart_dsl/README.md +0 -55
  118. data/examples/verify_quickstart_dsl/app.rb +0 -49
  119. data/examples/verify_quickstart_layout/README.md +0 -77
  120. data/examples/verify_quickstart_layout/app.rb +0 -73
  121. data/examples/verify_quickstart_lifecycle/README.md +0 -68
  122. data/examples/verify_quickstart_lifecycle/app.rb +0 -62
  123. data/examples/verify_readme_usage/README.md +0 -49
  124. data/examples/verify_readme_usage/app.rb +0 -42
  125. data/examples/verify_website_managed/README.md +0 -48
  126. data/examples/verify_website_managed/app.rb +0 -36
  127. data/examples/verify_website_menu/README.md +0 -60
  128. data/examples/verify_website_menu/app.rb +0 -84
  129. data/examples/verify_website_spinner/README.md +0 -44
  130. data/examples/verify_website_spinner/app.rb +0 -34
  131. data/examples/widget_barchart/README.md +0 -58
  132. data/examples/widget_barchart/app.rb +0 -240
  133. data/examples/widget_block/README.md +0 -44
  134. data/examples/widget_block/app.rb +0 -258
  135. data/examples/widget_box/README.md +0 -54
  136. data/examples/widget_box/app.rb +0 -255
  137. data/examples/widget_calendar/README.md +0 -48
  138. data/examples/widget_calendar/app.rb +0 -115
  139. data/examples/widget_canvas/README.md +0 -31
  140. data/examples/widget_canvas/app.rb +0 -130
  141. data/examples/widget_cell/README.md +0 -45
  142. data/examples/widget_cell/app.rb +0 -112
  143. data/examples/widget_center/README.md +0 -33
  144. data/examples/widget_center/app.rb +0 -118
  145. data/examples/widget_chart/README.md +0 -50
  146. data/examples/widget_chart/app.rb +0 -220
  147. data/examples/widget_gauge/README.md +0 -50
  148. data/examples/widget_gauge/app.rb +0 -229
  149. data/examples/widget_layout_split/README.md +0 -53
  150. data/examples/widget_layout_split/app.rb +0 -260
  151. data/examples/widget_line_gauge/README.md +0 -50
  152. data/examples/widget_line_gauge/app.rb +0 -219
  153. data/examples/widget_list/README.md +0 -58
  154. data/examples/widget_list/app.rb +0 -384
  155. data/examples/widget_map/README.md +0 -48
  156. data/examples/widget_map/app.rb +0 -95
  157. data/examples/widget_overlay/README.md +0 -45
  158. data/examples/widget_overlay/app.rb +0 -250
  159. data/examples/widget_popup/README.md +0 -45
  160. data/examples/widget_popup/app.rb +0 -106
  161. data/examples/widget_ratatui_logo/README.md +0 -43
  162. data/examples/widget_ratatui_logo/app.rb +0 -104
  163. data/examples/widget_ratatui_mascot/README.md +0 -43
  164. data/examples/widget_ratatui_mascot/app.rb +0 -95
  165. data/examples/widget_rect/README.md +0 -53
  166. data/examples/widget_rect/app.rb +0 -222
  167. data/examples/widget_render/README.md +0 -46
  168. data/examples/widget_render/app.rb +0 -186
  169. data/examples/widget_render/app.rbs +0 -41
  170. data/examples/widget_rich_text/README.md +0 -44
  171. data/examples/widget_rich_text/app.rb +0 -193
  172. data/examples/widget_scroll_text/README.md +0 -46
  173. data/examples/widget_scroll_text/app.rb +0 -109
  174. data/examples/widget_scrollbar/README.md +0 -46
  175. data/examples/widget_scrollbar/app.rb +0 -155
  176. data/examples/widget_sparkline/README.md +0 -51
  177. data/examples/widget_sparkline/app.rb +0 -277
  178. data/examples/widget_style_colors/README.md +0 -43
  179. data/examples/widget_style_colors/app.rb +0 -83
  180. data/examples/widget_table/README.md +0 -57
  181. data/examples/widget_table/app.rb +0 -279
  182. data/examples/widget_tabs/README.md +0 -50
  183. data/examples/widget_tabs/app.rb +0 -183
  184. data/examples/widget_text_width/README.md +0 -44
  185. data/examples/widget_text_width/app.rb +0 -117
  186. data/migrate_to_buffer.rb +0 -145
  187. data/mise.toml +0 -8
  188. data/tasks/autodoc/examples.rb +0 -87
  189. data/tasks/autodoc/member.rb +0 -58
  190. data/tasks/autodoc/name.rb +0 -21
  191. data/tasks/autodoc.rake +0 -21
  192. data/tasks/bump/cargo_lockfile.rb +0 -21
  193. data/tasks/bump/changelog.rb +0 -47
  194. data/tasks/bump/header.rb +0 -32
  195. data/tasks/bump/history.rb +0 -32
  196. data/tasks/bump/links.rb +0 -69
  197. data/tasks/bump/manifest.rb +0 -33
  198. data/tasks/bump/ruby_gem.rb +0 -49
  199. data/tasks/bump/sem_ver.rb +0 -40
  200. data/tasks/bump/unreleased_section.rb +0 -56
  201. data/tasks/bump.rake +0 -51
  202. data/tasks/doc.rake +0 -887
  203. data/tasks/example_viewer.html.erb +0 -172
  204. data/tasks/extension.rake +0 -14
  205. data/tasks/license/headers_md.rb +0 -223
  206. data/tasks/license/headers_rb.rb +0 -210
  207. data/tasks/license/license_utils.rb +0 -130
  208. data/tasks/license/snippets_md.rb +0 -315
  209. data/tasks/license/snippets_rdoc.rb +0 -150
  210. data/tasks/license.rake +0 -91
  211. data/tasks/lint.rake +0 -170
  212. data/tasks/rdoc_config.rb +0 -29
  213. data/tasks/resources/build.yml.erb +0 -60
  214. data/tasks/resources/index.html.erb +0 -141
  215. data/tasks/resources/rubies.yml +0 -7
  216. data/tasks/sourcehut.rake +0 -110
  217. data/tasks/steep.rake +0 -11
  218. data/tasks/terminal_preview/app_screenshot.rb +0 -45
  219. data/tasks/terminal_preview/crash_report.rb +0 -54
  220. data/tasks/terminal_preview/example_app.rb +0 -27
  221. data/tasks/terminal_preview/launcher_script.rb +0 -48
  222. data/tasks/terminal_preview/preview_collection.rb +0 -60
  223. data/tasks/terminal_preview/preview_timing.rb +0 -24
  224. data/tasks/terminal_preview/safety_confirmation.rb +0 -58
  225. data/tasks/terminal_preview/saved_screenshot.rb +0 -56
  226. data/tasks/terminal_preview/system_appearance.rb +0 -13
  227. data/tasks/terminal_preview/terminal_window.rb +0 -138
  228. data/tasks/terminal_preview/window_id.rb +0 -16
  229. data/tasks/terminal_preview.rake +0 -30
  230. data/tasks/test.rake +0 -33
  231. data/tasks/website/index_page.rb +0 -30
  232. data/tasks/website/version.rb +0 -127
  233. data/tasks/website/version_menu.rb +0 -68
  234. data/tasks/website/versioned_documentation.rb +0 -83
  235. data/tasks/website/website.rb +0 -53
  236. data/tasks/website.rake +0 -28
@@ -1,400 +0,0 @@
1
- <!--
2
- SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
3
- SPDX-License-Identifier: CC-BY-SA-4.0
4
- -->
5
-
6
- # Developing Examples
7
-
8
- Guidelines for creating and testing examples in the `examples/` directory.
9
-
10
- ## Example Structure
11
-
12
- Every interactive example should follow this pattern, living in its own directory:
13
-
14
- `examples/my_example/app.rb`:
15
- <!-- SPDX-SnippetBegin -->
16
- <!--
17
- SPDX-FileCopyrightText: 2025 Kerrick Long
18
- SPDX-License-Identifier: MIT-0
19
- -->
20
- ```ruby
21
- $LOAD_PATH.unshift File.expand_path("../../lib", __dir__)
22
- require "ratatui_ruby"
23
-
24
- class MyExampleApp
25
- def initialize
26
- # Initialize state (styles must be initialized in run when @tui is available)
27
- end
28
-
29
- def run
30
- RatatuiRuby.run do |tui|
31
- @tui = tui # Store for use in private methods
32
- loop do
33
- render
34
- break if handle_input == :quit
35
- end
36
- end
37
- end
38
-
39
- private
40
-
41
- def render
42
- @tui.draw do |frame|
43
- # 1. Split layout using Session helpers
44
- areas = @tui.layout_split(frame.area, constraints: [@tui.constraint_fill(1)])
45
- # 2. Create and render widgets
46
- widget = @tui.paragraph(text: "Hello", block: @tui.block(borders: [:all]))
47
- frame.render_widget(widget, areas[0])
48
- end
49
- end
50
-
51
- def handle_input
52
- case @tui.poll_event
53
- in { type: :key, code: "q" }
54
- :quit
55
- in { type: :key, code: code }
56
- # Handle other keys
57
- else
58
- # Ignore unhandled events
59
- end
60
- end
61
- end
62
-
63
- MyExampleApp.new.run if __FILE__ == $PROGRAM_NAME
64
- ```
65
- <!-- SPDX-SnippetEnd -->
66
-
67
- ### Naming Convention (Required)
68
-
69
- Example directories **must** follow a prefixing convention to categorize them alphabetically:
70
- - `app_`: Application showcases (e.g., `app_analytics`). Class name: `AppAnalytics`.
71
- - `widget_`: Widget-focused demonstrations (e.g., `widget_gauge`). Class name: `WidgetGaugeDemo`.
72
- - `verify_`: Documentation verification examples (e.g., `verify_readme_usage`). Class name: `VerifyReadmeUsage`.
73
-
74
- The directory and class names must match (snake_case directory maps to PascalCase class).
75
-
76
- This convention enables the `terminal_preview:update` rake task to automatically capture terminal output for all examples without maintaining a manual registry.
77
-
78
- ### Terminal Size Constraint
79
-
80
- All interactive examples must fit within an **80×24 terminal** (standard VT100 dimensions). This ensures:
81
- - Examples work on minimal terminal configurations
82
- - Tests can use the default `with_test_terminal` size (80x24)
83
- - Examples remain discoverable and self-documenting through visible hotkey help
84
-
85
- **Layout pattern for 80×24:**
86
- - **Bottom control panel:** Allocate ~5-7 lines at bottom for a full-width control block with hotkey documentation. Style hotkeys with **bold and underline** to make them discoverable. Use double-space or pipe separators to compress multiple controls per line. This keeps all UI text at full readability while maximizing space for the main content area.
87
-
88
- **Best practices:**
89
- - Use descriptive names (e.g., "Yellow on Black" not "Yellow") so controls are self-documenting and discoverable.
90
- - **Style hotkeys visually:** Use `modifiers: [:bold, :underlined]` on hotkey letters to make them stand out from descriptions. Example: `i` (bold, underlined) followed by `Items`.
91
- - Test early by running the example at 80×24 and verifying all content is visible without wrapping, scrolling, or clipping.
92
-
93
- ## Type Signatures
94
-
95
- Every example must also have an RBS file documenting its public methods. Type signatures live in a centralized location:
96
-
97
- `sig/examples/my_example/app.rbs`:
98
- <!-- SPDX-SnippetBegin -->
99
- <!--
100
- SPDX-FileCopyrightText: 2025 Kerrick Long
101
- SPDX-License-Identifier: MIT-0
102
- -->
103
- ```rbs
104
- class MyExampleApp
105
- # @public
106
- def self.new: () -> MyExampleApp
107
-
108
- # @public
109
- def run: () -> void
110
- end
111
- ```
112
- <!-- SPDX-SnippetEnd -->
113
-
114
- ## Directory Structure
115
-
116
- Examples are organized across three locations:
117
-
118
- <!-- SPDX-SnippetBegin -->
119
- <!--
120
- SPDX-FileCopyrightText: 2026 Kerrick Long
121
- SPDX-License-Identifier: MIT-0
122
- -->
123
- ```
124
- examples/
125
- my_example/
126
- app.rb ← REQUIRED: The runnable example code
127
- README.md ← REQUIRED: Purpose, architecture, hotkeys, usage
128
-
129
- test/examples/
130
- my_example/
131
- test_app.rb ← REQUIRED: Tests (centralized, not local to example)
132
- snapshots/ ← Auto-created by snapshot assertions
133
- initial_render.txt
134
-
135
- sig/examples/
136
- my_example/
137
- app.rbs ← REQUIRED: Type signatures (centralized, not local to example)
138
- ```
139
- <!-- SPDX-SnippetEnd -->
140
-
141
- ### Key Requirements
142
-
143
- 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.
144
-
145
- 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.
146
-
147
- 3. **Use the TUI API (`tui`) for cleaner code.** Accept the `tui` block parameter from `RatatuiRuby.run` and use it throughout your app:
148
- - `@tui.draw { |frame| ... }` instead of `RatatuiRuby.draw`
149
- - `@tui.poll_event` instead of `RatatuiRuby.poll_event`
150
- - `@tui.style(...)` instead of `RatatuiRuby::Style::Style.new(...)`
151
- - `@tui.paragraph(...)` instead of `RatatuiRuby::Widgets::Paragraph.new(...)`
152
- - `@tui.block(...)` instead of `RatatuiRuby::Widgets::Block.new(...)`
153
- - `@tui.layout_split(...)` instead of `RatatuiRuby::Layout.split(...)`
154
- - `@tui.constraint_fill(...)` instead of `RatatuiRuby::Layout::Constraint.fill(...)`
155
- - `@tui.text_line(...)` instead of `RatatuiRuby::Text::Line.new(...)`
156
- - `@tui.text_span(...)` instead of `RatatuiRuby::Text::Span.new(...)`
157
-
158
- 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`:
159
-
160
- ```ruby
161
- def handle_input
162
- case @tui.poll_event
163
- in { type: :key, code: "q" }
164
- :quit
165
- in { type: :mouse, kind: "down", x:, y: }
166
- handle_click(x, y)
167
- else
168
- # Ignore other events
169
- end
170
- end
171
-
172
- 5. **Use keyboard keys to cycle through widget attributes.** Users should be able to interactively explore all widget options. Common patterns:
173
- - Arrow keys: Navigate or adjust values
174
- - Letter keys: Cycle through styles, modes, or variants. Prefer all lowercase keys to avoid confusion and simplify the UI description.
175
- - Space: Toggle or select
176
- - `q` or Ctrl+C: Quit
177
-
178
- 6. **All examples must include a README.md** explaining:
179
- - What problem the example solves
180
- - Architecture (if applicable)
181
- - Hotkeys (if interactive): Document all keyboard/mouse controls
182
- - Key concepts demonstrated
183
- - Usage instructions
184
- - Learning outcomes
185
-
186
- See examples/app_color_picker/README.md and examples/app_all_events/README.md for patterns. Adhere to docs/contributors/documentation_style.md.
187
-
188
- 7. **Naming Conventions for Controls**
189
-
190
- When documenting hotkeys and cycling options in the UI, use consistent naming:
191
-
192
- - **Parameter names:** Always match the actual Ruby parameter name. For example:
193
- - Use "Scroll Padding" (not "Scroll Pad") for the `scroll_padding:` parameter
194
- - Use "Highlight Style" (not "Highlight") for the `highlight_style:` parameter
195
- - Use "Repeat Symbol" (not "Repeat") for the `repeat_highlight_symbol:` parameter
196
-
197
- - **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:
198
- ```ruby
199
- # In run method, after @tui = tui:
200
- @styles = [
201
- { name: "Yellow Bold", style: @tui.style(fg: :yellow, modifiers: [:bold]) },
202
- { name: "Blue on White", style: @tui.style(fg: :blue, bg: :white) }
203
- ]
204
-
205
- # In controls: "h: Highlight Style (#{@styles[@style_index][:name]})"
206
- # Outputs: "h: Highlight Style (Yellow Bold)"
207
- ```
208
-
209
- This keeps the UI self-documenting and users can see exact parameter names when they read the hotkey help.
210
-
211
- 8. **Hit Testing**
212
-
213
- 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:
214
-
215
- <!-- SPDX-SnippetBegin -->
216
- <!--
217
- SPDX-FileCopyrightText: 2025 Kerrick Long
218
- SPDX-License-Identifier: MIT-0
219
- -->
220
- ```ruby
221
- if @sidebar_rect&.contains?(event.x, event.y)
222
- # Handle click
223
- end
224
- ```
225
- <!-- SPDX-SnippetEnd -->
226
-
227
- ## Testing Examples
228
-
229
- Example tests live in a centralized test tree:
230
-
231
- `test/examples/my_example/test_app.rb`:
232
- <!-- SPDX-SnippetBegin -->
233
- <!--
234
- SPDX-FileCopyrightText: 2026 Kerrick Long
235
- SPDX-License-Identifier: MIT-0
236
- -->
237
- ```ruby
238
- $LOAD_PATH.unshift File.expand_path("../../lib", __dir__)
239
- require "ratatui_ruby"
240
- require "ratatui_ruby/test_helper"
241
- require "minitest/autorun"
242
- require_relative "app"
243
-
244
- class TestMyExampleApp < Minitest::Test
245
- include RatatuiRuby::TestHelper
246
-
247
- def setup
248
- @app = MyExampleApp.new
249
- end
250
-
251
- def test_initial_render
252
- with_test_terminal do
253
- inject_key(:q)
254
- @app.run
255
- assert_snapshots("initial_render")
256
- end
257
- end
258
- end
259
- ```
260
- <!-- SPDX-SnippetEnd -->
261
-
262
- ## Snapshot Testing Pattern (REQUIRED)
263
-
264
- All example tests MUST use snapshot testing via the `assert_snapshots` API, not manual content assertions.
265
-
266
- ### Why Snapshots
267
-
268
- - **Exact verification:** Captures complete screen state, character-by-character
269
- - **Auto-update:** `UPDATE_SNAPSHOTS=1 bin/agent_rake test` regenerates all snapshots
270
- - **Auto-managed:** Snapshots live in `test/examples/{name}/snapshots/{test_name}.txt`
271
- - **Maintainable:** No tedious manual string checks
272
- - **Self-documenting:** Snapshots show exactly what output is expected
273
-
274
- ### Basic Pattern
275
-
276
- <!-- SPDX-SnippetBegin -->
277
- <!--
278
- SPDX-FileCopyrightText: 2026 Kerrick Long
279
- SPDX-License-Identifier: MIT-0
280
- -->
281
- ```ruby
282
- def test_initial_render
283
- with_test_terminal do
284
- inject_key(:q)
285
- @app.run
286
-
287
- assert_snapshots("initial_render")
288
- end
289
- end
290
- ```
291
- <!-- SPDX-SnippetEnd -->
292
-
293
- Snapshot auto-saved to: `test/examples/widget_foo/snapshots/initial_render.txt`
294
-
295
- ### With Normalization (for dynamic content)
296
-
297
- For examples with timestamps, random data, or other non-deterministic output:
298
-
299
- <!-- SPDX-SnippetBegin -->
300
- <!--
301
- SPDX-FileCopyrightText: 2026 Kerrick Long
302
- SPDX-License-Identifier: MIT-0
303
- -->
304
- ```ruby
305
- private def assert_normalized_snapshots(snapshot_name)
306
- assert_plain_snapshot(snapshot_name) do |actual|
307
- actual.map do |line|
308
- line.gsub(/\d{2}:\d{2}:\d{2}/, "XX:XX:XX") # Mask timestamps
309
- .gsub(/Random ID: \d+/, "Random ID: XXX") # Mask random values
310
- end
311
- end
312
- end
313
-
314
- def test_after_event
315
- with_test_terminal do
316
- inject_key("a")
317
- inject_key(:q)
318
- @app.run
319
-
320
- assert_normalized_snapshots("after_event")
321
- end
322
- end
323
- ```
324
- <!-- SPDX-SnippetEnd -->
325
-
326
- See `test/examples/app_all_events/test_app.rb` for a complete example.
327
-
328
- ### Regenerating Snapshots
329
-
330
- When UI changes are intentional, regenerate all snapshots:
331
-
332
- <!-- SPDX-SnippetBegin -->
333
- <!--
334
- SPDX-FileCopyrightText: 2026 Kerrick Long
335
- SPDX-License-Identifier: MIT-0
336
- -->
337
- ```bash
338
- UPDATE_SNAPSHOTS=1 bin/agent_rake test
339
- ```
340
- <!-- SPDX-SnippetEnd -->
341
-
342
- ## Widget Attribute Cycling
343
-
344
- Examples should demonstrate widget configurability by allowing interactive cycling:
345
-
346
- | Widget | Attribute | Key Suggestion |
347
- |--------|-----------|----------------|
348
- | Tabs | highlight_style | Space |
349
- | Tabs | divider | d |
350
- | Tabs | style | s |
351
- | Block | border_type | Space |
352
- | Block | border_color | c |
353
- | List | highlight_style | Space |
354
- | Sparkline | direction | d |
355
- | Scrollbar | orientation | o |
356
- | Scrollbar | theme | s |
357
-
358
- 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.
359
-
360
- ## Data Quality
361
-
362
- Examples must use **realistic, meaningful data**—not dummy placeholder text. This ensures examples:
363
- - Demonstrate the widget's real-world usage
364
- - Provide educational value to users reading the code
365
- - Look professional and polished
366
-
367
- ### Guidelines
368
-
369
- **For small datasets (< 10 items):**
370
- Use hardcoded realistic data. Examples:
371
- - Geographic coordinates with city names (see `widget_map/app.rb`)
372
- - Real product names or person names
373
- - Meaningful status values ("Completed", "Pending", "Failed")
374
-
375
- **For large datasets (≥ 10 items):**
376
- Use the [Faker](https://github.com/faker-ruby/faker) gem with **deterministic seeding** so data is consistent across runs:
377
-
378
- <!-- SPDX-SnippetBegin -->
379
- <!--
380
- SPDX-FileCopyrightText: 2026 Kerrick Long
381
- SPDX-License-Identifier: MIT-0
382
- -->
383
- ```ruby
384
- require "faker"
385
-
386
- # Seed Faker for reproducible output
387
- Faker::Config.random = Random.new(12345)
388
-
389
- # Generate realistic data
390
- users = Array.new(50) { Faker::Name.name }
391
- emails = Array.new(50) { Faker::Internet.email }
392
- ```
393
- <!-- SPDX-SnippetEnd -->
394
-
395
- In tests, set the same seed before each test to ensure snapshot consistency.
396
-
397
- **Avoid:**
398
- - Repeated placeholder text like "Lorem ipsum" or "Background Layer" × 20
399
- - Generic numbered items like "Item 1", "Item 2" (unless the context demands it)
400
- - Nonsensical or visually jarring content
@@ -1,121 +0,0 @@
1
- <!--
2
- SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
3
- SPDX-License-Identifier: CC-BY-SA-4.0
4
- -->
5
-
6
- # Documentation Style Guide
7
-
8
- 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
-
10
- **All agents and contributors must adhere to these standards.**
11
-
12
- ## 1. Core Philosophy
13
-
14
- * **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.
15
- * **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.
16
- * **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.
17
- * **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."
18
-
19
- ## 2. Class Documentation
20
-
21
- Every public class must begin with a **Context-Problem-Solution** narrative.
22
-
23
- ### Structure
24
-
25
- 1. **Summary Line:** A single line explaining the class's role.
26
- 2. **Context (Narrative):** A short paragraph establishing the domain or situation.
27
- 3. **Problem (Narrative):** A sentence or two identifying the specific difficulty, complexity, or "pain" the user faces in this context without the widget.
28
- 4. **Solution (Narrative):** A sentence explaining how this widget solves that problem, often starting with "This widget..." or "Use it to...".
29
- 5. **Usage (Narrative):** A concrete "Use it to..." sentence listing common applications.
30
- 6. **Example:** A comprehensive, copy-pasteable code example using `=== Examples`. Provide **multiple** examples to cover different use cases (e.g., basic usage vs. advanced configuration).
31
-
32
- ### Example
33
-
34
- **Bad (Generic/Descriptive):**
35
- <!-- SPDX-SnippetBegin -->
36
- <!--
37
- SPDX-FileCopyrightText: 2025 Kerrick Long
38
- SPDX-License-Identifier: MIT-0
39
- -->
40
- ```ruby
41
- # A widget for displaying list items.
42
- # It allows the user to select an item from an array of strings.
43
- # Supports scrolling and custom styling.
44
- ```
45
- <!-- SPDX-SnippetEnd -->
46
-
47
- **Good (Alexandrian/Zinsser/Plain Language):**
48
- <!-- SPDX-SnippetBegin -->
49
- <!--
50
- SPDX-FileCopyrightText: 2025 Kerrick Long
51
- SPDX-License-Identifier: MIT-0
52
- -->
53
- ```ruby
54
- # Displays a selectable list of items.
55
- #
56
- # Users need to choose from options. Menus, file explorers, and selectors are everywhere.
57
- # Implementing navigation, highlighting, and scrolling state from scratch is tedious.
58
- #
59
- # This widget manages the list. It renders the items. It highlights the selection. It handles the scrolling window.
60
- #
61
- # Use it to build main menus, navigation sidebars, or logs.
62
- ```
63
- <!-- SPDX-SnippetEnd -->
64
-
65
- ## 3. Method and Attribute Documentation
66
-
67
- ### Prose Style
68
-
69
- * **Attributes:** Use concise noun phrases. Avoid "This attribute returns..." or "Getter for...".
70
- * *Bad:* "This is the width of the widget."
71
- * *Good:* "Width of the widget in cells."
72
- * **Methods:** Use active, third-person present tense verbs.
73
- * *Bad:* "Will calculate the total."
74
- * *Good:* "Calculates the total."
75
- * **Context:** For complex methods, you may use a condensed version of the Context-Problem-Solution pattern, but keep it brief.
76
-
77
- ### Syntax Standards
78
-
79
- * **Examples:** All public methods must include at least one usage example. Use `=== Example`.
80
- * **Attributes:** Use `attr_reader` with documentation comments immediately preceding them.
81
- * **Parameters:** Use strict RDoc definition lists `[name] description` for parameters in the `initialize` method.
82
- * **Formatting:** Use `<tt>` tags for code literals, symbols, and values (e.g., `<tt>:vertical</tt>`).
83
- * Do **not** use backticks (\`) or markdown-style links `[text](url)`. RDoc does not render them correctly in all contexts.
84
- * Do **not** use smart quotes.
85
-
86
- ### Example
87
-
88
- <!-- SPDX-SnippetBegin -->
89
- <!--
90
- SPDX-FileCopyrightText: 2025 Kerrick Long
91
- SPDX-License-Identifier: MIT-0
92
- -->
93
- ```ruby
94
- # The styling to apply to the content.
95
- attr_reader :style
96
-
97
- # Creates a new List.
98
- #
99
- # [items] Array of Strings.
100
- # [selected_index] Integer (nullable).
101
- def initialize(items: [], selected_index: nil)
102
- super
103
- end
104
- ```
105
- <!-- SPDX-SnippetEnd -->
106
-
107
- ## 4. RDoc Specifics
108
-
109
- * **No Endless Methods:** Do **not** use Ruby 3.0+ endless method definitions (`def foo = bar`). RDoc currently has a bug where it fails to correctly parse the end of the method, causing subsequent methods to be nested incorrectly in the documentation tree. Always use standard `def ... end` blocks.
110
- * **No YARD:** Do not use `@param`, `@return`, or other YARD tags. Use standard RDoc formats.
111
- * **Directives:** Use `:nodoc:` for private or internal methods that should not appear in the API docs.
112
- * **Headings:** Use `===` for section headers like `=== Examples`.
113
-
114
- ## 5. Checklist for Agents
115
-
116
- Before finalizing documentation, ask:
117
- 1. Did I explain the *problem* this code solves?
118
- 2. Are my sentences short and active? (Did I remove "allows the user to"?)
119
- 3. Is the code example valid and copy-pasteable?
120
- 4. Did I use `<tt>` for symbols and code values?
121
- 5. Did I document every attribute and parameter?
@@ -1,21 +0,0 @@
1
- <!--
2
- SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
3
- SPDX-License-Identifier: CC-BY-SA-4.0
4
- -->
5
- # **ratatui_ruby** Contributors’ Documentation
6
-
7
-
8
- ## Documentation for Contributors
9
-
10
- - [Contributing Guidelines](https://man.sr.ht/~kerrick/ratatui_ruby/contributing.md): Issues, pull requests, and development setup
11
- - [Documentation Guide](https://man.sr.ht/~kerrick/ratatui_ruby/documentation_guide.md): Where to document (RDoc, repo docs, wiki)
12
- - [The Design of **ratatui_ruby**](./design.md): Architecture overview
13
- - [Ruby Frontend Design](./design/ruby_frontend.md): Two-layer architecture, TUI facade, data-driven UI
14
- - [Rust Backend Design](./design/rust_backend.md): Rendering pipeline, namespace dispatch, magnus integration
15
-
16
-
17
-
18
- ## Documentation for Users
19
-
20
- - [README](../../README.md): Project overview and installation
21
- - [More Documentation for Users](../index.md): Full user documentation index