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
data/sig/rooibos/command.rbs
CHANGED
|
@@ -135,12 +135,25 @@ module Rooibos
|
|
|
135
135
|
|
|
136
136
|
# Mixin for user-defined custom commands.
|
|
137
137
|
module Custom
|
|
138
|
+
# Interface for classes with a members method (Data.define, Struct).
|
|
139
|
+
interface _HasMembers
|
|
140
|
+
def members: () -> Array[Symbol]
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
# Methods excluded from deconstruct_keys introspection.
|
|
144
|
+
# Computed from Object, Data.define, Struct, and PP prototypes.
|
|
145
|
+
INFRASTRUCTURE_METHODS: Array[Symbol]
|
|
146
|
+
|
|
138
147
|
# Brand predicate for command identification.
|
|
139
148
|
def rooibos_command?: () -> true
|
|
140
149
|
|
|
141
150
|
# Cleanup time after cancellation is requested. In seconds.
|
|
142
151
|
# Default: 0.1 seconds (100 milliseconds).
|
|
143
152
|
def rooibos_cancellation_grace_period: () -> Float
|
|
153
|
+
|
|
154
|
+
# Deconstructs for hash-based pattern matching.
|
|
155
|
+
# Introspects public query methods and returns a hash with :type discriminator.
|
|
156
|
+
def deconstruct_keys: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
|
|
144
157
|
end
|
|
145
158
|
|
|
146
159
|
# Minimal interface for callables accepted by Lifecycle.run_sync.
|
|
@@ -179,8 +192,17 @@ module Rooibos
|
|
|
179
192
|
|
|
180
193
|
# Messaging gateway for custom commands.
|
|
181
194
|
class Outlet
|
|
195
|
+
# Internal handle for async streaming commands.
|
|
196
|
+
class AsyncHandle < Data
|
|
197
|
+
attr_reader future: Concurrent::Promises::Future[void]
|
|
198
|
+
|
|
199
|
+
def self.new: (future: Concurrent::Promises::Future[void]) -> instance
|
|
200
|
+
end
|
|
201
|
+
|
|
182
202
|
@channel: Concurrent::Promises::Channel
|
|
183
203
|
@live: Lifecycle
|
|
204
|
+
@pending_async: Array[AsyncHandle]
|
|
205
|
+
|
|
184
206
|
|
|
185
207
|
def initialize: (Concurrent::Promises::Channel channel, lifecycle: Lifecycle) -> void
|
|
186
208
|
|
|
@@ -192,6 +214,14 @@ module Rooibos
|
|
|
192
214
|
|
|
193
215
|
# Runs a child command synchronously, returning its result.
|
|
194
216
|
def source: (_Callable command, Concurrent::Cancellation token, ?timeout: Float) -> Object?
|
|
217
|
+
|
|
218
|
+
# Spawns an async streaming command.
|
|
219
|
+
# Returns a handle for use with wait.
|
|
220
|
+
def standing: (_Callable command, Concurrent::Cancellation token) -> AsyncHandle
|
|
221
|
+
|
|
222
|
+
# Blocks until async commands complete.
|
|
223
|
+
# If no handles given, waits for all pending async commands.
|
|
224
|
+
def wait: (*AsyncHandle handles, ?token: Concurrent::Cancellation?) -> void
|
|
195
225
|
end
|
|
196
226
|
|
|
197
227
|
# A fire-and-forget parallel command.
|
|
@@ -261,5 +291,23 @@ module Rooibos
|
|
|
261
291
|
# DWIM: accepts positional args, method keywords (get:, post:, etc.), or explicit keywords.
|
|
262
292
|
# See Http class and documentation for all supported patterns.
|
|
263
293
|
def self.http: (*(Symbol | String | nil), **(Symbol | String | Integer | Float | Hash[String, String] | ^(String, Hash[String, String]?, Integer?) -> Object | nil)) -> Http
|
|
294
|
+
|
|
295
|
+
# Opens a file or URL with the system's default application.
|
|
296
|
+
class Open < Data
|
|
297
|
+
include Custom
|
|
298
|
+
|
|
299
|
+
attr_reader path: String
|
|
300
|
+
attr_reader envelope: String
|
|
301
|
+
|
|
302
|
+
def self.new: (path: String, envelope: String) -> instance
|
|
303
|
+
|
|
304
|
+
# Builds the platform-specific open command.
|
|
305
|
+
def self.system_command: (String path, ?String platform) -> String
|
|
306
|
+
|
|
307
|
+
def call: (Outlet out, Concurrent::Cancellation token) -> void
|
|
308
|
+
end
|
|
309
|
+
|
|
310
|
+
# Creates an open command for launching files with system opener.
|
|
311
|
+
def self.open: (String path, ?String envelope) -> Open
|
|
264
312
|
end
|
|
265
313
|
end
|
data/sig/rooibos/message.rbs
CHANGED
|
@@ -8,9 +8,18 @@ module Rooibos
|
|
|
8
8
|
module Message
|
|
9
9
|
# Fallback predicate mixin.
|
|
10
10
|
module Predicates
|
|
11
|
+
# Converts the message to a Symbol representation.
|
|
12
|
+
def to_sym: () -> Symbol
|
|
13
|
+
|
|
14
|
+
# Compares the message with another object.
|
|
15
|
+
def ==: (top other) -> bool
|
|
16
|
+
|
|
11
17
|
# Returns false for unknown predicate methods.
|
|
12
18
|
def method_missing: (Symbol name, *untyped args, **untyped kwargs) ?{ () -> untyped } -> bool
|
|
13
19
|
|
|
20
|
+
# Default deconstruct_keys for classes that don't define their own.
|
|
21
|
+
def deconstruct_keys: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
|
|
22
|
+
|
|
14
23
|
# Responds to all predicate methods.
|
|
15
24
|
def respond_to_missing?: (Symbol name, ?bool include_private) -> bool
|
|
16
25
|
end
|
|
@@ -100,6 +109,19 @@ module Rooibos
|
|
|
100
109
|
def deconstruct_keys: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
|
|
101
110
|
end
|
|
102
111
|
|
|
112
|
+
# Completion sentinel from Command.batch.
|
|
113
|
+
# Signals when all children of a batch command have finished.
|
|
114
|
+
class Batch < Data
|
|
115
|
+
include Predicates
|
|
116
|
+
|
|
117
|
+
attr_reader command: Command::Batch
|
|
118
|
+
|
|
119
|
+
def self.new: (command: Command::Batch) -> instance
|
|
120
|
+
|
|
121
|
+
def batch?: () -> bool
|
|
122
|
+
def deconstruct_keys: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
|
|
123
|
+
end
|
|
124
|
+
|
|
103
125
|
# Response from Command.all aggregating parallel execution.
|
|
104
126
|
class All
|
|
105
127
|
include Predicates
|
|
@@ -117,5 +139,43 @@ module Rooibos
|
|
|
117
139
|
def all?: () -> bool
|
|
118
140
|
def deconstruct_keys: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
|
|
119
141
|
end
|
|
142
|
+
|
|
143
|
+
# Error message from a failed command.
|
|
144
|
+
class Error < Data
|
|
145
|
+
include Predicates
|
|
146
|
+
|
|
147
|
+
attr_reader command: Command::Custom
|
|
148
|
+
attr_reader exception: Exception
|
|
149
|
+
|
|
150
|
+
def self.new: (command: Command::Custom, exception: Exception) -> instance
|
|
151
|
+
|
|
152
|
+
def error?: () -> bool
|
|
153
|
+
def deconstruct_keys: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
# Cancellation notification from a canceled command.
|
|
157
|
+
class Canceled < Data
|
|
158
|
+
include Predicates
|
|
159
|
+
|
|
160
|
+
attr_reader command: untyped
|
|
161
|
+
|
|
162
|
+
def self.new: (command: untyped) -> instance
|
|
163
|
+
|
|
164
|
+
def canceled?: () -> bool
|
|
165
|
+
alias cancelled? canceled?
|
|
166
|
+
def deconstruct_keys: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
# Success notification from Command.open.
|
|
170
|
+
class Open < Data
|
|
171
|
+
include Predicates
|
|
172
|
+
|
|
173
|
+
attr_reader envelope: String
|
|
174
|
+
|
|
175
|
+
def self.new: (envelope: String) -> instance
|
|
176
|
+
|
|
177
|
+
def open?: () -> bool
|
|
178
|
+
def deconstruct_keys: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
|
|
179
|
+
end
|
|
120
180
|
end
|
|
121
181
|
end
|
data/sig/rooibos/shortcuts.rbs
CHANGED
|
@@ -12,5 +12,19 @@ module Rooibos
|
|
|
12
12
|
def self.sh: (String command, Symbol | Class tag) -> Command::System
|
|
13
13
|
def self.map: (Command::execution inner_command) { (Array[untyped]) -> Array[untyped] } -> Command::Mapped
|
|
14
14
|
end
|
|
15
|
+
|
|
16
|
+
# Short aliases for Message types.
|
|
17
|
+
module Msg
|
|
18
|
+
Timer: singleton(Message::Timer)
|
|
19
|
+
Http: singleton(Message::HttpResponse)
|
|
20
|
+
|
|
21
|
+
module Sh
|
|
22
|
+
Batch: singleton(Message::System::Batch)
|
|
23
|
+
Stream: singleton(Message::System::Stream)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
All: singleton(Message::All)
|
|
27
|
+
Batch: singleton(Message::Batch)
|
|
28
|
+
end
|
|
15
29
|
end
|
|
16
30
|
end
|
data/sig/rooibos/test_helper.rbs
CHANGED
|
@@ -5,6 +5,10 @@
|
|
|
5
5
|
|
|
6
6
|
module Rooibos
|
|
7
7
|
module TestHelper
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
def validate_rooibos_command!: (Runtime::_MaybeCommand) -> nil
|
|
9
|
+
|
|
10
|
+
# Fails if any Command::Error is present in the messages array.
|
|
11
|
+
# Relies on Minitest's flunk method being available in the including class.
|
|
12
|
+
def assert_no_errors: (Array[untyped] messages, ?String? msg) -> void
|
|
13
|
+
end
|
|
10
14
|
end
|
|
@@ -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: |
|