rooibos 0.5.0 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 +57 -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_rails_developers.md +17 -0
- data/doc/getting_started/for_ratatui_ruby_developers.md +17 -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 +76 -23
- data/lib/rooibos/command/batch.rb +61 -34
- data/lib/rooibos/command/custom.rb +84 -1
- data/lib/rooibos/command/http.rb +121 -55
- data/lib/rooibos/command/lifecycle.rb +5 -5
- data/lib/rooibos/command/open.rb +93 -0
- data/lib/rooibos/command/outlet.rb +105 -3
- data/lib/rooibos/command/wait.rb +9 -6
- data/lib/rooibos/command.rb +114 -89
- 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 +4 -0
- data/sig/gem.rbs +20 -0
- data/sig/rooibos/cli.rbs +42 -0
- data/sig/rooibos/command.rbs +59 -7
- data/sig/rooibos/message.rbs +66 -2
- 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 +274 -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
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
#--
|
|
2
|
+
# SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
|
|
3
|
+
# SPDX-License-Identifier: LGPL-3.0-or-later
|
|
4
|
+
#++
|
|
5
|
+
|
|
6
|
+
module Rooibos
|
|
7
|
+
# Built-in welcome screen used by scaffolded applications.
|
|
8
|
+
module Welcome
|
|
9
|
+
WEBSITE_URL: String
|
|
10
|
+
|
|
11
|
+
# Internal UI module for styles and widgets.
|
|
12
|
+
module UI
|
|
13
|
+
module Styles
|
|
14
|
+
TEXT: RatatuiRuby::Style::Style
|
|
15
|
+
FILENAME: RatatuiRuby::Style::Style
|
|
16
|
+
COMMAND: RatatuiRuby::Style::Style
|
|
17
|
+
URL: RatatuiRuby::Style::Style
|
|
18
|
+
COMMAND_BUTTON: RatatuiRuby::Style::Style
|
|
19
|
+
COMMAND_BUTTON_FOCUS: RatatuiRuby::Style::Style
|
|
20
|
+
COMMAND_BUTTON_HOVER: RatatuiRuby::Style::Style
|
|
21
|
+
COMMAND_BUTTON_BOTH: RatatuiRuby::Style::Style
|
|
22
|
+
URL_BUTTON: RatatuiRuby::Style::Style
|
|
23
|
+
URL_BUTTON_FOCUS: RatatuiRuby::Style::Style
|
|
24
|
+
URL_BUTTON_HOVER: RatatuiRuby::Style::Style
|
|
25
|
+
URL_BUTTON_BOTH: RatatuiRuby::Style::Style
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
module Widgets
|
|
29
|
+
WELCOME_TEXT: Hash[String, RatatuiRuby::Style::Style]
|
|
30
|
+
PARAGRAPH: RatatuiRuby::Widgets::Paragraph
|
|
31
|
+
def self.website_button: (?focused: bool, ?hovered: bool) -> RatatuiRuby::Text::Span
|
|
32
|
+
def self.exit_button: (?focused: bool, ?hovered: bool) -> RatatuiRuby::Text::Span
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
BUTTON_SLOTS: Hash[Symbol, Integer]
|
|
36
|
+
FOCUS_ORDER: Array[Symbol]
|
|
37
|
+
BUTTON_BAR_CONSTRAINTS: Array[RatatuiRuby::Layout::Constraint]
|
|
38
|
+
CONTENT_CONSTRAINTS: Array[RatatuiRuby::Layout::Constraint]
|
|
39
|
+
|
|
40
|
+
def self.button_bar: (focused: Symbol?, hovered: Symbol?) -> RatatuiRuby::Layout::Layout
|
|
41
|
+
def self.content_layout: (focused: Symbol?, hovered: Symbol?) -> RatatuiRuby::Layout::Layout
|
|
42
|
+
def self.frame: (focused: Symbol?, hovered: Symbol?) -> RatatuiRuby::Widgets::Block
|
|
43
|
+
|
|
44
|
+
# Value object for button hit-test areas.
|
|
45
|
+
class ButtonAreas
|
|
46
|
+
attr_reader website: RatatuiRuby::Layout::Rect?
|
|
47
|
+
attr_reader exit: RatatuiRuby::Layout::Rect?
|
|
48
|
+
def initialize: (website: RatatuiRuby::Layout::Rect?, exit: RatatuiRuby::Layout::Rect?) -> void
|
|
49
|
+
def contains?: (Symbol name, Integer x, Integer y) -> bool
|
|
50
|
+
def button_at: (Integer x, Integer y) -> Symbol?
|
|
51
|
+
def for_viewport: (Integer width, Integer height) -> ButtonAreas
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Model for Welcome screen state.
|
|
56
|
+
class Model
|
|
57
|
+
attr_reader button_areas: UI::ButtonAreas
|
|
58
|
+
attr_reader focused: Symbol?
|
|
59
|
+
attr_reader hovered: Symbol?
|
|
60
|
+
def initialize: (button_areas: UI::ButtonAreas, focused: Symbol?, hovered: Symbol?) -> void
|
|
61
|
+
def tree: () -> RatatuiRuby::Widgets::Block
|
|
62
|
+
def active_button: () -> Symbol?
|
|
63
|
+
def with: (?button_areas: UI::ButtonAreas, ?focused: Symbol?, ?hovered: Symbol?) -> Model
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
View: ^(Model, untyped) -> RatatuiRuby::Widgets::Block
|
|
67
|
+
Update: ^(untyped, Model) -> (Model | Command::Exit | [Model, Command::System])
|
|
68
|
+
Init: ^() -> Model
|
|
69
|
+
|
|
70
|
+
def self.handle_click: (untyped message, Model model) -> (Model | Command::Exit | [Model, Command::System])
|
|
71
|
+
def self.handle_hover: (untyped message, Model model) -> Model
|
|
72
|
+
def self.cycle_focus: (Model model, Symbol direction) -> Model
|
|
73
|
+
def self.activate_button: (Symbol? button, Model model) -> (Model | Command::Exit | [Model, Command::System])
|
|
74
|
+
end
|
|
75
|
+
end
|
data/tasks/install.rake
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
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
|
+
require "rubygems"
|
|
9
|
+
|
|
10
|
+
namespace :install do
|
|
11
|
+
desc "Force install rooibos gem globally (required for integration tests)"
|
|
12
|
+
task :force do
|
|
13
|
+
require "rooibos/version"
|
|
14
|
+
|
|
15
|
+
# Build the gem first
|
|
16
|
+
Rake::Task["build"].invoke
|
|
17
|
+
|
|
18
|
+
gem_file = "pkg/rooibos-#{Rooibos::VERSION}.gem"
|
|
19
|
+
unless File.exist?(gem_file)
|
|
20
|
+
abort "Gem not found at #{gem_file}. Run 'rake build' first."
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
puts "Installing rooibos #{Rooibos::VERSION} globally..."
|
|
24
|
+
system("gem", "install", gem_file, "--force", "--no-document") ||
|
|
25
|
+
abort("Failed to install gem")
|
|
26
|
+
|
|
27
|
+
puts "✓ rooibos #{Rooibos::VERSION} installed globally"
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -40,6 +40,8 @@ tasks:
|
|
|
40
40
|
- test: |
|
|
41
41
|
. ~/.buildenv
|
|
42
42
|
cd <%= gem_name %>
|
|
43
|
+
echo "Installing rooibos gem globally for integration tests..."
|
|
44
|
+
mise x -- bundle exec rake install:force
|
|
43
45
|
echo "Testing Ruby <%= ruby_version %>"
|
|
44
46
|
mise x -- bundle exec rake test
|
|
45
47
|
- lint: |
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rooibos
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.6.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Kerrick Long
|
|
@@ -15,28 +15,14 @@ dependencies:
|
|
|
15
15
|
requirements:
|
|
16
16
|
- - "~>"
|
|
17
17
|
- !ruby/object:Gem::Version
|
|
18
|
-
version:
|
|
18
|
+
version: '1.2'
|
|
19
19
|
type: :runtime
|
|
20
20
|
prerelease: false
|
|
21
21
|
version_requirements: !ruby/object:Gem::Requirement
|
|
22
22
|
requirements:
|
|
23
23
|
- - "~>"
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
|
-
version:
|
|
26
|
-
- !ruby/object:Gem::Dependency
|
|
27
|
-
name: ostruct
|
|
28
|
-
requirement: !ruby/object:Gem::Requirement
|
|
29
|
-
requirements:
|
|
30
|
-
- - "~>"
|
|
31
|
-
- !ruby/object:Gem::Version
|
|
32
|
-
version: '0.6'
|
|
33
|
-
type: :runtime
|
|
34
|
-
prerelease: false
|
|
35
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
36
|
-
requirements:
|
|
37
|
-
- - "~>"
|
|
38
|
-
- !ruby/object:Gem::Version
|
|
39
|
-
version: '0.6'
|
|
25
|
+
version: '1.2'
|
|
40
26
|
- !ruby/object:Gem::Dependency
|
|
41
27
|
name: concurrent-ruby
|
|
42
28
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -93,11 +79,168 @@ dependencies:
|
|
|
93
79
|
- - "~>"
|
|
94
80
|
- !ruby/object:Gem::Version
|
|
95
81
|
version: '3.5'
|
|
96
|
-
|
|
82
|
+
- !ruby/object:Gem::Dependency
|
|
83
|
+
name: minitest-mock
|
|
84
|
+
requirement: !ruby/object:Gem::Requirement
|
|
85
|
+
requirements:
|
|
86
|
+
- - "~>"
|
|
87
|
+
- !ruby/object:Gem::Version
|
|
88
|
+
version: '5.27'
|
|
89
|
+
type: :development
|
|
90
|
+
prerelease: false
|
|
91
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
92
|
+
requirements:
|
|
93
|
+
- - "~>"
|
|
94
|
+
- !ruby/object:Gem::Version
|
|
95
|
+
version: '5.27'
|
|
96
|
+
description: "== Confidently Build Terminal Apps\n\nRooibos[https://rooibos.run] helps
|
|
97
|
+
you build interactive terminal applications.\nKeep your code understandable and
|
|
98
|
+
testable as it scales. Rooibos handles\nkeyboard, mouse, and async work so you can
|
|
99
|
+
focus on behavior and user experience.\n\n gem install rooibos\n\n<i>Currently
|
|
100
|
+
in beta. APIs may change before 1.0.</i>\n\n=== Get Started in Seconds\n\n rooibos
|
|
101
|
+
new my_app\n cd my_app\n rooibos run\n\nThat's it. You have a working app with
|
|
102
|
+
keyboard navigation, mouse support,\nand clickable buttons. Open <tt>lib/my_app.rb</tt>
|
|
103
|
+
to make it your own.\n\n\n---\n\n=== The Pattern\n\n\\Rooibos uses Model-View-Update,
|
|
104
|
+
the architecture behind\nElm[https://guide.elm-lang.org/architecture/],\nRedux[https://redux.js.org/],
|
|
105
|
+
and {Bubble\nTea}[https://github.com/charmbracelet/bubbletea].\nState lives in one
|
|
106
|
+
place. Updates flow in one direction. The runtime handles\nrendering and runs background
|
|
107
|
+
work for you.\n\n---\n\n=== Hello, MVU\n\nThe simplest \\Rooibos app. Press any
|
|
108
|
+
key to increment the counter. Press\n<tt>Ctrl</tt>+<tt>C</tt> to quit.\n\n require
|
|
109
|
+
\"rooibos\"\n\n module Counter\n # Init: How do you create the initial model?\n
|
|
110
|
+
\ Init = -> { 0 }\n \n # View: What does the user see?\n View = -> (model,
|
|
111
|
+
tui) { tui.paragraph(text: <<~END) }\n Current count: #{model}.\n Press
|
|
112
|
+
any key to increment.\n Press Ctrl+C to quit.\n END\n \n # Update: What
|
|
113
|
+
happens when things change?\n Update = -> (message, model) {\n if message.ctrl_c?\n
|
|
114
|
+
\ Rooibos::Command.exit\n elsif message.key?\n model + 1\n end\n
|
|
115
|
+
\ }\n end\n\n Rooibos.run(Counter)\n\nThat's the whole pattern: Model holds
|
|
116
|
+
state, Init creates it, View renders it,\nand Update changes it. The runtime handles
|
|
117
|
+
everything else.\n\n\n---\n\n=== Your First Real Application\n\nA file browser in
|
|
118
|
+
sixty lines. It opens files, navigates directories, handles\nerrors, styles directories
|
|
119
|
+
and hidden files differently, and supports vim-style\nkeyboard shortcuts. If you
|
|
120
|
+
can do this much with this little code, imagine how\neasy _your_ app will be to
|
|
121
|
+
build.\n\n require \"rooibos\"\n \n module FileBrowser\n # Model: What state
|
|
122
|
+
does your app need?\n Model = Data.define(:path, :entries, :selected, :error)\n
|
|
123
|
+
\ \n Init = -> {\n path = Dir.pwd\n entries = Entries[path]\n Ractor.make_shareable(
|
|
124
|
+
# Ensures thread safety\n Model.new(path:, entries:, selected: entries.first,
|
|
125
|
+
error: nil))\n }\n \n View = -> (model, tui) {\n tui.block(\n titles:
|
|
126
|
+
[model.error || model.path,\n { content: KEYS, position: :bottom,
|
|
127
|
+
alignment: :right}],\n borders: [:all],\n border_style: if model.error
|
|
128
|
+
then tui.style(fg: :red) else nil end,\n children: [tui.list(items: model.entries.map(&ListItem[model,
|
|
129
|
+
tui]),\n selected_index: model.entries.index(model.selected),\n
|
|
130
|
+
\ highlight_symbol: \"\",\n highlight_style:
|
|
131
|
+
tui.style(modifiers: [:reversed]))]\n )\n }\n \n Update = -> (message,
|
|
132
|
+
model) {\n return model.with(error: ERROR) if message.error?\n model =
|
|
133
|
+
model.with(error: nil) if model.error && message.key?\n \n if message.ctrl_c?
|
|
134
|
+
|| message.q? then Rooibos::Command.exit\n elsif message.home? || message.g?
|
|
135
|
+
then model.with(selected: model.entries.first)\n elsif message.end? || message.G?
|
|
136
|
+
then model.with(selected: model.entries.last)\n elsif message.up_arrow? ||
|
|
137
|
+
message.k? then Select[:-, model]\n elsif message.down_arrow? || message.j?
|
|
138
|
+
then Select[:+, model]\n elsif message.enter? then Open[model]\n elsif
|
|
139
|
+
message.escape? then Navigate[File.dirname(model.path), model]\n end\n }\n
|
|
140
|
+
\ \n private # Lines below this are implementation details\n \n KEYS = \"↑/↓/Home/End:
|
|
141
|
+
Select | Enter: Open | Esc: Navigate Up | q: Quit\"\n ERROR = \"Sorry, opening
|
|
142
|
+
the selected file failed.\"\n \n ListItem = -> (model, tui) { -> (name) {\n
|
|
143
|
+
\ modifiers = name.start_with?(\".\") ? [:dim] : []\n fg = :blue
|
|
144
|
+
if name.end_with?(\"/\")\n tui.list_item(content: name, style: tui.style(fg:,
|
|
145
|
+
modifiers:))\n } }\n \n Select = -> (operator, model) {\n new_index
|
|
146
|
+
= model.entries.index(model.selected).public_send(operator, 1)\n model.with(selected:
|
|
147
|
+
model.entries[new_index.clamp(0, model.entries.length - 1)])\n }\n \n Open
|
|
148
|
+
= -> (model) {\n full = File.join(model.path, model.selected.delete_suffix(\"/\"))\n
|
|
149
|
+
\ model.selected.end_with?(\"/\") ? Navigate[full, model] : Rooibos::Command.open(full)\n
|
|
150
|
+
\ }\n \n Navigate = -> (path, model) {\n entries = Entries[path]\n model.with(path:,
|
|
151
|
+
entries:, selected: entries.first, error: nil)\n }\n \n Entries = -> (path)
|
|
152
|
+
{\n Dir.children(path).map { |name|\n File.directory?(File.join(path,
|
|
153
|
+
name)) ? \"#{name}/\" : name\n }.sort_by { |name| [name.end_with?(\"/\") ?
|
|
154
|
+
0 : 1, name.downcase] }\n }\n end\n\n Rooibos.run(FileBrowser)\n\n\n---\n\n===
|
|
155
|
+
Batteries Included\n\n==== Commands\n\nApplications fetch data, run shell commands,
|
|
156
|
+
and set timers. \\Rooibos Commands\nrun off the main thread and send results back
|
|
157
|
+
as messages.\n\n<b>HTTP requests:</b>\n\n Update = -> (message, model) {\n case
|
|
158
|
+
message\n in :fetch_users\n [model.with(loading: true), Rooibos::Command.http(:get,
|
|
159
|
+
\"/api/users\", :got_users)]\n in { type: :http, envelope: :got_users, status:
|
|
160
|
+
200, body: }\n model.with(loading: false, users: JSON.parse(body))\n in
|
|
161
|
+
{ type: :http, envelope: :got_users, status: }\n model.with(error: \"HTTP #{status}\")\n
|
|
162
|
+
\ end\n }\n\n<b>Shell commands:</b>\n\n Update = -> (message, model) {\n case
|
|
163
|
+
message\n in :list_files\n Rooibos::Command.system(\"ls -la\", :listed_files)\n
|
|
164
|
+
\ in { type: :system, envelope: :listed_files, stdout:, status: 0 }\n model.with(files:
|
|
165
|
+
stdout.lines.map(&:chomp))\n in { type: :system, envelope: :listed_files, stderr:,
|
|
166
|
+
status: }\n model.with(error: stderr)\n end\n }\n\n<b>Timers:</b>\n\n Update
|
|
167
|
+
= -> (message, model) {\n case message\n in { type: :timer, envelope: :tick,
|
|
168
|
+
elapsed: }\n [model.with(frame: model.frame + 1), Rooibos::Command.wait(1.0
|
|
169
|
+
/ 24, :tick)]\n end\n }\n\n<b>And more!</b> \\Rooibos includes <tt>all</tt>,
|
|
170
|
+
<tt>batch</tt>, <tt>cancel</tt>,\n<tt>custom</tt>, <tt>exit</tt>, <tt>http</tt>,
|
|
171
|
+
<tt>map</tt>, <tt>open</tt>,\n<tt>system</tt>, <tt>tick</tt>, and <tt>wait</tt>
|
|
172
|
+
commands. You can also define\nyour own custom commands for complex orchestration.
|
|
173
|
+
\n\nEvery command produces a message, and Update handles it the same way.\n\n====
|
|
174
|
+
Testing\n\n\\Rooibos makes TUIs so easy to test, you'll save more time by writing
|
|
175
|
+
tests than\nby not testing.\n\n<b>Unit test Update, View, and Init.</b> No terminal
|
|
176
|
+
needed. Test helpers included.\n\n def test_moves_selection_down_with_j\n model
|
|
177
|
+
= Ractor.make_shareable(FileBrowser::Model.new(\n path: \"/\", entries: %w[bin
|
|
178
|
+
exe lib], selected: \"bin\", error: nil))\n message = RatatuiRuby::Event::Key.new(code:
|
|
179
|
+
\"j\")\n\n result = FileBrowser::Update.call(message, model)\n\n assert_equal
|
|
180
|
+
\"exe\", result.selected\n end\n\n<b>Style assertions.</b> Draw to a headless terminal,
|
|
181
|
+
verify colors and modifiers.\n\n def test_directories_are_blue\n with_test_terminal(60,
|
|
182
|
+
10) do\n model = Ractor.make_shareable(FileBrowser::Model.new(\n path:
|
|
183
|
+
\"/\", entries: %w[file.txt subdir/], selected: \"file.txt\", error: nil))\n widget
|
|
184
|
+
= FileBrowser::View.call(model, RatatuiRuby::TUI.new)\n\n RatatuiRuby.draw
|
|
185
|
+
{ |frame| frame.render_widget(widget, frame.area) }\n\n assert_blue(1, 2) #
|
|
186
|
+
\"subdir/\" at column 1, row 2\n end\n end\n\n<b>System tests.</b> Inject events,
|
|
187
|
+
run the full app, snapshot the result.\n\n def test_selection_moves_down\n with_test_terminal(120,
|
|
188
|
+
30) do\n Dir.mktmpdir do |dir|\n FileUtils.touch(File.join(dir, \"a\"))\n
|
|
189
|
+
\ FileUtils.touch(File.join(dir, \"b\"))\n FileUtils.touch(File.join(dir,
|
|
190
|
+
\"c\"))\n\n inject_key(:down)\n inject_key(:ctrl_c)\n\n # Tests
|
|
191
|
+
use explicit params to inject deterministic initial state.\n Rooibos.run(\n
|
|
192
|
+
\ model: Ractor.make_shareable(FileBrowser::Model.new(\n path:
|
|
193
|
+
dir, entries: %w[a b c], selected: \"a\", error: nil)),\n view: FileBrowser::View,\n
|
|
194
|
+
\ update: FileBrowser::Update\n )\n\n assert_snapshots(\"selection_moved_down\")
|
|
195
|
+
do |lines|\n title = \"┌/tmp/test#{'─' * 107}┐\"\n lines.map do
|
|
196
|
+
|l|\n l.gsub(/┌#{Regexp.escape(dir)}[^┐]*┐/, title)\n end\n
|
|
197
|
+
\ end\n end\n end\n end\n\nSnapshots record both plain text and ANSI
|
|
198
|
+
colors. Normalization blocks mask\ndynamic content (timestamps, temp paths) for
|
|
199
|
+
cross-platform reproducibility.\nRun <tt>UPDATE_SNAPSHOTS=1 rake test</tt> to regenerate
|
|
200
|
+
baselines.\n\n==== Scale Up\n\nLarge applications decompose into fragments. Each
|
|
201
|
+
fragment has its own Model,\nView, Update, and Init. Parents compose children. The
|
|
202
|
+
pattern scales.\n\nThe Router DSL eliminates boilerplate:\n\n module Dashboard\n
|
|
203
|
+
\ include Rooibos::Router\n\n route :stats, to: StatsPanel\n route :network,
|
|
204
|
+
to: NetworkPanel\n\n keymap do\n key :ctrl_c, -> { Rooibos::Command.exit
|
|
205
|
+
}\n only when: -> (model) { !model.modal_open } do\n key :q, -> { Rooibos::Command.exit
|
|
206
|
+
}\n key :s, -> { StatsPanel.fetch_command }\n key :p, -> { NetworkPanel.ping_command
|
|
207
|
+
}\n end\n end\n\n Update = from_router\n\n # ... Model, Init, View
|
|
208
|
+
below\n end\n\nDeclare routes and keymaps. The router generates Update for you.
|
|
209
|
+
Use guards to\nignore keys when needed.\n\n==== CLI\n\nThe <tt>rooibos</tt> command
|
|
210
|
+
scaffolds projects and runs applications.\n\n rooibos new my_app # Generate
|
|
211
|
+
project structure\n rooibos run # Run the app in current directory\n\nGenerated
|
|
212
|
+
apps include tests, type signatures, and a working welcome\nscreen with keyboard
|
|
213
|
+
and mouse support.\n\n\n---\n\n=== The Ecosystem\n\n\\Rooibos builds on RatatuiRuby[https://www.ratatui-ruby.dev],
|
|
214
|
+
a Rubygem built on\nRatatui[https://ratatui.rs]. You get native performance with
|
|
215
|
+
the joy of Ruby.\n\\Rooibos is one way to manage state and composition. Kit is another.\n\n====
|
|
216
|
+
Rooibos[https://git.sr.ht/~kerrick/rooibos]\n\nModel-View-Update architecture. Inspired
|
|
217
|
+
by Elm, Bubble Tea, and React +\nRedux. Your UI is a pure function of state.\n\n-
|
|
218
|
+
Functional programming with MVU\n- Commands work off the main thread\n- Messages,
|
|
219
|
+
not callbacks, drive updates\n\n==== {Kit}[https://sr.ht/~kerrick/ratatui_ruby/#chapter-3-the-object-path--kit]
|
|
220
|
+
(Coming Soon)\n\nComponent-based architecture. Encapsulate state, input handling,
|
|
221
|
+
and\nrendering in reusable pieces.\n\n- OOP with stateful components\n- Separate
|
|
222
|
+
UI state from domain logic\n- Built-in focus management & click handling\n\nBoth
|
|
223
|
+
use the same widget library and rendering engine. Pick the paradigm\nthat fits your
|
|
224
|
+
brain.\n\n\n---\n\n=== Links\n\n[Get Started]\n {Getting Started}[https://git.sr.ht/~kerrick/rooibos/tree/trunk/item/doc/getting_started/index.md],\n
|
|
225
|
+
\ {Tutorial}[https://git.sr.ht/~kerrick/rooibos/tree/trunk/item/doc/tutorial/index.md],\n
|
|
226
|
+
\ {Examples}[https://git.sr.ht/~kerrick/rooibos/tree/trunk/item/examples]\n\n[Coming
|
|
227
|
+
From...]\n {React/Redux}[https://git.sr.ht/~kerrick/rooibos/tree/trunk/item/doc/getting_started/for_react_developers.md],\n
|
|
228
|
+
\ {BubbleTea}[https://git.sr.ht/~kerrick/rooibos/tree/trunk/item/doc/getting_started/for_go_developers.md],\n
|
|
229
|
+
\ {Textual}[https://git.sr.ht/~kerrick/rooibos/tree/trunk/item/doc/getting_started/for_python_developers.md]\n\n[Learn
|
|
230
|
+
More]\n {Essentials}[https://git.sr.ht/~kerrick/rooibos/tree/trunk/item/doc/essentials/index.md],\n
|
|
231
|
+
\ {Scaling Up}[https://git.sr.ht/~kerrick/rooibos/tree/trunk/item/doc/scaling_up/index.md],\n
|
|
232
|
+
\ {Best Practices}[https://git.sr.ht/~kerrick/rooibos/tree/trunk/item/doc/best_practices/index.md],\n
|
|
233
|
+
\ {Troubleshooting}[https://git.sr.ht/~kerrick/rooibos/tree/trunk/item/doc/troubleshooting/index.md]\n\n[Community]\n
|
|
234
|
+
\ {Discuss}[https://lists.sr.ht/~kerrick/ratatui_ruby-discuss],\n {Announcements}[https://lists.sr.ht/~kerrick/ratatui_ruby-announce],\n
|
|
235
|
+
\ {Bug Tracker}[https://todo.sr.ht/~kerrick/ratatui_ruby],\n {Contribution Guide}[https://man.sr.ht/~kerrick/ratatui_ruby/contributing.md],\n
|
|
236
|
+
\ {Code of Conduct}[https://man.sr.ht/~kerrick/ratatui_ruby/code_of_conduct.md]\n\n\n---\n\n[Website]
|
|
237
|
+
https://rooibos.run\n[Source] https://git.sr.ht/~kerrick/rooibos\n[RubyGems] https://rubygems.org/gems/rooibos\n\n©
|
|
238
|
+
2026 Kerrick Long · Library: LGPL-3.0-or-later · Website: CC-BY-NC-ND-4.0 · Snippets:
|
|
239
|
+
MIT-0\n"
|
|
97
240
|
email:
|
|
98
241
|
- me@kerricklong.com
|
|
99
242
|
executables:
|
|
100
|
-
-
|
|
243
|
+
- rooibos
|
|
101
244
|
extensions: []
|
|
102
245
|
extra_rdoc_files: []
|
|
103
246
|
files:
|
|
@@ -117,30 +260,107 @@ files:
|
|
|
117
260
|
- LICENSES/MIT-0.txt
|
|
118
261
|
- LICENSES/MIT.txt
|
|
119
262
|
- README.md
|
|
263
|
+
- README.rdoc
|
|
120
264
|
- REUSE.toml
|
|
121
265
|
- Rakefile
|
|
122
266
|
- Steepfile
|
|
123
|
-
- doc/
|
|
124
|
-
- doc/
|
|
125
|
-
- doc/
|
|
126
|
-
- doc/
|
|
127
|
-
- doc/
|
|
128
|
-
- doc/
|
|
129
|
-
- doc/
|
|
130
|
-
- doc/
|
|
131
|
-
- doc/contributors/WIP/mvu_tea_implementations_research.md
|
|
132
|
-
- doc/contributors/WIP/runtime_refactoring_status.md
|
|
133
|
-
- doc/contributors/WIP/task.md
|
|
134
|
-
- doc/contributors/WIP/v0.4.0_todo.md
|
|
267
|
+
- doc/best_practices/forms_and_validation.md
|
|
268
|
+
- doc/best_practices/http_workflows.md
|
|
269
|
+
- doc/best_practices/index.md
|
|
270
|
+
- doc/best_practices/lists_and_tables.md
|
|
271
|
+
- doc/best_practices/modal_dialogs.md
|
|
272
|
+
- doc/best_practices/no_stateful_widgets.md
|
|
273
|
+
- doc/best_practices/orchestration.md
|
|
274
|
+
- doc/best_practices/streaming_data.md
|
|
135
275
|
- doc/contributors/design/commands_and_outlets.md
|
|
136
|
-
- doc/contributors/
|
|
137
|
-
- doc/contributors/
|
|
276
|
+
- doc/contributors/design/mvu_tea_implementations_research.md
|
|
277
|
+
- doc/contributors/documentation_plan.md
|
|
278
|
+
- doc/contributors/documentation_stub_audit.md
|
|
279
|
+
- doc/contributors/documentation_style.md
|
|
280
|
+
- doc/contributors/e2e_pty.md
|
|
281
|
+
- doc/contributors/specs/earliest_tutorial_steps_per_story.md
|
|
282
|
+
- doc/contributors/specs/file_browser.md
|
|
283
|
+
- doc/contributors/specs/file_browser_stories.md
|
|
284
|
+
- doc/contributors/specs/tutorials_to_stories.rb
|
|
285
|
+
- doc/contributors/todo/scrollbar.md
|
|
286
|
+
- doc/contributors/tutorial_old/01_project_setup.md
|
|
287
|
+
- doc/contributors/tutorial_old/02_hello_world.md
|
|
288
|
+
- doc/contributors/tutorial_old/03_adding_state.md
|
|
289
|
+
- doc/contributors/tutorial_old/06_organizing_your_code.md
|
|
290
|
+
- doc/contributors/tutorial_old/07_your_first_command.md
|
|
291
|
+
- doc/contributors/tutorial_old/08_the_preview_pane.md
|
|
292
|
+
- doc/contributors/tutorial_old/09_loading_states.md
|
|
293
|
+
- doc/contributors/tutorial_old/10_testing_your_app.md
|
|
294
|
+
- doc/contributors/tutorial_old/11_polish_and_refine.md
|
|
295
|
+
- doc/contributors/tutorial_old/12_going_further.md
|
|
296
|
+
- doc/contributors/tutorial_old/index.md
|
|
138
297
|
- doc/custom.css
|
|
298
|
+
- doc/essentials/commands.md
|
|
299
|
+
- doc/essentials/index.md
|
|
300
|
+
- doc/essentials/messages.md
|
|
301
|
+
- doc/essentials/models.md
|
|
302
|
+
- doc/essentials/shortcuts.md
|
|
303
|
+
- doc/essentials/the_elm_architecture.md
|
|
304
|
+
- doc/essentials/the_runtime.md
|
|
305
|
+
- doc/essentials/update_functions.md
|
|
306
|
+
- doc/essentials/views.md
|
|
307
|
+
- doc/getting_started/for_go_developers.md
|
|
308
|
+
- doc/getting_started/for_python_developers.md
|
|
309
|
+
- doc/getting_started/for_rails_developers.md
|
|
310
|
+
- doc/getting_started/for_ratatui_ruby_developers.md
|
|
311
|
+
- doc/getting_started/for_react_developers.md
|
|
312
|
+
- doc/getting_started/index.md
|
|
313
|
+
- doc/getting_started/install.md
|
|
139
314
|
- doc/getting_started/quickstart.md
|
|
140
|
-
- doc/
|
|
315
|
+
- doc/getting_started/ruby_primer.md
|
|
316
|
+
- doc/getting_started/why_rooibos.md
|
|
141
317
|
- doc/images/verify_readme_usage.png
|
|
142
318
|
- doc/images/widget_cmd_exec.png
|
|
143
319
|
- doc/index.md
|
|
320
|
+
- doc/scaling_up/async_patterns.md
|
|
321
|
+
- doc/scaling_up/command_composition.md
|
|
322
|
+
- doc/scaling_up/custom_commands.md
|
|
323
|
+
- doc/scaling_up/fractal_architecture.md
|
|
324
|
+
- doc/scaling_up/index.md
|
|
325
|
+
- doc/scaling_up/message_routing.md
|
|
326
|
+
- doc/scaling_up/ractor_safety.md
|
|
327
|
+
- doc/scaling_up/testing.md
|
|
328
|
+
- doc/troubleshooting/common_errors.md
|
|
329
|
+
- doc/troubleshooting/debugging.md
|
|
330
|
+
- doc/troubleshooting/index.md
|
|
331
|
+
- doc/troubleshooting/performance.md
|
|
332
|
+
- doc/tutorial/01_project_setup.md
|
|
333
|
+
- doc/tutorial/02_hello_world.md
|
|
334
|
+
- doc/tutorial/03_static_file_list.md
|
|
335
|
+
- doc/tutorial/04_arrow_navigation.md
|
|
336
|
+
- doc/tutorial/05_real_files.md
|
|
337
|
+
- doc/tutorial/06_safe_refactoring.md
|
|
338
|
+
- doc/tutorial/07_red_first_tdd.md
|
|
339
|
+
- doc/tutorial/08_file_metadata.md
|
|
340
|
+
- doc/tutorial/09_text_preview.md
|
|
341
|
+
- doc/tutorial/10_directory_tree.md
|
|
342
|
+
- doc/tutorial/11_pane_focus.md
|
|
343
|
+
- doc/tutorial/12_sorting.md
|
|
344
|
+
- doc/tutorial/13_filtering.md
|
|
345
|
+
- doc/tutorial/14_toggle_hidden.md
|
|
346
|
+
- doc/tutorial/15_text_input_widget.md
|
|
347
|
+
- doc/tutorial/16_rename_files.md
|
|
348
|
+
- doc/tutorial/17_confirmation_dialogs.md
|
|
349
|
+
- doc/tutorial/18_progress_indicators.md
|
|
350
|
+
- doc/tutorial/19_atomic_operations.md
|
|
351
|
+
- doc/tutorial/20_external_editor.md
|
|
352
|
+
- doc/tutorial/21_modal_overlays.md
|
|
353
|
+
- doc/tutorial/22_error_handling.md
|
|
354
|
+
- doc/tutorial/23_terminal_capabilities.md
|
|
355
|
+
- doc/tutorial/24_mouse_events.md
|
|
356
|
+
- doc/tutorial/25_resize_events.md
|
|
357
|
+
- doc/tutorial/26_loading_states.md
|
|
358
|
+
- doc/tutorial/27_performance.md
|
|
359
|
+
- doc/tutorial/28_color_schemes.md
|
|
360
|
+
- doc/tutorial/29_configuration.md
|
|
361
|
+
- doc/tutorial/30_going_further.md
|
|
362
|
+
- doc/tutorial/index.md
|
|
363
|
+
- examples/app_file_browser/app.rb
|
|
144
364
|
- examples/app_fractal_dashboard/README.md
|
|
145
365
|
- examples/app_fractal_dashboard/app.rb
|
|
146
366
|
- examples/app_fractal_dashboard/dashboard/base.rb
|
|
@@ -158,22 +378,33 @@ files:
|
|
|
158
378
|
- examples/app_fractal_dashboard/fragments/uptime.rb
|
|
159
379
|
- examples/verify_readme_usage/README.md
|
|
160
380
|
- examples/verify_readme_usage/app.rb
|
|
381
|
+
- examples/verify_website_first_app/app.rb
|
|
382
|
+
- examples/verify_website_hello_mvu/app.rb
|
|
161
383
|
- examples/widget_command_system/README.md
|
|
162
384
|
- examples/widget_command_system/app.rb
|
|
163
|
-
- exe
|
|
385
|
+
- exe/rooibos
|
|
386
|
+
- generate_tutorial_stubs.rb
|
|
164
387
|
- lib/rooibos.rb
|
|
388
|
+
- lib/rooibos/cli.rb
|
|
389
|
+
- lib/rooibos/cli/commands/new.rb
|
|
390
|
+
- lib/rooibos/cli/commands/run.rb
|
|
165
391
|
- lib/rooibos/command.rb
|
|
166
392
|
- lib/rooibos/command/all.rb
|
|
167
393
|
- lib/rooibos/command/batch.rb
|
|
168
394
|
- lib/rooibos/command/custom.rb
|
|
169
395
|
- lib/rooibos/command/http.rb
|
|
170
396
|
- lib/rooibos/command/lifecycle.rb
|
|
397
|
+
- lib/rooibos/command/open.rb
|
|
171
398
|
- lib/rooibos/command/outlet.rb
|
|
172
399
|
- lib/rooibos/command/wait.rb
|
|
173
400
|
- lib/rooibos/error.rb
|
|
174
401
|
- lib/rooibos/message.rb
|
|
175
402
|
- lib/rooibos/message/all.rb
|
|
403
|
+
- lib/rooibos/message/batch.rb
|
|
404
|
+
- lib/rooibos/message/canceled.rb
|
|
405
|
+
- lib/rooibos/message/error.rb
|
|
176
406
|
- lib/rooibos/message/http_response.rb
|
|
407
|
+
- lib/rooibos/message/open.rb
|
|
177
408
|
- lib/rooibos/message/system/batch.rb
|
|
178
409
|
- lib/rooibos/message/system/stream.rb
|
|
179
410
|
- lib/rooibos/message/timer.rb
|
|
@@ -182,14 +413,17 @@ files:
|
|
|
182
413
|
- lib/rooibos/shortcuts.rb
|
|
183
414
|
- lib/rooibos/test_helper.rb
|
|
184
415
|
- lib/rooibos/version.rb
|
|
416
|
+
- lib/rooibos/welcome.rb
|
|
185
417
|
- mise.toml
|
|
186
418
|
- rbs_collection.lock.yaml
|
|
187
419
|
- rbs_collection.yaml
|
|
188
420
|
- sig/concurrent.rbs
|
|
189
421
|
- sig/examples/verify_readme_usage/app.rbs
|
|
190
422
|
- sig/examples/widget_command_system/app.rbs
|
|
423
|
+
- sig/gem.rbs
|
|
191
424
|
- sig/open3.rbs
|
|
192
425
|
- sig/rooibos.rbs
|
|
426
|
+
- sig/rooibos/cli.rbs
|
|
193
427
|
- sig/rooibos/command.rbs
|
|
194
428
|
- sig/rooibos/error.rbs
|
|
195
429
|
- sig/rooibos/message.rbs
|
|
@@ -198,18 +432,20 @@ files:
|
|
|
198
432
|
- sig/rooibos/shortcuts.rbs
|
|
199
433
|
- sig/rooibos/test_helper.rbs
|
|
200
434
|
- sig/rooibos/version.rbs
|
|
435
|
+
- sig/rooibos/welcome.rbs
|
|
201
436
|
- tasks/example_viewer.html.erb
|
|
437
|
+
- tasks/install.rake
|
|
202
438
|
- tasks/resources/build.yml.erb
|
|
203
439
|
- tasks/resources/index.html.erb
|
|
204
440
|
- tasks/resources/rubies.yml
|
|
205
441
|
- tasks/steep.rake
|
|
206
442
|
- vendor/goodcop/base.yml
|
|
207
|
-
homepage: https://
|
|
443
|
+
homepage: https://rooibos.run
|
|
208
444
|
licenses:
|
|
209
445
|
- LGPL-3.0-or-later
|
|
210
446
|
metadata:
|
|
211
447
|
allowed_push_host: https://rubygems.org
|
|
212
|
-
homepage_uri: https://
|
|
448
|
+
homepage_uri: https://rooibos.run
|
|
213
449
|
bug_tracker_uri: https://todo.sr.ht/~kerrick/ratatui_ruby
|
|
214
450
|
mailing_list_uri: https://lists.sr.ht/~kerrick/ratatui_ruby-discuss
|
|
215
451
|
source_code_uri: https://git.sr.ht/~kerrick/rooibos
|
|
@@ -237,5 +473,5 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
237
473
|
requirements: []
|
|
238
474
|
rubygems_version: 4.0.3
|
|
239
475
|
specification_version: 4
|
|
240
|
-
summary:
|
|
476
|
+
summary: "☕ Confidently Build Terminal Apps"
|
|
241
477
|
test_files: []
|