rooibos 0.5.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.
- checksums.yaml +4 -4
- data/.builds/ruby-3.2.yml +9 -5
- data/.builds/ruby-3.3.yml +9 -5
- data/.builds/ruby-3.4.yml +9 -5
- data/.builds/ruby-4.0.0.yml +9 -5
- data/AGENTS.md +1 -1
- data/CHANGELOG.md +46 -0
- data/README.md +2 -2
- data/README.rdoc +374 -0
- data/REUSE.toml +5 -0
- data/Rakefile +1 -1
- data/doc/best_practices/forms_and_validation.md +20 -0
- data/doc/best_practices/http_workflows.md +20 -0
- data/doc/best_practices/index.md +26 -0
- data/doc/best_practices/lists_and_tables.md +20 -0
- data/doc/best_practices/modal_dialogs.md +20 -0
- data/doc/best_practices/no_stateful_widgets.md +184 -0
- data/doc/best_practices/orchestration.md +20 -0
- data/doc/best_practices/streaming_data.md +20 -0
- data/doc/contributors/design/commands_and_outlets.md +1 -1
- data/doc/contributors/documentation_plan.md +616 -0
- data/doc/contributors/documentation_stub_audit.md +112 -0
- data/doc/contributors/documentation_style.md +275 -0
- data/doc/contributors/e2e_pty.md +168 -0
- data/doc/contributors/specs/earliest_tutorial_steps_per_story.md +70 -0
- data/doc/contributors/specs/file_browser.md +789 -0
- data/doc/contributors/specs/file_browser_stories.md +774 -0
- data/doc/contributors/specs/tutorials_to_stories.rb +167 -0
- data/doc/contributors/todo/scrollbar.md +118 -0
- data/doc/contributors/tutorial_old/01_project_setup.md +20 -0
- data/doc/contributors/tutorial_old/02_hello_world.md +24 -0
- data/doc/contributors/tutorial_old/03_adding_state.md +26 -0
- data/doc/contributors/tutorial_old/06_organizing_your_code.md +20 -0
- data/doc/contributors/tutorial_old/07_your_first_command.md +21 -0
- data/doc/contributors/tutorial_old/08_the_preview_pane.md +20 -0
- data/doc/contributors/tutorial_old/09_loading_states.md +20 -0
- data/doc/contributors/tutorial_old/10_testing_your_app.md +20 -0
- data/doc/contributors/tutorial_old/11_polish_and_refine.md +20 -0
- data/doc/contributors/tutorial_old/12_going_further.md +20 -0
- data/doc/contributors/tutorial_old/index.md +20 -0
- data/doc/essentials/commands.md +20 -0
- data/doc/essentials/index.md +31 -0
- data/doc/essentials/messages.md +21 -0
- data/doc/essentials/models.md +21 -0
- data/doc/essentials/shortcuts.md +19 -0
- data/doc/essentials/the_elm_architecture.md +24 -0
- data/doc/essentials/the_runtime.md +21 -0
- data/doc/essentials/update_functions.md +20 -0
- data/doc/essentials/views.md +22 -0
- data/doc/getting_started/for_go_developers.md +16 -0
- data/doc/getting_started/for_python_developers.md +16 -0
- data/doc/getting_started/for_react_developers.md +17 -0
- data/doc/getting_started/index.md +52 -0
- data/doc/getting_started/install.md +20 -0
- data/doc/getting_started/quickstart.md +9 -45
- data/doc/getting_started/ruby_primer.md +19 -0
- data/doc/getting_started/why_rooibos.md +20 -0
- data/doc/index.md +79 -11
- data/doc/scaling_up/async_patterns.md +20 -0
- data/doc/scaling_up/command_composition.md +20 -0
- data/doc/scaling_up/custom_commands.md +21 -0
- data/doc/scaling_up/fractal_architecture.md +20 -0
- data/doc/scaling_up/index.md +30 -0
- data/doc/scaling_up/message_routing.md +20 -0
- data/doc/scaling_up/ractor_safety.md +20 -0
- data/doc/scaling_up/testing.md +21 -0
- data/doc/troubleshooting/common_errors.md +20 -0
- data/doc/troubleshooting/debugging.md +21 -0
- data/doc/troubleshooting/index.md +23 -0
- data/doc/troubleshooting/performance.md +20 -0
- data/doc/tutorial/01_project_setup.md +44 -0
- data/doc/tutorial/02_hello_world.md +45 -0
- data/doc/tutorial/03_static_file_list.md +44 -0
- data/doc/tutorial/04_arrow_navigation.md +47 -0
- data/doc/tutorial/05_real_files.md +45 -0
- data/doc/tutorial/06_safe_refactoring.md +21 -0
- data/doc/tutorial/07_red_first_tdd.md +26 -0
- data/doc/tutorial/08_file_metadata.md +42 -0
- data/doc/tutorial/09_text_preview.md +44 -0
- data/doc/tutorial/10_directory_tree.md +42 -0
- data/doc/tutorial/11_pane_focus.md +40 -0
- data/doc/tutorial/12_sorting.md +41 -0
- data/doc/tutorial/13_filtering.md +43 -0
- data/doc/tutorial/14_toggle_hidden.md +41 -0
- data/doc/tutorial/15_text_input_widget.md +43 -0
- data/doc/tutorial/16_rename_files.md +42 -0
- data/doc/tutorial/17_confirmation_dialogs.md +43 -0
- data/doc/tutorial/18_progress_indicators.md +43 -0
- data/doc/tutorial/19_atomic_operations.md +42 -0
- data/doc/tutorial/20_external_editor.md +42 -0
- data/doc/tutorial/21_modal_overlays.md +41 -0
- data/doc/tutorial/22_error_handling.md +43 -0
- data/doc/tutorial/23_terminal_capabilities.md +53 -0
- data/doc/tutorial/24_mouse_events.md +43 -0
- data/doc/tutorial/25_resize_events.md +43 -0
- data/doc/tutorial/26_loading_states.md +42 -0
- data/doc/tutorial/27_performance.md +43 -0
- data/doc/tutorial/28_color_schemes.md +47 -0
- data/doc/tutorial/29_configuration.md +124 -0
- data/doc/tutorial/30_going_further.md +17 -0
- data/doc/tutorial/index.md +17 -0
- data/examples/app_file_browser/app.rb +40 -0
- data/examples/app_fractal_dashboard/dashboard/update_manual.rb +7 -7
- data/examples/app_fractal_dashboard/fragments/custom_shell_input.rb +5 -5
- data/examples/app_fractal_dashboard/fragments/custom_shell_modal.rb +1 -1
- data/examples/app_fractal_dashboard/fragments/disk_usage.rb +2 -2
- data/examples/app_fractal_dashboard/fragments/network_panel.rb +4 -4
- data/examples/app_fractal_dashboard/fragments/ping.rb +2 -2
- data/examples/app_fractal_dashboard/fragments/stats_panel.rb +4 -4
- data/examples/app_fractal_dashboard/fragments/system_info.rb +2 -2
- data/examples/app_fractal_dashboard/fragments/uptime.rb +2 -2
- data/examples/verify_website_first_app/app.rb +85 -0
- data/examples/verify_website_hello_mvu/app.rb +31 -0
- data/examples/widget_command_system/app.rb +15 -13
- data/exe/rooibos +10 -0
- data/generate_tutorial_stubs.rb +126 -0
- data/lib/rooibos/cli/commands/new.rb +373 -0
- data/lib/rooibos/cli/commands/run.rb +98 -0
- data/lib/rooibos/cli.rb +78 -0
- data/lib/rooibos/command/all.rb +25 -20
- data/lib/rooibos/command/batch.rb +26 -25
- data/lib/rooibos/command/custom.rb +84 -1
- data/lib/rooibos/command/http.rb +59 -55
- data/lib/rooibos/command/lifecycle.rb +5 -5
- data/lib/rooibos/command/open.rb +86 -0
- data/lib/rooibos/command/outlet.rb +105 -3
- data/lib/rooibos/command/wait.rb +5 -5
- data/lib/rooibos/command.rb +57 -74
- data/lib/rooibos/message/batch.rb +39 -0
- data/lib/rooibos/message/canceled.rb +51 -0
- data/lib/rooibos/message/error.rb +48 -0
- data/lib/rooibos/message/open.rb +30 -0
- data/lib/rooibos/message.rb +84 -4
- data/lib/rooibos/router.rb +11 -14
- data/lib/rooibos/runtime.rb +40 -43
- data/lib/rooibos/shortcuts.rb +47 -0
- data/lib/rooibos/test_helper.rb +71 -6
- data/lib/rooibos/version.rb +1 -1
- data/lib/rooibos/welcome.rb +237 -0
- data/lib/rooibos.rb +4 -3
- data/mise.toml +1 -1
- data/rbs_collection.lock.yaml +2 -2
- data/sig/concurrent.rbs +3 -0
- data/sig/gem.rbs +20 -0
- data/sig/rooibos/cli.rbs +42 -0
- data/sig/rooibos/command.rbs +48 -0
- data/sig/rooibos/message.rbs +60 -0
- data/sig/rooibos/shortcuts.rbs +14 -0
- data/sig/rooibos/test_helper.rbs +6 -2
- data/sig/rooibos/welcome.rbs +75 -0
- data/tasks/install.rake +29 -0
- data/tasks/resources/build.yml.erb +2 -0
- metadata +272 -38
- data/doc/concepts/application_architecture.md +0 -197
- data/doc/concepts/application_testing.md +0 -49
- data/doc/concepts/async_work.md +0 -164
- data/doc/concepts/commands.md +0 -530
- data/doc/concepts/message_processing.md +0 -51
- data/doc/contributors/WIP/decomposition_strategies_analysis.md +0 -258
- data/doc/contributors/WIP/implementation_plan.md +0 -409
- data/doc/contributors/WIP/init_callable_proposal.md +0 -344
- data/doc/contributors/WIP/runtime_refactoring_status.md +0 -47
- data/doc/contributors/WIP/task.md +0 -36
- data/doc/contributors/WIP/v0.4.0_todo.md +0 -468
- data/doc/contributors/kit-no-outlet.md +0 -238
- data/doc/contributors/priorities.md +0 -38
- data/doc/images/.gitkeep +0 -0
- data/exe/.gitkeep +0 -0
- /data/doc/contributors/{WIP → design}/mvu_tea_implementations_research.md +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3c2eb32007ddd93c0a653829b44492878ca229fef1f90c84516d474d3f324132
|
|
4
|
+
data.tar.gz: f52b7a94243bd9582b7229cf48b3834d3f9ae6abaf9f9d6c622625f1d3951a8a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2d5dc50320f2b8026cbb4f33d4c94b2a18beb6930bbdda45a0d38f14013c7015ecb5fce740d2003e6ba19cf48c901dc21e65034d2a66cc6ab6e6c7a3615688e0
|
|
7
|
+
data.tar.gz: 17a5f9bd24f5c9075fbe333a542a094ec40aa9063bd93d0265a5c4c264ead213d9c5030691c62cfd40c3c731570b5c30da0665dc67dbb1ff2a57545e729404f4
|
data/.builds/ruby-3.2.yml
CHANGED
|
@@ -15,8 +15,10 @@ packages:
|
|
|
15
15
|
- libffi
|
|
16
16
|
- clang
|
|
17
17
|
- git
|
|
18
|
+
artifacts:
|
|
19
|
+
- rooibos/pkg/rooibos-0.6.0.gem
|
|
18
20
|
sources:
|
|
19
|
-
- https://git.sr.ht/~kerrick/
|
|
21
|
+
- https://git.sr.ht/~kerrick/rooibos
|
|
20
22
|
tasks:
|
|
21
23
|
- setup: |
|
|
22
24
|
curl https://mise.jdx.dev/install.sh | sh
|
|
@@ -27,7 +29,7 @@ tasks:
|
|
|
27
29
|
echo 'export BINDGEN_EXTRA_CLANG_ARGS="-include stdbool.h"' >> ~/.buildenv
|
|
28
30
|
. ~/.buildenv
|
|
29
31
|
export CI="true"
|
|
30
|
-
cd
|
|
32
|
+
cd rooibos
|
|
31
33
|
sed -i 's/ruby = .*/ruby = "3.2"/' mise.toml
|
|
32
34
|
mise install
|
|
33
35
|
mise x -- pip install reuse
|
|
@@ -37,15 +39,17 @@ tasks:
|
|
|
37
39
|
mise x -- bundle install
|
|
38
40
|
- test: |
|
|
39
41
|
. ~/.buildenv
|
|
40
|
-
cd
|
|
42
|
+
cd rooibos
|
|
43
|
+
echo "Installing rooibos gem globally for integration tests..."
|
|
44
|
+
mise x -- bundle exec rake install:force
|
|
41
45
|
echo "Testing Ruby 3.2"
|
|
42
46
|
mise x -- bundle exec rake test
|
|
43
47
|
- lint: |
|
|
44
48
|
. ~/.buildenv
|
|
45
|
-
cd
|
|
49
|
+
cd rooibos
|
|
46
50
|
echo "Linting Ruby 3.2"
|
|
47
51
|
mise x -- bundle exec rake lint
|
|
48
52
|
- package: |
|
|
49
53
|
. ~/.buildenv
|
|
50
|
-
cd
|
|
54
|
+
cd rooibos
|
|
51
55
|
mise x -- bundle exec rake build
|
data/.builds/ruby-3.3.yml
CHANGED
|
@@ -15,8 +15,10 @@ packages:
|
|
|
15
15
|
- libffi
|
|
16
16
|
- clang
|
|
17
17
|
- git
|
|
18
|
+
artifacts:
|
|
19
|
+
- rooibos/pkg/rooibos-0.6.0.gem
|
|
18
20
|
sources:
|
|
19
|
-
- https://git.sr.ht/~kerrick/
|
|
21
|
+
- https://git.sr.ht/~kerrick/rooibos
|
|
20
22
|
tasks:
|
|
21
23
|
- setup: |
|
|
22
24
|
curl https://mise.jdx.dev/install.sh | sh
|
|
@@ -27,7 +29,7 @@ tasks:
|
|
|
27
29
|
echo 'export BINDGEN_EXTRA_CLANG_ARGS="-include stdbool.h"' >> ~/.buildenv
|
|
28
30
|
. ~/.buildenv
|
|
29
31
|
export CI="true"
|
|
30
|
-
cd
|
|
32
|
+
cd rooibos
|
|
31
33
|
sed -i 's/ruby = .*/ruby = "3.3"/' mise.toml
|
|
32
34
|
mise install
|
|
33
35
|
mise x -- pip install reuse
|
|
@@ -37,15 +39,17 @@ tasks:
|
|
|
37
39
|
mise x -- bundle install
|
|
38
40
|
- test: |
|
|
39
41
|
. ~/.buildenv
|
|
40
|
-
cd
|
|
42
|
+
cd rooibos
|
|
43
|
+
echo "Installing rooibos gem globally for integration tests..."
|
|
44
|
+
mise x -- bundle exec rake install:force
|
|
41
45
|
echo "Testing Ruby 3.3"
|
|
42
46
|
mise x -- bundle exec rake test
|
|
43
47
|
- lint: |
|
|
44
48
|
. ~/.buildenv
|
|
45
|
-
cd
|
|
49
|
+
cd rooibos
|
|
46
50
|
echo "Linting Ruby 3.3"
|
|
47
51
|
mise x -- bundle exec rake lint
|
|
48
52
|
- package: |
|
|
49
53
|
. ~/.buildenv
|
|
50
|
-
cd
|
|
54
|
+
cd rooibos
|
|
51
55
|
mise x -- bundle exec rake build
|
data/.builds/ruby-3.4.yml
CHANGED
|
@@ -15,8 +15,10 @@ packages:
|
|
|
15
15
|
- libffi
|
|
16
16
|
- clang
|
|
17
17
|
- git
|
|
18
|
+
artifacts:
|
|
19
|
+
- rooibos/pkg/rooibos-0.6.0.gem
|
|
18
20
|
sources:
|
|
19
|
-
- https://git.sr.ht/~kerrick/
|
|
21
|
+
- https://git.sr.ht/~kerrick/rooibos
|
|
20
22
|
tasks:
|
|
21
23
|
- setup: |
|
|
22
24
|
curl https://mise.jdx.dev/install.sh | sh
|
|
@@ -27,7 +29,7 @@ tasks:
|
|
|
27
29
|
echo 'export BINDGEN_EXTRA_CLANG_ARGS="-include stdbool.h"' >> ~/.buildenv
|
|
28
30
|
. ~/.buildenv
|
|
29
31
|
export CI="true"
|
|
30
|
-
cd
|
|
32
|
+
cd rooibos
|
|
31
33
|
sed -i 's/ruby = .*/ruby = "3.4"/' mise.toml
|
|
32
34
|
mise install
|
|
33
35
|
mise x -- pip install reuse
|
|
@@ -37,15 +39,17 @@ tasks:
|
|
|
37
39
|
mise x -- bundle install
|
|
38
40
|
- test: |
|
|
39
41
|
. ~/.buildenv
|
|
40
|
-
cd
|
|
42
|
+
cd rooibos
|
|
43
|
+
echo "Installing rooibos gem globally for integration tests..."
|
|
44
|
+
mise x -- bundle exec rake install:force
|
|
41
45
|
echo "Testing Ruby 3.4"
|
|
42
46
|
mise x -- bundle exec rake test
|
|
43
47
|
- lint: |
|
|
44
48
|
. ~/.buildenv
|
|
45
|
-
cd
|
|
49
|
+
cd rooibos
|
|
46
50
|
echo "Linting Ruby 3.4"
|
|
47
51
|
mise x -- bundle exec rake lint
|
|
48
52
|
- package: |
|
|
49
53
|
. ~/.buildenv
|
|
50
|
-
cd
|
|
54
|
+
cd rooibos
|
|
51
55
|
mise x -- bundle exec rake build
|
data/.builds/ruby-4.0.0.yml
CHANGED
|
@@ -15,8 +15,10 @@ packages:
|
|
|
15
15
|
- libffi
|
|
16
16
|
- clang
|
|
17
17
|
- git
|
|
18
|
+
artifacts:
|
|
19
|
+
- rooibos/pkg/rooibos-0.6.0.gem
|
|
18
20
|
sources:
|
|
19
|
-
- https://git.sr.ht/~kerrick/
|
|
21
|
+
- https://git.sr.ht/~kerrick/rooibos
|
|
20
22
|
tasks:
|
|
21
23
|
- setup: |
|
|
22
24
|
curl https://mise.jdx.dev/install.sh | sh
|
|
@@ -27,7 +29,7 @@ tasks:
|
|
|
27
29
|
echo 'export BINDGEN_EXTRA_CLANG_ARGS="-include stdbool.h"' >> ~/.buildenv
|
|
28
30
|
. ~/.buildenv
|
|
29
31
|
export CI="true"
|
|
30
|
-
cd
|
|
32
|
+
cd rooibos
|
|
31
33
|
sed -i 's/ruby = .*/ruby = "4.0.0"/' mise.toml
|
|
32
34
|
mise install
|
|
33
35
|
mise x -- pip install reuse
|
|
@@ -37,15 +39,17 @@ tasks:
|
|
|
37
39
|
mise x -- bundle install
|
|
38
40
|
- test: |
|
|
39
41
|
. ~/.buildenv
|
|
40
|
-
cd
|
|
42
|
+
cd rooibos
|
|
43
|
+
echo "Installing rooibos gem globally for integration tests..."
|
|
44
|
+
mise x -- bundle exec rake install:force
|
|
41
45
|
echo "Testing Ruby 4.0.0"
|
|
42
46
|
mise x -- bundle exec rake test
|
|
43
47
|
- lint: |
|
|
44
48
|
. ~/.buildenv
|
|
45
|
-
cd
|
|
49
|
+
cd rooibos
|
|
46
50
|
echo "Linting Ruby 4.0.0"
|
|
47
51
|
mise x -- bundle exec rake lint
|
|
48
52
|
- package: |
|
|
49
53
|
. ~/.buildenv
|
|
50
|
-
cd
|
|
54
|
+
cd rooibos
|
|
51
55
|
mise x -- bundle exec rake build
|
data/AGENTS.md
CHANGED
|
@@ -35,7 +35,7 @@ Description: Part of the RatatuiRuby ecosystem.
|
|
|
35
35
|
|
|
36
36
|
- **BANNED WORD: "component"** — Reserved for Kit.
|
|
37
37
|
- **Avoid "widget" for Rooibos units** — "Widget" refers to Engine/Ratatui render primitives. In Rooibos, call them **fragments**.
|
|
38
|
-
- **Fragment:** A module containing `Model`, `
|
|
38
|
+
- **Fragment:** A module containing `Model`, `Init`, `Update`, and `View` constants. Fragments compose: parent fragments delegate to child fragments.
|
|
39
39
|
- Use "model", "update", "view" for the MVU pattern. Use "message" (not "msg") and "command" (not "cmd").
|
|
40
40
|
|
|
41
41
|
### Ruby Standards
|
data/CHANGELOG.md
CHANGED
|
@@ -21,6 +21,51 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
21
21
|
|
|
22
22
|
### Removed
|
|
23
23
|
|
|
24
|
+
## [0.6.0] - 2026-01-25
|
|
25
|
+
|
|
26
|
+
### Added
|
|
27
|
+
|
|
28
|
+
- **rooibos CLI**: New command-line interface installed as executable when you install the gem. Provides `rooibos new APP_NAME` to scaffold a complete Rooibos application using `bundle gem` conventions, and `rooibos run` to launch the application. The scaffolded app includes a working TUI that displays "Hello, Rooibos!" and exits on q or Ctrl+C, plus a passing test demonstrating `Rooibos::TestHelper` patterns.
|
|
29
|
+
|
|
30
|
+
- **Rooibos::Welcome**: Built-in welcome screen fragment available via `require "rooibos/welcome"`. Provides `Model`, `View`, `Update`, and `Init` constants that scaffolded apps delegate to. Features keyboard Tab/Shift+Tab focus cycling, mouse hover states, and clickable buttons for visiting the website or exiting. Use as a starting point or reference for building your own fragments.
|
|
31
|
+
|
|
32
|
+
- **Command::Custom#deconstruct_keys**: Default pattern matching support for custom commands. Introspects public query methods and returns a hash with `:type` as a snake_case discriminator. Data.define members are included automatically. Respects the `keys` argument for performance optimization. Override for hot paths or metaprogrammed methods.
|
|
33
|
+
|
|
34
|
+
- **Rooibos::TestHelper#assert_no_errors**: Test assertion to fail fast when `Message::Error` is unexpectedly present in collected messages. Works with Minitest (via `flunk`) and RSpec (via `raise`). Include via `include Rooibos::TestHelper`.
|
|
35
|
+
|
|
36
|
+
- **Message::Error**: New message type for command errors. Includes `error?` predicate and `deconstruct_keys` for pattern matching with `{ type: :error, command:, exception: }`.
|
|
37
|
+
|
|
38
|
+
- **Message::Canceled**: New message type for canceled commands. Includes `canceled?` predicate (with `cancelled?` alias for British spelling) and `deconstruct_keys` for pattern matching with `{ type: :canceled, command: }`. Custom command authors should emit this when `token.canceled?` is true.
|
|
39
|
+
|
|
40
|
+
- **Message Symbol Comparison**: All `Message::*` types now support symbol comparison via `to_sym` and `==`, similar to RatatuiRuby events. Symbols use the `message_` prefix to avoid collision with event types: `msg == :message_timer`, `msg == :message_http`, `msg == :message_error`. `Message::Predicates` also provides a smart-default `deconstruct_keys` that derives `:type` from the class name.
|
|
41
|
+
|
|
42
|
+
- **Rooibos::Message.=== for case/when dispatch**: The `Rooibos::Message` module now implements `===` for use in case/when statements. Matches only built-in framework message types (classes under `Rooibos::Message::`), rejecting key events and user-defined message classes. Enables Update functions to distinguish framework responses from user input.
|
|
43
|
+
|
|
44
|
+
- **Command.open**: Opens a file or URL with the system's default application. Cross-platform: uses `open` on macOS, `xdg-open` on Linux, `start` on Windows. Sends `Message::Open` on success (exit 0) or `Message::Error` on failure.
|
|
45
|
+
|
|
46
|
+
### Changed
|
|
47
|
+
|
|
48
|
+
- **BREAKING: Rooibos::TestHelper Include Pattern**: `Rooibos::TestHelper` now includes `RatatuiRuby::TestHelper` instead of the other way around. Previously, requiring `rooibos/test_helper` would inject Rooibos assertions into `RatatuiRuby::TestHelper`. Now, use `include Rooibos::TestHelper` to get both Rooibos assertions and RatatuiRuby test terminal helpers. Update your test classes from `include RatatuiRuby::TestHelper` to `include Rooibos::TestHelper`.
|
|
49
|
+
|
|
50
|
+
- **BREAKING: Rooibos.delegate Message Format**: `Rooibos.delegate` now passes `message[1]` (single value) to child UPDATEs instead of `message[1..]` (array slice). This aligns child fragments with the universal `{ type:, envelope: }` pattern. Update pattern matches from `in [{ type: :system, ... }]` to `in { type: :system, ... }`.
|
|
51
|
+
|
|
52
|
+
- **BREAKING: Command::Error → Message::Error**: Moved `Command::Error` to `Message::Error`. Commands flow *out* from Update; Messages flow *in* to Update. Error was always sent *to* Update so it belongs in the Message module. Includes `error?` predicate and `deconstruct_keys` for pattern matching with `{ type: :error, command:, exception: }`. Update pattern matches from `Command::Error` to `Message::Error`.
|
|
53
|
+
|
|
54
|
+
- **BREAKING: Timer/Batch Cancellation → Message::Canceled**: When `Command.wait`, `Command.tick`, `Command.all`, or `Command.batch` are canceled, they now send `Message::Canceled` instead of `Command.cancel(self)`. Custom command authors should do the same: when `token.canceled?`, emit `Message::Canceled.new(command: self)`. Update pattern matches from `in Command::Cancel` to `in Message::Canceled` or `in { type: :canceled, command: }`.
|
|
55
|
+
|
|
56
|
+
- **Dependency Update**: Now requires `ratatui_ruby ~> 1.2.0` (was `~> 1.0.0.beta.3`). This stable release adds inline sync mode for deterministic event ordering in tests.
|
|
57
|
+
|
|
58
|
+
### Fixed
|
|
59
|
+
|
|
60
|
+
- **Init runs after terminal initialization**: `Init` callables now run after the terminal is initialized, enabling them to call `RatatuiRuby.terminal_size`, compute layout areas, or perform other terminal-dependent initialization. Previously Init ran before the terminal was ready, causing "Terminal is not initialized" errors.
|
|
61
|
+
|
|
62
|
+
- **FPS timeout uses float division**: The runtime now uses `1.0 / fps` instead of `1 / fps` for poll timeout calculation. Integer division caused `1 / 60` to yield 0, resulting in busy-wait CPU spinning at 100%.
|
|
63
|
+
|
|
64
|
+
### Removed
|
|
65
|
+
|
|
66
|
+
- **BREAKING: Command::Error class**: Removed. Use `Message::Error` instead.
|
|
67
|
+
- **BREAKING: Command.error factory**: Removed. Use `Message::Error.new(command:, exception:)` instead.
|
|
68
|
+
|
|
24
69
|
## [0.5.0] - 2026-01-16
|
|
25
70
|
|
|
26
71
|
### Added
|
|
@@ -205,6 +250,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
205
250
|
- **First Release**: Empty release of `rooibos`, a Ruby implementation of The Elm Architecture (TEA) for `ratatui_ruby`. Scaffolding generated by `ratatui_ruby-devtools`.
|
|
206
251
|
|
|
207
252
|
[Unreleased]: https://git.sr.ht/~kerrick/rooibos/refs/HEAD
|
|
253
|
+
[0.6.0]: https://git.sr.ht/~kerrick/rooibos/refs/v0.6.0
|
|
208
254
|
[0.5.0]: https://git.sr.ht/~kerrick/rooibos/refs/v0.5.0
|
|
209
255
|
[0.4.0]: https://git.sr.ht/~kerrick/rooibos/refs/v0.4.0
|
|
210
256
|
[0.3.1]: https://git.sr.ht/~kerrick/rooibos/refs/v0.3.1
|
data/README.md
CHANGED
|
@@ -20,7 +20,7 @@ Mailing List: Announcements](https://img.shields.io/badge/mailing_list-announcem
|
|
|
20
20
|
**ratatui_ruby** is a community wrapper that is not affiliated with [the Ratatui team](https://github.com/orgs/ratatui/people).
|
|
21
21
|
|
|
22
22
|
> [!WARNING]
|
|
23
|
-
> **rooibos** is currently in **
|
|
23
|
+
> **rooibos** is currently in **BETA**. The API may change with minor versions.
|
|
24
24
|
|
|
25
25
|
**[Why RatatuiRuby?](https://man.sr.ht/~kerrick/ratatui_ruby/why.md)** — Native Rust performance, zero runtime overhead, and Ruby's expressiveness. [See how we compare](https://man.sr.ht/~kerrick/ratatui_ruby/why.md) to CharmRuby, raw Rust, and Go.
|
|
26
26
|
|
|
@@ -146,7 +146,7 @@ For a full tutorial, see [the Quickstart](./doc/getting_started/quickstart.md).
|
|
|
146
146
|
|
|
147
147
|
## Features
|
|
148
148
|
|
|
149
|
-
_Because this gem is in
|
|
149
|
+
_Because this gem is in alpha, it lacks documentation. Please check the source files._
|
|
150
150
|
|
|
151
151
|
|
|
152
152
|
## Documentation
|
data/README.rdoc
ADDED
|
@@ -0,0 +1,374 @@
|
|
|
1
|
+
== Confidently Build Terminal Apps
|
|
2
|
+
|
|
3
|
+
Rooibos[https://rooibos.run] helps you build interactive terminal applications.
|
|
4
|
+
Keep your code understandable and testable as it scales. Rooibos handles
|
|
5
|
+
keyboard, mouse, and async work so you can focus on behavior and user experience.
|
|
6
|
+
|
|
7
|
+
gem install rooibos
|
|
8
|
+
|
|
9
|
+
<i>Currently in beta. APIs may change before 1.0.</i>
|
|
10
|
+
|
|
11
|
+
=== Get Started in Seconds
|
|
12
|
+
|
|
13
|
+
rooibos new my_app
|
|
14
|
+
cd my_app
|
|
15
|
+
rooibos run
|
|
16
|
+
|
|
17
|
+
That's it. You have a working app with keyboard navigation, mouse support,
|
|
18
|
+
and clickable buttons. Open <tt>lib/my_app.rb</tt> to make it your own.
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
=== The Pattern
|
|
24
|
+
|
|
25
|
+
\Rooibos uses Model-View-Update, the architecture behind
|
|
26
|
+
Elm[https://guide.elm-lang.org/architecture/],
|
|
27
|
+
Redux[https://redux.js.org/], and {Bubble
|
|
28
|
+
Tea}[https://github.com/charmbracelet/bubbletea].
|
|
29
|
+
State lives in one place. Updates flow in one direction. The runtime handles
|
|
30
|
+
rendering and runs background work for you.
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
=== Hello, MVU
|
|
35
|
+
|
|
36
|
+
The simplest \Rooibos app. Press any key to increment the counter. Press
|
|
37
|
+
<tt>Ctrl</tt>+<tt>C</tt> to quit.
|
|
38
|
+
|
|
39
|
+
require "rooibos"
|
|
40
|
+
|
|
41
|
+
module Counter
|
|
42
|
+
# Init: How do you create the initial model?
|
|
43
|
+
Init = -> { 0 }
|
|
44
|
+
|
|
45
|
+
# View: What does the user see?
|
|
46
|
+
View = -> (model, tui) { tui.paragraph(text: <<~END) }
|
|
47
|
+
Current count: #{model}.
|
|
48
|
+
Press any key to increment.
|
|
49
|
+
Press Ctrl+C to quit.
|
|
50
|
+
END
|
|
51
|
+
|
|
52
|
+
# Update: What happens when things change?
|
|
53
|
+
Update = -> (message, model) {
|
|
54
|
+
if message.ctrl_c?
|
|
55
|
+
Rooibos::Command.exit
|
|
56
|
+
elsif message.key?
|
|
57
|
+
model + 1
|
|
58
|
+
end
|
|
59
|
+
}
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
Rooibos.run(Counter)
|
|
63
|
+
|
|
64
|
+
That's the whole pattern: Model holds state, Init creates it, View renders it,
|
|
65
|
+
and Update changes it. The runtime handles everything else.
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
=== Your First Real Application
|
|
71
|
+
|
|
72
|
+
A file browser in sixty lines. It opens files, navigates directories, handles
|
|
73
|
+
errors, styles directories and hidden files differently, and supports vim-style
|
|
74
|
+
keyboard shortcuts. If you can do this much with this little code, imagine how
|
|
75
|
+
easy _your_ app will be to build.
|
|
76
|
+
|
|
77
|
+
require "rooibos"
|
|
78
|
+
|
|
79
|
+
module FileBrowser
|
|
80
|
+
# Model: What state does your app need?
|
|
81
|
+
Model = Data.define(:path, :entries, :selected, :error)
|
|
82
|
+
|
|
83
|
+
Init = -> {
|
|
84
|
+
path = Dir.pwd
|
|
85
|
+
entries = Entries[path]
|
|
86
|
+
Ractor.make_shareable( # Ensures thread safety
|
|
87
|
+
Model.new(path:, entries:, selected: entries.first, error: nil))
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
View = -> (model, tui) {
|
|
91
|
+
tui.block(
|
|
92
|
+
titles: [model.error || model.path,
|
|
93
|
+
{ content: KEYS, position: :bottom, alignment: :right}],
|
|
94
|
+
borders: [:all],
|
|
95
|
+
border_style: if model.error then tui.style(fg: :red) else nil end,
|
|
96
|
+
children: [tui.list(items: model.entries.map(&ListItem[model, tui]),
|
|
97
|
+
selected_index: model.entries.index(model.selected),
|
|
98
|
+
highlight_symbol: "",
|
|
99
|
+
highlight_style: tui.style(modifiers: [:reversed]))]
|
|
100
|
+
)
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
Update = -> (message, model) {
|
|
104
|
+
return model.with(error: ERROR) if message.error?
|
|
105
|
+
model = model.with(error: nil) if model.error && message.key?
|
|
106
|
+
|
|
107
|
+
if message.ctrl_c? || message.q? then Rooibos::Command.exit
|
|
108
|
+
elsif message.home? || message.g? then model.with(selected: model.entries.first)
|
|
109
|
+
elsif message.end? || message.G? then model.with(selected: model.entries.last)
|
|
110
|
+
elsif message.up_arrow? || message.k? then Select[:-, model]
|
|
111
|
+
elsif message.down_arrow? || message.j? then Select[:+, model]
|
|
112
|
+
elsif message.enter? then Open[model]
|
|
113
|
+
elsif message.escape? then Navigate[File.dirname(model.path), model]
|
|
114
|
+
end
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
private # Lines below this are implementation details
|
|
118
|
+
|
|
119
|
+
KEYS = "↑/↓/Home/End: Select | Enter: Open | Esc: Navigate Up | q: Quit"
|
|
120
|
+
ERROR = "Sorry, opening the selected file failed."
|
|
121
|
+
|
|
122
|
+
ListItem = -> (model, tui) { -> (name) {
|
|
123
|
+
modifiers = name.start_with?(".") ? [:dim] : []
|
|
124
|
+
fg = :blue if name.end_with?("/")
|
|
125
|
+
tui.list_item(content: name, style: tui.style(fg:, modifiers:))
|
|
126
|
+
} }
|
|
127
|
+
|
|
128
|
+
Select = -> (operator, model) {
|
|
129
|
+
new_index = model.entries.index(model.selected).public_send(operator, 1)
|
|
130
|
+
model.with(selected: model.entries[new_index.clamp(0, model.entries.length - 1)])
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
Open = -> (model) {
|
|
134
|
+
full = File.join(model.path, model.selected.delete_suffix("/"))
|
|
135
|
+
model.selected.end_with?("/") ? Navigate[full, model] : Rooibos::Command.open(full)
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
Navigate = -> (path, model) {
|
|
139
|
+
entries = Entries[path]
|
|
140
|
+
model.with(path:, entries:, selected: entries.first, error: nil)
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
Entries = -> (path) {
|
|
144
|
+
Dir.children(path).map { |name|
|
|
145
|
+
File.directory?(File.join(path, name)) ? "#{name}/" : name
|
|
146
|
+
}.sort_by { |name| [name.end_with?("/") ? 0 : 1, name.downcase] }
|
|
147
|
+
}
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
Rooibos.run(FileBrowser)
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
=== Batteries Included
|
|
156
|
+
|
|
157
|
+
==== Commands
|
|
158
|
+
|
|
159
|
+
Applications fetch data, run shell commands, and set timers. \Rooibos Commands
|
|
160
|
+
run off the main thread and send results back as messages.
|
|
161
|
+
|
|
162
|
+
<b>HTTP requests:</b>
|
|
163
|
+
|
|
164
|
+
Update = -> (message, model) {
|
|
165
|
+
case message
|
|
166
|
+
in :fetch_users
|
|
167
|
+
[model.with(loading: true), Rooibos::Command.http(:get, "/api/users", :got_users)]
|
|
168
|
+
in { type: :http, envelope: :got_users, status: 200, body: }
|
|
169
|
+
model.with(loading: false, users: JSON.parse(body))
|
|
170
|
+
in { type: :http, envelope: :got_users, status: }
|
|
171
|
+
model.with(error: "HTTP #{status}")
|
|
172
|
+
end
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
<b>Shell commands:</b>
|
|
176
|
+
|
|
177
|
+
Update = -> (message, model) {
|
|
178
|
+
case message
|
|
179
|
+
in :list_files
|
|
180
|
+
Rooibos::Command.system("ls -la", :listed_files)
|
|
181
|
+
in { type: :system, envelope: :listed_files, stdout:, status: 0 }
|
|
182
|
+
model.with(files: stdout.lines.map(&:chomp))
|
|
183
|
+
in { type: :system, envelope: :listed_files, stderr:, status: }
|
|
184
|
+
model.with(error: stderr)
|
|
185
|
+
end
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
<b>Timers:</b>
|
|
189
|
+
|
|
190
|
+
Update = -> (message, model) {
|
|
191
|
+
case message
|
|
192
|
+
in { type: :timer, envelope: :tick, elapsed: }
|
|
193
|
+
[model.with(frame: model.frame + 1), Rooibos::Command.wait(1.0 / 24, :tick)]
|
|
194
|
+
end
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
<b>And more!</b> \Rooibos includes <tt>all</tt>, <tt>batch</tt>, <tt>cancel</tt>,
|
|
198
|
+
<tt>custom</tt>, <tt>exit</tt>, <tt>http</tt>, <tt>map</tt>, <tt>open</tt>,
|
|
199
|
+
<tt>system</tt>, <tt>tick</tt>, and <tt>wait</tt> commands. You can also define
|
|
200
|
+
your own custom commands for complex orchestration.
|
|
201
|
+
|
|
202
|
+
Every command produces a message, and Update handles it the same way.
|
|
203
|
+
|
|
204
|
+
==== Testing
|
|
205
|
+
|
|
206
|
+
\Rooibos makes TUIs so easy to test, you'll save more time by writing tests than
|
|
207
|
+
by not testing.
|
|
208
|
+
|
|
209
|
+
<b>Unit test Update, View, and Init.</b> No terminal needed. Test helpers included.
|
|
210
|
+
|
|
211
|
+
def test_moves_selection_down_with_j
|
|
212
|
+
model = Ractor.make_shareable(FileBrowser::Model.new(
|
|
213
|
+
path: "/", entries: %w[bin exe lib], selected: "bin", error: nil))
|
|
214
|
+
message = RatatuiRuby::Event::Key.new(code: "j")
|
|
215
|
+
|
|
216
|
+
result = FileBrowser::Update.call(message, model)
|
|
217
|
+
|
|
218
|
+
assert_equal "exe", result.selected
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
<b>Style assertions.</b> Draw to a headless terminal, verify colors and modifiers.
|
|
222
|
+
|
|
223
|
+
def test_directories_are_blue
|
|
224
|
+
with_test_terminal(60, 10) do
|
|
225
|
+
model = Ractor.make_shareable(FileBrowser::Model.new(
|
|
226
|
+
path: "/", entries: %w[file.txt subdir/], selected: "file.txt", error: nil))
|
|
227
|
+
widget = FileBrowser::View.call(model, RatatuiRuby::TUI.new)
|
|
228
|
+
|
|
229
|
+
RatatuiRuby.draw { |frame| frame.render_widget(widget, frame.area) }
|
|
230
|
+
|
|
231
|
+
assert_blue(1, 2) # "subdir/" at column 1, row 2
|
|
232
|
+
end
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
<b>System tests.</b> Inject events, run the full app, snapshot the result.
|
|
236
|
+
|
|
237
|
+
def test_selection_moves_down
|
|
238
|
+
with_test_terminal(120, 30) do
|
|
239
|
+
Dir.mktmpdir do |dir|
|
|
240
|
+
FileUtils.touch(File.join(dir, "a"))
|
|
241
|
+
FileUtils.touch(File.join(dir, "b"))
|
|
242
|
+
FileUtils.touch(File.join(dir, "c"))
|
|
243
|
+
|
|
244
|
+
inject_key(:down)
|
|
245
|
+
inject_key(:ctrl_c)
|
|
246
|
+
|
|
247
|
+
# Tests use explicit params to inject deterministic initial state.
|
|
248
|
+
Rooibos.run(
|
|
249
|
+
model: Ractor.make_shareable(FileBrowser::Model.new(
|
|
250
|
+
path: dir, entries: %w[a b c], selected: "a", error: nil)),
|
|
251
|
+
view: FileBrowser::View,
|
|
252
|
+
update: FileBrowser::Update
|
|
253
|
+
)
|
|
254
|
+
|
|
255
|
+
assert_snapshots("selection_moved_down") do |lines|
|
|
256
|
+
title = "┌/tmp/test#{'─' * 107}┐"
|
|
257
|
+
lines.map do |l|
|
|
258
|
+
l.gsub(/┌#{Regexp.escape(dir)}[^┐]*┐/, title)
|
|
259
|
+
end
|
|
260
|
+
end
|
|
261
|
+
end
|
|
262
|
+
end
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
Snapshots record both plain text and ANSI colors. Normalization blocks mask
|
|
266
|
+
dynamic content (timestamps, temp paths) for cross-platform reproducibility.
|
|
267
|
+
Run <tt>UPDATE_SNAPSHOTS=1 rake test</tt> to regenerate baselines.
|
|
268
|
+
|
|
269
|
+
==== Scale Up
|
|
270
|
+
|
|
271
|
+
Large applications decompose into fragments. Each fragment has its own Model,
|
|
272
|
+
View, Update, and Init. Parents compose children. The pattern scales.
|
|
273
|
+
|
|
274
|
+
The Router DSL eliminates boilerplate:
|
|
275
|
+
|
|
276
|
+
module Dashboard
|
|
277
|
+
include Rooibos::Router
|
|
278
|
+
|
|
279
|
+
route :stats, to: StatsPanel
|
|
280
|
+
route :network, to: NetworkPanel
|
|
281
|
+
|
|
282
|
+
keymap do
|
|
283
|
+
key :ctrl_c, -> { Rooibos::Command.exit }
|
|
284
|
+
only when: -> (model) { !model.modal_open } do
|
|
285
|
+
key :q, -> { Rooibos::Command.exit }
|
|
286
|
+
key :s, -> { StatsPanel.fetch_command }
|
|
287
|
+
key :p, -> { NetworkPanel.ping_command }
|
|
288
|
+
end
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
Update = from_router
|
|
292
|
+
|
|
293
|
+
# ... Model, Init, View below
|
|
294
|
+
end
|
|
295
|
+
|
|
296
|
+
Declare routes and keymaps. The router generates Update for you. Use guards to
|
|
297
|
+
ignore keys when needed.
|
|
298
|
+
|
|
299
|
+
==== CLI
|
|
300
|
+
|
|
301
|
+
The <tt>rooibos</tt> command scaffolds projects and runs applications.
|
|
302
|
+
|
|
303
|
+
rooibos new my_app # Generate project structure
|
|
304
|
+
rooibos run # Run the app in current directory
|
|
305
|
+
|
|
306
|
+
Generated apps include tests, type signatures, and a working welcome
|
|
307
|
+
screen with keyboard and mouse support.
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
---
|
|
311
|
+
|
|
312
|
+
=== The Ecosystem
|
|
313
|
+
|
|
314
|
+
\Rooibos builds on RatatuiRuby[https://www.ratatui-ruby.dev], a Rubygem built on
|
|
315
|
+
Ratatui[https://ratatui.rs]. You get native performance with the joy of Ruby.
|
|
316
|
+
\Rooibos is one way to manage state and composition. Kit is another.
|
|
317
|
+
|
|
318
|
+
==== Rooibos[https://git.sr.ht/~kerrick/rooibos]
|
|
319
|
+
|
|
320
|
+
Model-View-Update architecture. Inspired by Elm, Bubble Tea, and React +
|
|
321
|
+
Redux. Your UI is a pure function of state.
|
|
322
|
+
|
|
323
|
+
- Functional programming with MVU
|
|
324
|
+
- Commands work off the main thread
|
|
325
|
+
- Messages, not callbacks, drive updates
|
|
326
|
+
|
|
327
|
+
==== {Kit}[https://sr.ht/~kerrick/ratatui_ruby/#chapter-3-the-object-path--kit] (Coming Soon)
|
|
328
|
+
|
|
329
|
+
Component-based architecture. Encapsulate state, input handling, and
|
|
330
|
+
rendering in reusable pieces.
|
|
331
|
+
|
|
332
|
+
- OOP with stateful components
|
|
333
|
+
- Separate UI state from domain logic
|
|
334
|
+
- Built-in focus management & click handling
|
|
335
|
+
|
|
336
|
+
Both use the same widget library and rendering engine. Pick the paradigm
|
|
337
|
+
that fits your brain.
|
|
338
|
+
|
|
339
|
+
|
|
340
|
+
---
|
|
341
|
+
|
|
342
|
+
=== Links
|
|
343
|
+
|
|
344
|
+
[Get Started]
|
|
345
|
+
{Getting Started}[https://git.sr.ht/~kerrick/rooibos/tree/trunk/item/doc/getting_started/index.md],
|
|
346
|
+
{Tutorial}[https://git.sr.ht/~kerrick/rooibos/tree/trunk/item/doc/tutorial/index.md],
|
|
347
|
+
{Examples}[https://git.sr.ht/~kerrick/rooibos/tree/trunk/item/examples]
|
|
348
|
+
|
|
349
|
+
[Coming From...]
|
|
350
|
+
{React/Redux}[https://git.sr.ht/~kerrick/rooibos/tree/trunk/item/doc/getting_started/for_react_developers.md],
|
|
351
|
+
{BubbleTea}[https://git.sr.ht/~kerrick/rooibos/tree/trunk/item/doc/getting_started/for_go_developers.md],
|
|
352
|
+
{Textual}[https://git.sr.ht/~kerrick/rooibos/tree/trunk/item/doc/getting_started/for_python_developers.md]
|
|
353
|
+
|
|
354
|
+
[Learn More]
|
|
355
|
+
{Essentials}[https://git.sr.ht/~kerrick/rooibos/tree/trunk/item/doc/essentials/index.md],
|
|
356
|
+
{Scaling Up}[https://git.sr.ht/~kerrick/rooibos/tree/trunk/item/doc/scaling_up/index.md],
|
|
357
|
+
{Best Practices}[https://git.sr.ht/~kerrick/rooibos/tree/trunk/item/doc/best_practices/index.md],
|
|
358
|
+
{Troubleshooting}[https://git.sr.ht/~kerrick/rooibos/tree/trunk/item/doc/troubleshooting/index.md]
|
|
359
|
+
|
|
360
|
+
[Community]
|
|
361
|
+
{Discuss}[https://lists.sr.ht/~kerrick/ratatui_ruby-discuss],
|
|
362
|
+
{Announcements}[https://lists.sr.ht/~kerrick/ratatui_ruby-announce],
|
|
363
|
+
{Bug Tracker}[https://todo.sr.ht/~kerrick/ratatui_ruby],
|
|
364
|
+
{Contribution Guide}[https://man.sr.ht/~kerrick/ratatui_ruby/contributing.md],
|
|
365
|
+
{Code of Conduct}[https://man.sr.ht/~kerrick/ratatui_ruby/code_of_conduct.md]
|
|
366
|
+
|
|
367
|
+
|
|
368
|
+
---
|
|
369
|
+
|
|
370
|
+
[Website] https://rooibos.run
|
|
371
|
+
[Source] https://git.sr.ht/~kerrick/rooibos
|
|
372
|
+
[RubyGems] https://rubygems.org/gems/rooibos
|
|
373
|
+
|
|
374
|
+
© 2026 Kerrick Long · Library: LGPL-3.0-or-later · Website: CC-BY-NC-ND-4.0 · Snippets: MIT-0
|
data/REUSE.toml
CHANGED
|
@@ -8,6 +8,11 @@ path = 'Gemfile.lock'
|
|
|
8
8
|
SPDX-FileCopyrightText = "2026 Kerrick Long <me@kerricklong.com>"
|
|
9
9
|
SPDX-License-Identifier = "CC0-1.0"
|
|
10
10
|
|
|
11
|
+
[[annotations]]
|
|
12
|
+
path = 'README.rdoc'
|
|
13
|
+
SPDX-FileCopyrightText = "2025 Kerrick Long <me@kerricklong.com>"
|
|
14
|
+
SPDX-License-Identifier = "CC-BY-SA-4.0"
|
|
15
|
+
|
|
11
16
|
[[annotations]]
|
|
12
17
|
path = '**/snapshots/*.txt'
|
|
13
18
|
SPDX-FileCopyrightText = "2026 Kerrick Long <me@kerricklong.com>"
|
data/Rakefile
CHANGED