ratatui_ruby 0.9.0 → 0.10.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.
- checksums.yaml +4 -4
- data/.builds/ruby-3.2.yml +1 -1
- data/.builds/ruby-3.3.yml +1 -1
- data/.builds/ruby-3.4.yml +1 -1
- data/.builds/ruby-4.0.0.yml +1 -1
- data/AGENTS.md +2 -1
- data/CHANGELOG.md +122 -0
- data/REUSE.toml +5 -0
- data/Rakefile +1 -1
- data/Steepfile +49 -0
- data/doc/concepts/debugging.md +401 -0
- data/doc/getting_started/quickstart.md +8 -3
- data/doc/images/app_all_events.png +0 -0
- data/doc/images/app_color_picker.png +0 -0
- data/doc/images/app_debugging_showcase.gif +0 -0
- data/doc/images/app_debugging_showcase.png +0 -0
- data/doc/images/app_login_form.png +0 -0
- data/doc/images/app_stateful_interaction.png +0 -0
- data/doc/images/verify_quickstart_dsl.png +0 -0
- data/doc/images/verify_quickstart_layout.png +0 -0
- data/doc/images/verify_quickstart_lifecycle.png +0 -0
- data/doc/images/verify_readme_usage.png +0 -0
- data/doc/images/widget_barchart.png +0 -0
- data/doc/images/widget_block.png +0 -0
- data/doc/images/widget_box.png +0 -0
- data/doc/images/widget_calendar.png +0 -0
- data/doc/images/widget_canvas.png +0 -0
- data/doc/images/widget_cell.png +0 -0
- data/doc/images/widget_center.png +0 -0
- data/doc/images/widget_chart.png +0 -0
- data/doc/images/widget_gauge.png +0 -0
- data/doc/images/widget_layout_split.png +0 -0
- data/doc/images/widget_line_gauge.png +0 -0
- data/doc/images/widget_list.png +0 -0
- data/doc/images/widget_map.png +0 -0
- data/doc/images/widget_overlay.png +0 -0
- data/doc/images/widget_popup.png +0 -0
- data/doc/images/widget_ratatui_logo.png +0 -0
- data/doc/images/widget_ratatui_mascot.png +0 -0
- data/doc/images/widget_rect.png +0 -0
- data/doc/images/widget_render.png +0 -0
- data/doc/images/widget_rich_text.png +0 -0
- data/doc/images/widget_scroll_text.png +0 -0
- data/doc/images/widget_scrollbar.png +0 -0
- data/doc/images/widget_sparkline.png +0 -0
- data/doc/images/widget_style_colors.png +0 -0
- data/doc/images/widget_table.png +0 -0
- data/doc/images/widget_tabs.png +0 -0
- data/doc/images/widget_text_width.png +0 -0
- data/doc/troubleshooting/async.md +4 -0
- data/examples/app_debugging_showcase/README.md +119 -0
- data/examples/app_debugging_showcase/app.rb +318 -0
- data/examples/widget_canvas/app.rb +19 -14
- data/examples/widget_gauge/app.rb +18 -3
- data/examples/widget_layout_split/app.rb +16 -4
- data/examples/widget_list/app.rb +22 -6
- data/examples/widget_rect/app.rb +7 -6
- data/examples/widget_rich_text/app.rb +62 -37
- data/examples/widget_style_colors/app.rb +26 -47
- data/examples/widget_table/app.rb +28 -5
- data/examples/widget_text_width/app.rb +6 -4
- data/ext/ratatui_ruby/Cargo.lock +48 -1
- data/ext/ratatui_ruby/Cargo.toml +6 -2
- data/ext/ratatui_ruby/src/color.rs +82 -0
- data/ext/ratatui_ruby/src/errors.rs +28 -0
- data/ext/ratatui_ruby/src/events.rs +16 -14
- data/ext/ratatui_ruby/src/lib.rs +56 -0
- data/ext/ratatui_ruby/src/rendering.rs +3 -1
- data/ext/ratatui_ruby/src/style.rs +48 -21
- data/ext/ratatui_ruby/src/terminal.rs +40 -9
- data/ext/ratatui_ruby/src/text.rs +21 -9
- data/ext/ratatui_ruby/src/widgets/chart.rs +2 -1
- data/ext/ratatui_ruby/src/widgets/layout.rs +90 -2
- data/ext/ratatui_ruby/src/widgets/list.rs +6 -5
- data/ext/ratatui_ruby/src/widgets/overlay.rs +2 -1
- data/ext/ratatui_ruby/src/widgets/table.rs +7 -6
- data/ext/ratatui_ruby/src/widgets/table_state.rs +55 -0
- data/ext/ratatui_ruby/src/widgets/tabs.rs +3 -2
- data/lib/ratatui_ruby/buffer/cell.rb +25 -15
- data/lib/ratatui_ruby/buffer.rb +134 -2
- data/lib/ratatui_ruby/cell.rb +13 -5
- data/lib/ratatui_ruby/debug.rb +215 -0
- data/lib/ratatui_ruby/event/key.rb +3 -2
- data/lib/ratatui_ruby/event/sync.rb +52 -0
- data/lib/ratatui_ruby/event.rb +7 -1
- data/lib/ratatui_ruby/layout/constraint.rb +184 -0
- data/lib/ratatui_ruby/layout/layout.rb +119 -13
- data/lib/ratatui_ruby/layout/position.rb +55 -0
- data/lib/ratatui_ruby/layout/rect.rb +188 -0
- data/lib/ratatui_ruby/layout/size.rb +55 -0
- data/lib/ratatui_ruby/layout.rb +4 -0
- data/lib/ratatui_ruby/style/color.rb +149 -0
- data/lib/ratatui_ruby/style/style.rb +51 -4
- data/lib/ratatui_ruby/style.rb +2 -0
- data/lib/ratatui_ruby/symbols.rb +435 -0
- data/lib/ratatui_ruby/synthetic_events.rb +86 -0
- data/lib/ratatui_ruby/table_state.rb +51 -0
- data/lib/ratatui_ruby/terminal_lifecycle.rb +2 -1
- data/lib/ratatui_ruby/test_helper/event_injection.rb +34 -1
- data/lib/ratatui_ruby/test_helper.rb +9 -0
- data/lib/ratatui_ruby/text/line.rb +245 -0
- data/lib/ratatui_ruby/text/span.rb +158 -0
- data/lib/ratatui_ruby/text.rb +99 -0
- data/lib/ratatui_ruby/tui/canvas_factories.rb +103 -0
- data/lib/ratatui_ruby/tui/core.rb +13 -2
- data/lib/ratatui_ruby/tui/layout_factories.rb +50 -3
- data/lib/ratatui_ruby/tui/state_factories.rb +42 -0
- data/lib/ratatui_ruby/tui/text_factories.rb +40 -0
- data/lib/ratatui_ruby/tui/widget_factories.rb +135 -60
- data/lib/ratatui_ruby/tui.rb +22 -1
- data/lib/ratatui_ruby/version.rb +1 -1
- data/lib/ratatui_ruby/widgets/bar_chart/bar.rb +2 -0
- data/lib/ratatui_ruby/widgets/bar_chart/bar_group.rb +2 -0
- data/lib/ratatui_ruby/widgets/bar_chart.rb +30 -20
- data/lib/ratatui_ruby/widgets/block.rb +14 -6
- data/lib/ratatui_ruby/widgets/calendar.rb +2 -0
- data/lib/ratatui_ruby/widgets/canvas.rb +56 -0
- data/lib/ratatui_ruby/widgets/cell.rb +2 -0
- data/lib/ratatui_ruby/widgets/center.rb +2 -0
- data/lib/ratatui_ruby/widgets/chart.rb +6 -0
- data/lib/ratatui_ruby/widgets/clear.rb +2 -0
- data/lib/ratatui_ruby/widgets/coerceable_widget.rb +77 -0
- data/lib/ratatui_ruby/widgets/cursor.rb +2 -0
- data/lib/ratatui_ruby/widgets/gauge.rb +61 -3
- data/lib/ratatui_ruby/widgets/line_gauge.rb +66 -4
- data/lib/ratatui_ruby/widgets/list.rb +87 -3
- data/lib/ratatui_ruby/widgets/list_item.rb +2 -0
- data/lib/ratatui_ruby/widgets/overlay.rb +2 -0
- data/lib/ratatui_ruby/widgets/paragraph.rb +4 -0
- data/lib/ratatui_ruby/widgets/ratatui_logo.rb +2 -0
- data/lib/ratatui_ruby/widgets/ratatui_mascot.rb +2 -0
- data/lib/ratatui_ruby/widgets/row.rb +45 -0
- data/lib/ratatui_ruby/widgets/scrollbar.rb +2 -0
- data/lib/ratatui_ruby/widgets/shape/label.rb +2 -0
- data/lib/ratatui_ruby/widgets/sparkline.rb +21 -13
- data/lib/ratatui_ruby/widgets/table.rb +13 -3
- data/lib/ratatui_ruby/widgets/tabs.rb +6 -4
- data/lib/ratatui_ruby/widgets.rb +1 -0
- data/lib/ratatui_ruby.rb +51 -16
- data/sig/examples/app_all_events/model/app_model.rbs +23 -0
- data/sig/examples/app_all_events/model/event_entry.rbs +15 -8
- data/sig/examples/app_all_events/model/timestamp.rbs +1 -1
- data/sig/examples/app_all_events/view.rbs +1 -1
- data/sig/examples/app_stateful_interaction/app.rbs +5 -5
- data/sig/examples/widget_block_demo/app.rbs +6 -6
- data/sig/manifest.yaml +5 -0
- data/sig/patches/data.rbs +26 -0
- data/sig/patches/debugger__.rbs +8 -0
- data/sig/ratatui_ruby/buffer/cell.rbs +46 -0
- data/sig/ratatui_ruby/buffer.rbs +18 -0
- data/sig/ratatui_ruby/cell.rbs +44 -0
- data/sig/ratatui_ruby/clear.rbs +18 -0
- data/sig/ratatui_ruby/constraint.rbs +26 -0
- data/sig/ratatui_ruby/debug.rbs +45 -0
- data/sig/ratatui_ruby/draw.rbs +30 -0
- data/sig/ratatui_ruby/event.rbs +68 -8
- data/sig/ratatui_ruby/frame.rbs +4 -4
- data/sig/ratatui_ruby/interfaces.rbs +25 -0
- data/sig/ratatui_ruby/layout/constraint.rbs +39 -0
- data/sig/ratatui_ruby/layout/layout.rbs +45 -0
- data/sig/ratatui_ruby/layout/position.rbs +18 -0
- data/sig/ratatui_ruby/layout/rect.rbs +64 -0
- data/sig/ratatui_ruby/layout/size.rbs +18 -0
- data/sig/ratatui_ruby/output_guard.rbs +23 -0
- data/sig/ratatui_ruby/ratatui_ruby.rbs +83 -4
- data/sig/ratatui_ruby/rect.rbs +17 -0
- data/sig/ratatui_ruby/style/color.rbs +22 -0
- data/sig/ratatui_ruby/style/style.rbs +29 -0
- data/sig/ratatui_ruby/symbols.rbs +141 -0
- data/sig/ratatui_ruby/synthetic_events.rbs +21 -0
- data/sig/ratatui_ruby/table_state.rbs +6 -0
- data/sig/ratatui_ruby/terminal_lifecycle.rbs +31 -0
- data/sig/ratatui_ruby/test_helper/event_injection.rbs +2 -2
- data/sig/ratatui_ruby/test_helper/snapshot.rbs +22 -3
- data/sig/ratatui_ruby/test_helper/style_assertions.rbs +8 -1
- data/sig/ratatui_ruby/test_helper/test_doubles.rbs +7 -3
- data/sig/ratatui_ruby/text/line.rbs +27 -0
- data/sig/ratatui_ruby/text/span.rbs +23 -0
- data/sig/ratatui_ruby/text.rbs +12 -0
- data/sig/ratatui_ruby/tui/buffer_factories.rbs +1 -1
- data/sig/ratatui_ruby/tui/canvas_factories.rbs +23 -5
- data/sig/ratatui_ruby/tui/core.rbs +2 -2
- data/sig/ratatui_ruby/tui/layout_factories.rbs +16 -2
- data/sig/ratatui_ruby/tui/state_factories.rbs +8 -3
- data/sig/ratatui_ruby/tui/style_factories.rbs +3 -1
- data/sig/ratatui_ruby/tui/text_factories.rbs +7 -4
- data/sig/ratatui_ruby/tui/widget_factories.rbs +123 -30
- data/sig/ratatui_ruby/widgets/bar_chart.rbs +95 -0
- data/sig/ratatui_ruby/widgets/block.rbs +51 -0
- data/sig/ratatui_ruby/widgets/calendar.rbs +45 -0
- data/sig/ratatui_ruby/widgets/canvas.rbs +95 -0
- data/sig/ratatui_ruby/widgets/chart.rbs +91 -0
- data/sig/ratatui_ruby/widgets/coerceable_widget.rbs +26 -0
- data/sig/ratatui_ruby/widgets/gauge.rbs +44 -0
- data/sig/ratatui_ruby/widgets/line_gauge.rbs +48 -0
- data/sig/ratatui_ruby/widgets/list.rbs +63 -0
- data/sig/ratatui_ruby/widgets/misc.rbs +158 -0
- data/sig/ratatui_ruby/widgets/paragraph.rbs +45 -0
- data/sig/ratatui_ruby/widgets/row.rbs +43 -0
- data/sig/ratatui_ruby/widgets/scrollbar.rbs +53 -0
- data/sig/ratatui_ruby/widgets/shape/label.rbs +37 -0
- data/sig/ratatui_ruby/widgets/sparkline.rbs +45 -0
- data/sig/ratatui_ruby/widgets/table.rbs +78 -0
- data/sig/ratatui_ruby/widgets/tabs.rbs +44 -0
- data/sig/ratatui_ruby/{schema/list_item.rbs → widgets.rbs} +4 -4
- data/tasks/steep.rake +11 -0
- metadata +82 -63
- data/doc/contributors/v1.0.0_blockers.md +0 -876
- data/doc/troubleshooting/debugging.md +0 -101
- data/lib/ratatui_ruby/schema/bar_chart/bar.rb +0 -47
- data/lib/ratatui_ruby/schema/bar_chart/bar_group.rb +0 -25
- data/lib/ratatui_ruby/schema/bar_chart.rb +0 -287
- data/lib/ratatui_ruby/schema/block.rb +0 -198
- data/lib/ratatui_ruby/schema/calendar.rb +0 -84
- data/lib/ratatui_ruby/schema/canvas.rb +0 -239
- data/lib/ratatui_ruby/schema/center.rb +0 -67
- data/lib/ratatui_ruby/schema/chart.rb +0 -159
- data/lib/ratatui_ruby/schema/clear.rb +0 -62
- data/lib/ratatui_ruby/schema/constraint.rb +0 -151
- data/lib/ratatui_ruby/schema/cursor.rb +0 -50
- data/lib/ratatui_ruby/schema/gauge.rb +0 -72
- data/lib/ratatui_ruby/schema/layout.rb +0 -122
- data/lib/ratatui_ruby/schema/line_gauge.rb +0 -80
- data/lib/ratatui_ruby/schema/list.rb +0 -135
- data/lib/ratatui_ruby/schema/list_item.rb +0 -51
- data/lib/ratatui_ruby/schema/overlay.rb +0 -51
- data/lib/ratatui_ruby/schema/paragraph.rb +0 -107
- data/lib/ratatui_ruby/schema/ratatui_logo.rb +0 -31
- data/lib/ratatui_ruby/schema/ratatui_mascot.rb +0 -36
- data/lib/ratatui_ruby/schema/rect.rb +0 -174
- data/lib/ratatui_ruby/schema/row.rb +0 -76
- data/lib/ratatui_ruby/schema/scrollbar.rb +0 -143
- data/lib/ratatui_ruby/schema/shape/label.rb +0 -76
- data/lib/ratatui_ruby/schema/sparkline.rb +0 -142
- data/lib/ratatui_ruby/schema/style.rb +0 -97
- data/lib/ratatui_ruby/schema/table.rb +0 -141
- data/lib/ratatui_ruby/schema/tabs.rb +0 -85
- data/lib/ratatui_ruby/schema/text.rb +0 -217
- data/sig/examples/app_all_events/model/events.rbs +0 -15
- data/sig/examples/app_all_events/view_state.rbs +0 -21
- data/sig/ratatui_ruby/schema/bar_chart/bar.rbs +0 -22
- data/sig/ratatui_ruby/schema/bar_chart/bar_group.rbs +0 -19
- data/sig/ratatui_ruby/schema/bar_chart.rbs +0 -38
- data/sig/ratatui_ruby/schema/block.rbs +0 -18
- data/sig/ratatui_ruby/schema/calendar.rbs +0 -23
- data/sig/ratatui_ruby/schema/canvas.rbs +0 -81
- data/sig/ratatui_ruby/schema/center.rbs +0 -17
- data/sig/ratatui_ruby/schema/chart.rbs +0 -39
- data/sig/ratatui_ruby/schema/constraint.rbs +0 -22
- data/sig/ratatui_ruby/schema/cursor.rbs +0 -16
- data/sig/ratatui_ruby/schema/draw.rbs +0 -33
- data/sig/ratatui_ruby/schema/gauge.rbs +0 -23
- data/sig/ratatui_ruby/schema/layout.rbs +0 -27
- data/sig/ratatui_ruby/schema/line_gauge.rbs +0 -24
- data/sig/ratatui_ruby/schema/list.rbs +0 -28
- data/sig/ratatui_ruby/schema/overlay.rbs +0 -15
- data/sig/ratatui_ruby/schema/paragraph.rbs +0 -20
- data/sig/ratatui_ruby/schema/ratatui_logo.rbs +0 -14
- data/sig/ratatui_ruby/schema/ratatui_mascot.rbs +0 -17
- data/sig/ratatui_ruby/schema/rect.rbs +0 -48
- data/sig/ratatui_ruby/schema/row.rbs +0 -28
- data/sig/ratatui_ruby/schema/scrollbar.rbs +0 -42
- data/sig/ratatui_ruby/schema/sparkline.rbs +0 -22
- data/sig/ratatui_ruby/schema/style.rbs +0 -19
- data/sig/ratatui_ruby/schema/table.rbs +0 -32
- data/sig/ratatui_ruby/schema/tabs.rbs +0 -21
- data/sig/ratatui_ruby/schema/text.rbs +0 -31
- /data/lib/ratatui_ruby/{schema/draw.rb → draw.rb} +0 -0
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
<!--
|
|
2
|
-
SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
|
|
3
|
-
SPDX-License-Identifier: CC-BY-SA-4.0
|
|
4
|
-
-->
|
|
5
|
-
|
|
6
|
-
# Debugging TUI Applications
|
|
7
|
-
|
|
8
|
-
TUI applications run in raw terminal mode. stderr and stdout carry terminal escape sequences. Using `puts` or `warn` inside the render loop corrupts the display.
|
|
9
|
-
|
|
10
|
-
This creates a problem: how do you inspect variables and trace execution?
|
|
11
|
-
|
|
12
|
-
Write debug output to files. Tail them in a separate terminal.
|
|
13
|
-
|
|
14
|
-
## File-Based Logging
|
|
15
|
-
|
|
16
|
-
Create timestamped log files to avoid overwrites:
|
|
17
|
-
|
|
18
|
-
<!-- SPDX-SnippetBegin -->
|
|
19
|
-
<!--
|
|
20
|
-
SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
21
|
-
SPDX-License-Identifier: MIT-0
|
|
22
|
-
-->
|
|
23
|
-
```ruby
|
|
24
|
-
FileUtils.mkdir_p(File.join(Dir.tmpdir, "my_debug"))
|
|
25
|
-
timestamp = Time.now.strftime('%Y%m%d_%H%M%S_%N')
|
|
26
|
-
File.write(
|
|
27
|
-
File.join(Dir.tmpdir, "my_debug", "#{timestamp}.log"),
|
|
28
|
-
"variable=#{value.inspect}\n"
|
|
29
|
-
)
|
|
30
|
-
```
|
|
31
|
-
<!-- SPDX-SnippetEnd -->
|
|
32
|
-
|
|
33
|
-
Or append to a single file:
|
|
34
|
-
|
|
35
|
-
<!-- SPDX-SnippetBegin -->
|
|
36
|
-
<!--
|
|
37
|
-
SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
38
|
-
SPDX-License-Identifier: MIT-0
|
|
39
|
-
-->
|
|
40
|
-
```ruby
|
|
41
|
-
File.write("/tmp/debug.log", "#{Time.now}: #{message}\n", mode: "a")
|
|
42
|
-
```
|
|
43
|
-
<!-- SPDX-SnippetEnd -->
|
|
44
|
-
|
|
45
|
-
Tail the logs in a separate terminal:
|
|
46
|
-
|
|
47
|
-
<!-- SPDX-SnippetBegin -->
|
|
48
|
-
<!--
|
|
49
|
-
SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
50
|
-
SPDX-License-Identifier: MIT-0
|
|
51
|
-
-->
|
|
52
|
-
```bash
|
|
53
|
-
# Single file
|
|
54
|
-
tail -f /tmp/debug.log
|
|
55
|
-
|
|
56
|
-
# Directory of timestamped files
|
|
57
|
-
watch -n 0.5 'ls -la /tmp/my_debug/ && cat /tmp/my_debug/*.log'
|
|
58
|
-
```
|
|
59
|
-
<!-- SPDX-SnippetEnd -->
|
|
60
|
-
|
|
61
|
-
## REPL Debugging with `__FILE__` Guards
|
|
62
|
-
|
|
63
|
-
Unit tests verify correctness. But during exploratory debugging, you want to poke at objects interactively. Loading the full TUI just to inspect one object is slow.
|
|
64
|
-
|
|
65
|
-
Wrap your main execution in a guard:
|
|
66
|
-
|
|
67
|
-
<!-- SPDX-SnippetBegin -->
|
|
68
|
-
<!--
|
|
69
|
-
SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
70
|
-
SPDX-License-Identifier: MIT-0
|
|
71
|
-
-->
|
|
72
|
-
```ruby
|
|
73
|
-
if __FILE__ == $PROGRAM_NAME
|
|
74
|
-
MyApp.new.run
|
|
75
|
-
end
|
|
76
|
-
```
|
|
77
|
-
<!-- SPDX-SnippetEnd -->
|
|
78
|
-
|
|
79
|
-
Now load the file and interact with classes directly:
|
|
80
|
-
|
|
81
|
-
<!-- SPDX-SnippetBegin -->
|
|
82
|
-
<!--
|
|
83
|
-
SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
84
|
-
SPDX-License-Identifier: MIT-0
|
|
85
|
-
-->
|
|
86
|
-
```bash
|
|
87
|
-
ruby -e 'load "./bin/my_tui"; obj = MyClass.new; sleep 1; puts obj.result'
|
|
88
|
-
```
|
|
89
|
-
<!-- SPDX-SnippetEnd -->
|
|
90
|
-
|
|
91
|
-
This exercises domain logic without entering raw terminal mode. Use it for exploratory debugging. Write tests using the [TestHelper](application_testing.md) for regression coverage.
|
|
92
|
-
|
|
93
|
-
## Isolating Terminal Issues
|
|
94
|
-
|
|
95
|
-
Something works in a `ruby -e` script but fails in the TUI. Common causes:
|
|
96
|
-
|
|
97
|
-
1. **Thread context.** Ruby threads share the process's terminal state.
|
|
98
|
-
2. **Raw mode.** External commands fail when stdin/stdout are reconfigured.
|
|
99
|
-
3. **SSH/Git auth.** Commands that prompt for credentials hang or return empty.
|
|
100
|
-
|
|
101
|
-
See [Async Operations](async.md) for solutions.
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
#--
|
|
4
|
-
# SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
|
|
5
|
-
# SPDX-License-Identifier: LGPL-3.0-or-later
|
|
6
|
-
#++
|
|
7
|
-
|
|
8
|
-
module RatatuiRuby
|
|
9
|
-
class BarChart
|
|
10
|
-
# A bar in a grouped bar chart.
|
|
11
|
-
#
|
|
12
|
-
# === Examples
|
|
13
|
-
#
|
|
14
|
-
# BarChart::Bar.new(value: 10, style: Style.new(fg: :red), label: "A")
|
|
15
|
-
class Bar < Data.define(:value, :label, :style, :value_style, :text_value)
|
|
16
|
-
##
|
|
17
|
-
# :attr_reader: value
|
|
18
|
-
# The value of the bar (Integer).
|
|
19
|
-
|
|
20
|
-
##
|
|
21
|
-
# :attr_reader: label
|
|
22
|
-
# The label of the bar (optional String, Text::Span, or Text::Line for rich styling).
|
|
23
|
-
|
|
24
|
-
##
|
|
25
|
-
# :attr_reader: style
|
|
26
|
-
# The style of the bar (optional Style).
|
|
27
|
-
|
|
28
|
-
##
|
|
29
|
-
# :attr_reader: value_style
|
|
30
|
-
# The style of the value (optional Style).
|
|
31
|
-
|
|
32
|
-
##
|
|
33
|
-
# :attr_reader: text_value
|
|
34
|
-
# The text to display as the value (optional String, Text::Span, or Text::Line for rich styling).
|
|
35
|
-
|
|
36
|
-
def initialize(value:, label: nil, style: nil, value_style: nil, text_value: nil)
|
|
37
|
-
super(
|
|
38
|
-
value: Integer(value),
|
|
39
|
-
label:,
|
|
40
|
-
style:,
|
|
41
|
-
value_style:,
|
|
42
|
-
text_value:
|
|
43
|
-
)
|
|
44
|
-
end
|
|
45
|
-
end
|
|
46
|
-
end
|
|
47
|
-
end
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
#--
|
|
4
|
-
# SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
|
|
5
|
-
# SPDX-License-Identifier: LGPL-3.0-or-later
|
|
6
|
-
#++
|
|
7
|
-
|
|
8
|
-
module RatatuiRuby
|
|
9
|
-
class BarChart
|
|
10
|
-
# A group of bars in a grouped bar chart.
|
|
11
|
-
#
|
|
12
|
-
# === Examples
|
|
13
|
-
#
|
|
14
|
-
# BarChart::BarGroup.new(label: "Q1", bars: [BarChart::Bar.new(value: 10), BarChart::Bar.new(value: 20)])
|
|
15
|
-
class BarGroup < Data.define(:label, :bars)
|
|
16
|
-
##
|
|
17
|
-
# :attr_reader: label
|
|
18
|
-
# The label of the group (String).
|
|
19
|
-
|
|
20
|
-
##
|
|
21
|
-
# :attr_reader: bars
|
|
22
|
-
# The bars in the group (Array of Bar).
|
|
23
|
-
end
|
|
24
|
-
end
|
|
25
|
-
end
|
|
@@ -1,287 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
#--
|
|
4
|
-
# SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
|
|
5
|
-
# SPDX-License-Identifier: LGPL-3.0-or-later
|
|
6
|
-
#++
|
|
7
|
-
|
|
8
|
-
module RatatuiRuby
|
|
9
|
-
# Displays categorical data as bars.
|
|
10
|
-
#
|
|
11
|
-
# Raw tables of numbers are hard to scan. Comparing magnitudes requires mental arithmetic, which slows down decision-making.
|
|
12
|
-
#
|
|
13
|
-
# This widget visualizes the data. It renders vertical bars proportional to their value.
|
|
14
|
-
#
|
|
15
|
-
# Use it to compare server loads, sales figures, or any discrete datasets.
|
|
16
|
-
#
|
|
17
|
-
# {rdoc-image:/doc/images/widget_barchart.png}[link:/examples/widget_barchart/app_rb.html]
|
|
18
|
-
#
|
|
19
|
-
# === Example
|
|
20
|
-
#
|
|
21
|
-
# Run the interactive demo from the terminal:
|
|
22
|
-
#
|
|
23
|
-
#--
|
|
24
|
-
# SPDX-SnippetBegin
|
|
25
|
-
# SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
26
|
-
# SPDX-License-Identifier: MIT-0
|
|
27
|
-
#++
|
|
28
|
-
# ruby examples/widget_barchart/app.rb
|
|
29
|
-
#
|
|
30
|
-
# # Grouped Bar Chart
|
|
31
|
-
# BarChart.new(
|
|
32
|
-
# data: [
|
|
33
|
-
# BarGroup.new(label: "Q1", bars: [Bar.new(value: 40), Bar.new(value: 45)]),
|
|
34
|
-
# BarGroup.new(label: "Q2", bars: [Bar.new(value: 50), Bar.new(value: 55)])
|
|
35
|
-
# ],
|
|
36
|
-
# bar_width: 5,
|
|
37
|
-
# group_gap: 3
|
|
38
|
-
# )
|
|
39
|
-
#--
|
|
40
|
-
# SPDX-SnippetEnd
|
|
41
|
-
#++
|
|
42
|
-
class BarChart < Data.define(:data, :bar_width, :bar_gap, :group_gap, :max, :style, :block, :direction, :label_style, :value_style, :bar_set)
|
|
43
|
-
##
|
|
44
|
-
##
|
|
45
|
-
##
|
|
46
|
-
##
|
|
47
|
-
# :attr_reader: data
|
|
48
|
-
# The data to display.
|
|
49
|
-
#
|
|
50
|
-
# Supports multiple formats:
|
|
51
|
-
# [<tt>Hash</tt>]
|
|
52
|
-
# Mapping labels (<tt>String</tt> or <tt>Symbol</tt>) to values (<tt>Integer</tt>).
|
|
53
|
-
# [<tt>Array</tt> of tuples]
|
|
54
|
-
# Ordered list of <tt>["Label", Value]</tt> or <tt>["Label", Value, Style]</tt> pairs.
|
|
55
|
-
# [<tt>Array</tt> of <tt>BarChart::BarGroup</tt>]
|
|
56
|
-
#--
|
|
57
|
-
# SPDX-SnippetBegin
|
|
58
|
-
# SPDX-FileCopyrightText: 2025 Kerrick Long
|
|
59
|
-
# SPDX-License-Identifier: MIT-0
|
|
60
|
-
#++
|
|
61
|
-
# List of <tt>BarChart::BarGroup</tt> objects for grouped charts.
|
|
62
|
-
#
|
|
63
|
-
#--
|
|
64
|
-
# SPDX-SnippetEnd
|
|
65
|
-
#++
|
|
66
|
-
# === Examples
|
|
67
|
-
#
|
|
68
|
-
# Hash (Simple):
|
|
69
|
-
#--
|
|
70
|
-
# SPDX-SnippetBegin
|
|
71
|
-
# SPDX-FileCopyrightText: 2025 Kerrick Long
|
|
72
|
-
# SPDX-License-Identifier: MIT-0
|
|
73
|
-
#++
|
|
74
|
-
# { "Apples" => 10, :Oranges => 15 }
|
|
75
|
-
#
|
|
76
|
-
#--
|
|
77
|
-
# SPDX-SnippetEnd
|
|
78
|
-
#++
|
|
79
|
-
# Array of Tuples (Ordered):
|
|
80
|
-
#--
|
|
81
|
-
# SPDX-SnippetBegin
|
|
82
|
-
# SPDX-FileCopyrightText: 2025 Kerrick Long
|
|
83
|
-
# SPDX-License-Identifier: MIT-0
|
|
84
|
-
#++
|
|
85
|
-
# [["Mon", 20], ["Tue", 30], ["Wed", 25]]
|
|
86
|
-
#
|
|
87
|
-
#--
|
|
88
|
-
# SPDX-SnippetEnd
|
|
89
|
-
#++
|
|
90
|
-
# BarGroup (Grouped):
|
|
91
|
-
#--
|
|
92
|
-
# SPDX-SnippetBegin
|
|
93
|
-
# SPDX-FileCopyrightText: 2025 Kerrick Long
|
|
94
|
-
# SPDX-License-Identifier: MIT-0
|
|
95
|
-
#++
|
|
96
|
-
# [
|
|
97
|
-
# RatatuiRuby::BarChart::BarGroup.new(label: "Q1", bars: [
|
|
98
|
-
# RatatuiRuby::BarChart::Bar.new(value: 50, label: "Rev"),
|
|
99
|
-
# RatatuiRuby::BarChart::Bar.new(value: 30, label: "Cost")
|
|
100
|
-
# ])
|
|
101
|
-
# ]
|
|
102
|
-
#--
|
|
103
|
-
# SPDX-SnippetEnd
|
|
104
|
-
#++
|
|
105
|
-
|
|
106
|
-
##
|
|
107
|
-
# :attr_reader: bar_width
|
|
108
|
-
# Width of each bar in characters.
|
|
109
|
-
|
|
110
|
-
##
|
|
111
|
-
# :attr_reader: bar_gap
|
|
112
|
-
# Spaces between bars.
|
|
113
|
-
|
|
114
|
-
##
|
|
115
|
-
# :attr_reader: group_gap
|
|
116
|
-
# Spaces between groups (for grouped bar charts).
|
|
117
|
-
|
|
118
|
-
##
|
|
119
|
-
# :attr_reader: max
|
|
120
|
-
# Maximum value for the Y-axis (optional).
|
|
121
|
-
#
|
|
122
|
-
# If nil, it is calculated from the data.
|
|
123
|
-
|
|
124
|
-
##
|
|
125
|
-
# :attr_reader: style
|
|
126
|
-
# Style for the bars.
|
|
127
|
-
|
|
128
|
-
##
|
|
129
|
-
# :attr_reader: block
|
|
130
|
-
# Optional wrapping block.
|
|
131
|
-
|
|
132
|
-
##
|
|
133
|
-
# :attr_reader: label_style
|
|
134
|
-
# Style for the bar labels (optional).
|
|
135
|
-
|
|
136
|
-
##
|
|
137
|
-
# :attr_reader: value_style
|
|
138
|
-
# Style for the bar values (optional).
|
|
139
|
-
|
|
140
|
-
##
|
|
141
|
-
# :attr_reader: bar_set
|
|
142
|
-
# Custom characters for the bars (optional).
|
|
143
|
-
#
|
|
144
|
-
# A Hash with keys defining the characters for the bars.
|
|
145
|
-
# Keys: <tt>:empty</tt>, <tt>:one_eighth</tt>, <tt>:one_quarter</tt>, <tt>:three_eighths</tt>, <tt>:half</tt>, <tt>:five_eighths</tt>, <tt>:three_quarters</tt>, <tt>:seven_eighths</tt>, <tt>:full</tt>.
|
|
146
|
-
#
|
|
147
|
-
# You can also use integers (0-8) as keys, where 0 is empty, 4 is half, and 8 is full.
|
|
148
|
-
#
|
|
149
|
-
# Alternatively, you can pass an Array of 9 strings, where index 0 is empty and index 8 is full.
|
|
150
|
-
#
|
|
151
|
-
# === Examples
|
|
152
|
-
#
|
|
153
|
-
#--
|
|
154
|
-
# SPDX-SnippetBegin
|
|
155
|
-
# SPDX-FileCopyrightText: 2025 Kerrick Long
|
|
156
|
-
# SPDX-License-Identifier: MIT-0
|
|
157
|
-
#++
|
|
158
|
-
# bar_set: {
|
|
159
|
-
# empty: " ",
|
|
160
|
-
# one_eighth: " ",
|
|
161
|
-
# one_quarter: "▂",
|
|
162
|
-
# three_eighths: "▃",
|
|
163
|
-
# half: "▄",
|
|
164
|
-
# five_eighths: "▅",
|
|
165
|
-
# three_quarters: "▆",
|
|
166
|
-
# seven_eighths: "▇",
|
|
167
|
-
# full: "█"
|
|
168
|
-
# }
|
|
169
|
-
#
|
|
170
|
-
# # Numeric keys (0-8)
|
|
171
|
-
# bar_set: {
|
|
172
|
-
# 0 => " ", 1 => " ", 2 => "▂", 3 => "▃", 4 => "▄", 5 => "▅", 6 => "▆", 7 => "▇", 8 => "█"
|
|
173
|
-
# }
|
|
174
|
-
#
|
|
175
|
-
# # Array (9 items)
|
|
176
|
-
# bar_set: [" ", " ", "▂", "▃", "▄", "▅", "▆", "▇", "█"]
|
|
177
|
-
#--
|
|
178
|
-
# SPDX-SnippetEnd
|
|
179
|
-
#++
|
|
180
|
-
|
|
181
|
-
BAR_KEYS = %i[empty one_eighth one_quarter three_eighths half five_eighths three_quarters seven_eighths full].freeze
|
|
182
|
-
|
|
183
|
-
# Creates a new BarChart widget.
|
|
184
|
-
#
|
|
185
|
-
# [data]
|
|
186
|
-
# Data to display. Hash, Array of arrays, or Array of BarGroup.
|
|
187
|
-
# [bar_width]
|
|
188
|
-
# Width of each bar (Integer).
|
|
189
|
-
# [bar_gap]
|
|
190
|
-
# Gap between bars (Integer).
|
|
191
|
-
# [group_gap]
|
|
192
|
-
# Gap between groups (Integer).
|
|
193
|
-
# [max]
|
|
194
|
-
# Maximum value of the bar chart (Integer).
|
|
195
|
-
# [style]
|
|
196
|
-
# Base style for the widget (Style).
|
|
197
|
-
# [block]
|
|
198
|
-
# Block to render around the chart (Block).
|
|
199
|
-
# [direction]
|
|
200
|
-
# Direction of the bars (:vertical or :horizontal).
|
|
201
|
-
# [label_style]
|
|
202
|
-
# Style object for labels (optional).
|
|
203
|
-
# [value_style]
|
|
204
|
-
# Style object for values (optional).
|
|
205
|
-
# [bar_set]
|
|
206
|
-
# Hash or Array: Custom characters for the bars.
|
|
207
|
-
def initialize(data:, bar_width: 3, bar_gap: 1, group_gap: 0, max: nil, style: nil, block: nil, direction: :vertical, label_style: nil, value_style: nil, bar_set: nil)
|
|
208
|
-
if bar_set
|
|
209
|
-
if bar_set.is_a?(Array) && bar_set.size == 9
|
|
210
|
-
# Convert Array to Hash using BAR_KEYS order
|
|
211
|
-
bar_set = BAR_KEYS.zip(bar_set).to_h
|
|
212
|
-
else
|
|
213
|
-
bar_set = bar_set.dup
|
|
214
|
-
# Normalize numeric keys (0-8) to symbolic keys
|
|
215
|
-
BAR_KEYS.each_with_index do |key, i|
|
|
216
|
-
if (val = bar_set.delete(i) || bar_set.delete(i.to_s))
|
|
217
|
-
bar_set[key] = val
|
|
218
|
-
end
|
|
219
|
-
end
|
|
220
|
-
end
|
|
221
|
-
end
|
|
222
|
-
|
|
223
|
-
# Normalize data to Array of BarGroup
|
|
224
|
-
data = if data.is_a?(Hash)
|
|
225
|
-
if direction == :horizontal
|
|
226
|
-
bars = data.map do |label, value|
|
|
227
|
-
Bar.new(value:, label: label.to_s)
|
|
228
|
-
end
|
|
229
|
-
[BarGroup.new(label: "", bars:)]
|
|
230
|
-
else
|
|
231
|
-
data.map do |label, value|
|
|
232
|
-
BarGroup.new(label: label.to_s, bars: [Bar.new(value:)])
|
|
233
|
-
end
|
|
234
|
-
end
|
|
235
|
-
elsif data.is_a?(Array)
|
|
236
|
-
if data.empty?
|
|
237
|
-
[]
|
|
238
|
-
elsif data.first.is_a?(BarGroup)
|
|
239
|
-
data
|
|
240
|
-
elsif data.first.is_a?(Array)
|
|
241
|
-
# Tuples
|
|
242
|
-
if direction == :horizontal
|
|
243
|
-
bars = data.map do |item|
|
|
244
|
-
label = item[0].to_s
|
|
245
|
-
value = item[1]
|
|
246
|
-
style = item[2]
|
|
247
|
-
|
|
248
|
-
bar = Bar.new(value:, label:)
|
|
249
|
-
bar = bar.with(style:) if style
|
|
250
|
-
bar
|
|
251
|
-
end
|
|
252
|
-
[BarGroup.new(label: "", bars:)]
|
|
253
|
-
else
|
|
254
|
-
data.map do |item|
|
|
255
|
-
label = item[0].to_s
|
|
256
|
-
value = item[1]
|
|
257
|
-
style = item[2]
|
|
258
|
-
|
|
259
|
-
bar = Bar.new(value:)
|
|
260
|
-
bar = bar.with(style:) if style
|
|
261
|
-
BarGroup.new(label:, bars: [bar])
|
|
262
|
-
end
|
|
263
|
-
end
|
|
264
|
-
else
|
|
265
|
-
# Fallback
|
|
266
|
-
data
|
|
267
|
-
end
|
|
268
|
-
else
|
|
269
|
-
data
|
|
270
|
-
end
|
|
271
|
-
|
|
272
|
-
super(
|
|
273
|
-
data:,
|
|
274
|
-
bar_width: Integer(bar_width),
|
|
275
|
-
bar_gap: Integer(bar_gap),
|
|
276
|
-
group_gap: Integer(group_gap),
|
|
277
|
-
max: max.nil? ? nil : Integer(max),
|
|
278
|
-
style:,
|
|
279
|
-
block:,
|
|
280
|
-
direction:,
|
|
281
|
-
label_style:,
|
|
282
|
-
value_style:,
|
|
283
|
-
bar_set:
|
|
284
|
-
)
|
|
285
|
-
end
|
|
286
|
-
end
|
|
287
|
-
end
|
|
@@ -1,198 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
#--
|
|
4
|
-
# SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
|
|
5
|
-
# SPDX-License-Identifier: LGPL-3.0-or-later
|
|
6
|
-
#++
|
|
7
|
-
|
|
8
|
-
module RatatuiRuby
|
|
9
|
-
# Defines the visual container for a widget.
|
|
10
|
-
#
|
|
11
|
-
# Widgets often float in void. Without boundaries, interfaces become a chaotic mess of text. Users need structure to parse information.
|
|
12
|
-
#
|
|
13
|
-
# This widget creates that structure. It wraps content in borders. It labels sections with titles. It paints the background.
|
|
14
|
-
#
|
|
15
|
-
# Use blocks to define distinct areas. Group related information. Create a visual hierarchy that guides the user's eye.
|
|
16
|
-
#
|
|
17
|
-
# {rdoc-image:/doc/images/widget_box.png}[link:/examples/widget_box/app_rb.html]
|
|
18
|
-
#
|
|
19
|
-
# === Example
|
|
20
|
-
#
|
|
21
|
-
# Run the interactive demo from the terminal:
|
|
22
|
-
#
|
|
23
|
-
# ruby examples/widget_box/app.rb
|
|
24
|
-
class Block < Data.define(:title, :titles, :title_alignment, :title_style, :borders, :border_style, :border_type, :border_set, :style, :padding, :children)
|
|
25
|
-
##
|
|
26
|
-
# :attr_reader: title
|
|
27
|
-
# The main title displayed on the top border.
|
|
28
|
-
#
|
|
29
|
-
# === Example
|
|
30
|
-
#
|
|
31
|
-
# Block.new(title: "Main").title # => "Main"
|
|
32
|
-
|
|
33
|
-
##
|
|
34
|
-
# :attr_reader: titles
|
|
35
|
-
# Additional titles for complex labeling.
|
|
36
|
-
#
|
|
37
|
-
# Each title can be a <tt>String</tt> or a <tt>Hash</tt> with keys <tt>:content</tt>, <tt>:alignment</tt>, <tt>:position</tt> (<tt>:top</tt> or <tt>:bottom</tt>), and <tt>:style</tt>.
|
|
38
|
-
#
|
|
39
|
-
# === Example
|
|
40
|
-
#
|
|
41
|
-
# Block.new(titles: ["Top", { content: "Bottom", position: :bottom }]).titles
|
|
42
|
-
|
|
43
|
-
##
|
|
44
|
-
# :attr_reader: title_alignment
|
|
45
|
-
# Alignment of the main title.
|
|
46
|
-
#
|
|
47
|
-
# One of <tt>:left</tt>, <tt>:center</tt>, or <tt>:right</tt>.
|
|
48
|
-
#
|
|
49
|
-
# === Example
|
|
50
|
-
#
|
|
51
|
-
# Block.new(title_alignment: :center).title_alignment # => :center
|
|
52
|
-
|
|
53
|
-
##
|
|
54
|
-
# :attr_reader: title_style
|
|
55
|
-
# Style applied to all titles if not overridden.
|
|
56
|
-
#
|
|
57
|
-
# === Example
|
|
58
|
-
#
|
|
59
|
-
# Block.new(title_style: Style.new(fg: :red)).title_style
|
|
60
|
-
|
|
61
|
-
##
|
|
62
|
-
# :attr_reader: borders
|
|
63
|
-
# Visible borders.
|
|
64
|
-
#
|
|
65
|
-
# An array containing any of <tt>:top</tt>, <tt>:bottom</tt>, <tt>:left</tt>, <tt>:right</tt>, or <tt>:all</tt>.
|
|
66
|
-
#
|
|
67
|
-
# === Example
|
|
68
|
-
#
|
|
69
|
-
# Block.new(borders: [:left, :right]).borders # => [:left, :right]
|
|
70
|
-
|
|
71
|
-
##
|
|
72
|
-
# :attr_reader: border_style
|
|
73
|
-
# Full style (colors/modifiers) for the border lines.
|
|
74
|
-
#
|
|
75
|
-
# A Style object or Hash with <tt>:fg</tt>, <tt>:bg</tt>, and <tt>:modifiers</tt>.
|
|
76
|
-
# This allows borders to be bold, italic, colored, etc.
|
|
77
|
-
|
|
78
|
-
##
|
|
79
|
-
# :attr_reader: border_type
|
|
80
|
-
# Visual style of the border lines.
|
|
81
|
-
#
|
|
82
|
-
# One of <tt>:plain</tt>, <tt>:rounded</tt>, <tt>:double</tt>, <tt>:thick</tt>, etc.
|
|
83
|
-
|
|
84
|
-
##
|
|
85
|
-
# :attr_reader: border_set
|
|
86
|
-
# Custom characters for the border lines.
|
|
87
|
-
#
|
|
88
|
-
# A Hash with keys defining the characters for the borders.
|
|
89
|
-
# Keys: <tt>:top_left</tt>, <tt>:top_right</tt>, <tt>:bottom_left</tt>, <tt>:bottom_right</tt>,
|
|
90
|
-
# <tt>:vertical_left</tt>, <tt>:vertical_right</tt>, <tt>:horizontal_top</tt>, <tt>:horizontal_bottom</tt>.
|
|
91
|
-
#
|
|
92
|
-
# Providing this overrides <tt>border_type</tt>.
|
|
93
|
-
#
|
|
94
|
-
#
|
|
95
|
-
# === Example
|
|
96
|
-
#
|
|
97
|
-
# Block.new(border_set: { top_left: "1", top_right: "2", bottom_left: "3", bottom_right: "4", vertical_left: "5", vertical_right: "6", horizontal_top: "7", horizontal_bottom: "8" })
|
|
98
|
-
|
|
99
|
-
##
|
|
100
|
-
# :attr_reader: style
|
|
101
|
-
# Base style (colors/modifiers) for the block content.
|
|
102
|
-
|
|
103
|
-
##
|
|
104
|
-
# :attr_reader: padding
|
|
105
|
-
# Inner padding.
|
|
106
|
-
#
|
|
107
|
-
# Can be a single <tt>Integer</tt> (uniform) or a 4-element <tt>Array</tt> (left, right, top, bottom).
|
|
108
|
-
#
|
|
109
|
-
# === Example
|
|
110
|
-
#
|
|
111
|
-
#--
|
|
112
|
-
# SPDX-SnippetBegin
|
|
113
|
-
# SPDX-FileCopyrightText: 2025 Kerrick Long
|
|
114
|
-
# SPDX-License-Identifier: MIT-0
|
|
115
|
-
#++
|
|
116
|
-
# Block.new(padding: 2).padding # => 2
|
|
117
|
-
# Block.new(padding: [1, 1, 0, 0]).padding # => [1, 1, 0, 0]
|
|
118
|
-
#--
|
|
119
|
-
# SPDX-SnippetEnd
|
|
120
|
-
#++
|
|
121
|
-
|
|
122
|
-
##
|
|
123
|
-
# :attr_reader: children
|
|
124
|
-
# Widgets to render inside the block (optional).
|
|
125
|
-
#
|
|
126
|
-
# When provided, each child widget is rendered within the block's area.
|
|
127
|
-
#
|
|
128
|
-
# === Example
|
|
129
|
-
#
|
|
130
|
-
#--
|
|
131
|
-
# SPDX-SnippetBegin
|
|
132
|
-
# SPDX-FileCopyrightText: 2025 Kerrick Long
|
|
133
|
-
# SPDX-License-Identifier: MIT-0
|
|
134
|
-
#++
|
|
135
|
-
# Block.new(
|
|
136
|
-
# title: "Content",
|
|
137
|
-
# borders: [:all],
|
|
138
|
-
# children: [Paragraph.new(text: "Hello")]
|
|
139
|
-
# )
|
|
140
|
-
#--
|
|
141
|
-
# SPDX-SnippetEnd
|
|
142
|
-
#++
|
|
143
|
-
|
|
144
|
-
# Creates a new Block.
|
|
145
|
-
#
|
|
146
|
-
# [title]
|
|
147
|
-
# Main title string (optional).
|
|
148
|
-
# [titles]
|
|
149
|
-
# Array of additional titles (optional).
|
|
150
|
-
# [title_alignment]
|
|
151
|
-
# Alignment symbol: <tt>:left</tt> (default), <tt>:center</tt>, <tt>:right</tt>.
|
|
152
|
-
# [title_style]
|
|
153
|
-
# Base style for all titles (optional).
|
|
154
|
-
# [borders]
|
|
155
|
-
# Array of borders to show: <tt>:top</tt>, <tt>:bottom</tt>, <tt>:left</tt>, <tt>:right</tt>, or <tt>:all</tt> (default).
|
|
156
|
-
# [border_style]
|
|
157
|
-
# Style object or Hash for the border lines.
|
|
158
|
-
# [border_type]
|
|
159
|
-
# Symbol: <tt>:plain</tt> (default), <tt>:rounded</tt>, <tt>:double</tt>, <tt>:thick</tt>, <tt>:hidden</tt>, <tt>:quadrant_inside</tt>, <tt>:quadrant_outside</tt>.
|
|
160
|
-
# [border_set]
|
|
161
|
-
# Hash: Custom characters for the border lines. Unique characters are interned (leaked) permanently, so avoid infinite dynamic variations.
|
|
162
|
-
# [style]
|
|
163
|
-
# Style object or Hash for the block's content area.
|
|
164
|
-
# [padding]
|
|
165
|
-
# Integer (uniform) or Array[4] (left, right, top, bottom).
|
|
166
|
-
# [children]
|
|
167
|
-
# Array of widgets to render inside the block (optional).
|
|
168
|
-
def initialize(title: nil, titles: [], title_alignment: nil, title_style: nil, borders: [:all], border_style: nil, border_type: nil, border_set: nil, style: nil, padding: 0, children: [])
|
|
169
|
-
if border_set
|
|
170
|
-
border_set = border_set.dup
|
|
171
|
-
%i[top_left top_right bottom_left bottom_right vertical_left vertical_right horizontal_top horizontal_bottom].each do |long_key|
|
|
172
|
-
short_key = long_key.to_s.split("_").map { |s| s[0] }.join
|
|
173
|
-
if (val = border_set.delete(short_key.to_sym) || border_set.delete(short_key))
|
|
174
|
-
border_set[long_key] = val
|
|
175
|
-
end
|
|
176
|
-
end
|
|
177
|
-
end
|
|
178
|
-
coerced_padding = if padding.is_a?(Array)
|
|
179
|
-
padding.map { |v| Integer(v) }
|
|
180
|
-
else
|
|
181
|
-
Integer(padding)
|
|
182
|
-
end
|
|
183
|
-
super(
|
|
184
|
-
title:,
|
|
185
|
-
titles:,
|
|
186
|
-
title_alignment:,
|
|
187
|
-
title_style:,
|
|
188
|
-
borders:,
|
|
189
|
-
border_style:,
|
|
190
|
-
border_type:,
|
|
191
|
-
border_set:,
|
|
192
|
-
style:,
|
|
193
|
-
padding: coerced_padding,
|
|
194
|
-
children:
|
|
195
|
-
)
|
|
196
|
-
end
|
|
197
|
-
end
|
|
198
|
-
end
|