rooibos 0.6.2 → 0.7.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/LICENSES/BSD-2-Clause.txt +9 -0
- data/REUSE.toml +5 -0
- data/exe/.gitkeep +0 -0
- data/lib/rooibos/cli/commands/new.rb +24 -0
- data/lib/rooibos/command/batch.rb +10 -0
- data/lib/rooibos/command/bubble.rb +34 -0
- data/lib/rooibos/command/custom.rb +3 -2
- data/lib/rooibos/command/deliver.rb +50 -0
- data/lib/rooibos/command/http.rb +1 -1
- data/lib/rooibos/command/lifecycle.rb +3 -1
- data/lib/rooibos/command/outlet.rb +19 -9
- data/lib/rooibos/command.rb +107 -3
- data/lib/rooibos/configuration.rb +29 -0
- data/lib/rooibos/message/bubbled.rb +29 -0
- data/lib/rooibos/message.rb +24 -6
- data/lib/rooibos/router/action.rb +36 -0
- data/lib/rooibos/router/flow/dispatch.rb +39 -0
- data/lib/rooibos/router/flow/inward.rb +41 -0
- data/lib/rooibos/router/flow/outward.rb +44 -0
- data/lib/rooibos/router/guard.rb +56 -0
- data/lib/rooibos/router/predicate.rb +65 -0
- data/lib/rooibos/router/registry/actions.rb +41 -0
- data/lib/rooibos/router/registry/forwards.rb +58 -0
- data/lib/rooibos/router/registry/observes.rb +57 -0
- data/lib/rooibos/router/registry/otherwises.rb +29 -0
- data/lib/rooibos/router/registry/receives.rb +57 -0
- data/lib/rooibos/router/registry/routes.rb +59 -0
- data/lib/rooibos/router/registry.rb +26 -0
- data/lib/rooibos/router/route.rb +42 -0
- data/lib/rooibos/router/router_update.rb +53 -0
- data/lib/rooibos/router/rule/forward.rb +39 -0
- data/lib/rooibos/router/rule/observe.rb +22 -0
- data/lib/rooibos/router/rule/otherwise.rb +26 -0
- data/lib/rooibos/router/rule/receive.rb +22 -0
- data/lib/rooibos/router/rule.rb +40 -0
- data/lib/rooibos/router.rb +424 -438
- data/lib/rooibos/runtime.rb +37 -52
- data/lib/rooibos/test_helper.rb +22 -0
- data/lib/rooibos/transition.rb +92 -0
- data/lib/rooibos/version.rb +1 -1
- data/lib/rooibos.rb +2 -57
- data/sig/rooibos/cli.rbs +1 -0
- data/sig/rooibos/command.rbs +44 -0
- data/sig/rooibos/configuration.rbs +20 -0
- data/sig/rooibos/message.rbs +12 -0
- data/sig/rooibos/router/action.rbs +33 -0
- data/sig/rooibos/router/actions.rbs +27 -0
- data/sig/rooibos/router/flow/dispatch.rbs +29 -0
- data/sig/rooibos/router/flow/inward.rbs +37 -0
- data/sig/rooibos/router/flow/outward.rbs +36 -0
- data/sig/rooibos/router/forward.rbs +35 -0
- data/sig/rooibos/router/forwards.rbs +34 -0
- data/sig/rooibos/router/guard.rbs +21 -0
- data/sig/rooibos/router/observe.rbs +20 -0
- data/sig/rooibos/router/observes.rbs +38 -0
- data/sig/rooibos/router/otherwise.rbs +22 -0
- data/sig/rooibos/router/otherwises.rbs +20 -0
- data/sig/rooibos/router/predicate.rbs +51 -0
- data/sig/rooibos/router/receive.rbs +20 -0
- data/sig/rooibos/router/receives.rbs +38 -0
- data/sig/rooibos/router/registry.rbs +24 -0
- data/sig/rooibos/router/route.rbs +46 -0
- data/sig/rooibos/router/router_update.rbs +33 -0
- data/sig/rooibos/router/routes.rbs +41 -0
- data/sig/rooibos/router/rule.rbs +36 -0
- data/sig/rooibos/router.rbs +216 -161
- data/sig/rooibos/runtime.rbs +0 -1
- data/sig/rooibos/test_helper.rbs +6 -0
- data/sig/rooibos/transition.rbs +33 -0
- data/sig/rooibos.rbs +0 -10
- metadata +144 -198
- data/.builds/ruby-3.2.yml +0 -55
- data/.builds/ruby-3.3.yml +0 -55
- data/.builds/ruby-3.4.yml +0 -55
- data/.builds/ruby-4.0.0.yml +0 -55
- data/.pre-commit-config.yaml +0 -16
- data/.rubocop.yml +0 -8
- data/AGENTS.md +0 -108
- data/CHANGELOG.md +0 -308
- data/README.md +0 -183
- data/README.rdoc +0 -374
- data/Rakefile +0 -16
- data/Steepfile +0 -13
- data/doc/best_practices/forms_and_validation.md +0 -20
- data/doc/best_practices/http_workflows.md +0 -20
- data/doc/best_practices/index.md +0 -26
- data/doc/best_practices/lists_and_tables.md +0 -20
- data/doc/best_practices/modal_dialogs.md +0 -20
- data/doc/best_practices/no_stateful_widgets.md +0 -184
- data/doc/best_practices/orchestration.md +0 -20
- data/doc/best_practices/streaming_data.md +0 -20
- data/doc/contributors/design/commands_and_outlets.md +0 -214
- data/doc/contributors/design/mvu_tea_implementations_research.md +0 -373
- data/doc/contributors/documentation_plan.md +0 -616
- data/doc/contributors/documentation_stub_audit.md +0 -112
- data/doc/contributors/documentation_style.md +0 -275
- data/doc/contributors/e2e_pty.md +0 -168
- data/doc/contributors/maybe_stateful_router.md +0 -56
- data/doc/contributors/specs/earliest_tutorial_steps_per_story.md +0 -70
- data/doc/contributors/specs/file_browser.md +0 -789
- data/doc/contributors/specs/file_browser_stories.md +0 -784
- data/doc/contributors/specs/tutorials_to_stories.rb +0 -167
- data/doc/contributors/todo/scrollbar.md +0 -118
- data/doc/contributors/tutorial_old/01_project_setup.md +0 -20
- data/doc/contributors/tutorial_old/02_hello_world.md +0 -24
- data/doc/contributors/tutorial_old/03_adding_state.md +0 -26
- data/doc/contributors/tutorial_old/06_organizing_your_code.md +0 -20
- data/doc/contributors/tutorial_old/07_your_first_command.md +0 -21
- data/doc/contributors/tutorial_old/08_the_preview_pane.md +0 -20
- data/doc/contributors/tutorial_old/09_loading_states.md +0 -20
- data/doc/contributors/tutorial_old/10_testing_your_app.md +0 -20
- data/doc/contributors/tutorial_old/11_polish_and_refine.md +0 -20
- data/doc/contributors/tutorial_old/12_going_further.md +0 -20
- data/doc/contributors/tutorial_old/index.md +0 -20
- data/doc/custom.css +0 -22
- data/doc/essentials/commands.md +0 -20
- data/doc/essentials/index.md +0 -31
- data/doc/essentials/messages.md +0 -21
- data/doc/essentials/models.md +0 -21
- data/doc/essentials/shortcuts.md +0 -19
- data/doc/essentials/the_elm_architecture.md +0 -24
- data/doc/essentials/the_runtime.md +0 -21
- data/doc/essentials/update_functions.md +0 -20
- data/doc/essentials/views.md +0 -22
- data/doc/getting_started/for_go_developers.md +0 -16
- data/doc/getting_started/for_python_developers.md +0 -16
- data/doc/getting_started/for_rails_developers.md +0 -17
- data/doc/getting_started/for_ratatui_ruby_developers.md +0 -17
- data/doc/getting_started/for_react_developers.md +0 -17
- data/doc/getting_started/index.md +0 -52
- data/doc/getting_started/install.md +0 -20
- data/doc/getting_started/quickstart.md +0 -20
- data/doc/getting_started/ruby_primer.md +0 -19
- data/doc/getting_started/why_rooibos.md +0 -20
- data/doc/images/verify_readme_usage.png +0 -0
- data/doc/images/widget_cmd_exec.png +0 -0
- data/doc/index.md +0 -93
- data/doc/scaling_up/async_patterns.md +0 -20
- data/doc/scaling_up/command_composition.md +0 -20
- data/doc/scaling_up/custom_commands.md +0 -21
- data/doc/scaling_up/fractal_architecture.md +0 -20
- data/doc/scaling_up/index.md +0 -30
- data/doc/scaling_up/message_routing.md +0 -20
- data/doc/scaling_up/ractor_safety.md +0 -20
- data/doc/scaling_up/testing.md +0 -21
- data/doc/troubleshooting/common_errors.md +0 -20
- data/doc/troubleshooting/debugging.md +0 -21
- data/doc/troubleshooting/index.md +0 -23
- data/doc/troubleshooting/performance.md +0 -20
- data/doc/tutorial/01_project_setup.md +0 -44
- data/doc/tutorial/02_hello_world.md +0 -45
- data/doc/tutorial/03_static_file_list.md +0 -44
- data/doc/tutorial/04_arrow_navigation.md +0 -47
- data/doc/tutorial/05_real_files.md +0 -45
- data/doc/tutorial/06_safe_refactoring.md +0 -21
- data/doc/tutorial/07_red_first_tdd.md +0 -26
- data/doc/tutorial/08_file_metadata.md +0 -42
- data/doc/tutorial/09_text_preview.md +0 -44
- data/doc/tutorial/10_directory_tree.md +0 -42
- data/doc/tutorial/11_pane_focus.md +0 -40
- data/doc/tutorial/12_sorting.md +0 -41
- data/doc/tutorial/13_filtering.md +0 -43
- data/doc/tutorial/14_toggle_hidden.md +0 -41
- data/doc/tutorial/15_text_input_widget.md +0 -43
- data/doc/tutorial/16_rename_files.md +0 -42
- data/doc/tutorial/17_confirmation_dialogs.md +0 -43
- data/doc/tutorial/18_progress_indicators.md +0 -43
- data/doc/tutorial/19_atomic_operations.md +0 -42
- data/doc/tutorial/20_external_editor.md +0 -42
- data/doc/tutorial/21_modal_overlays.md +0 -41
- data/doc/tutorial/22_error_handling.md +0 -43
- data/doc/tutorial/23_terminal_capabilities.md +0 -53
- data/doc/tutorial/24_mouse_events.md +0 -43
- data/doc/tutorial/25_resize_events.md +0 -43
- data/doc/tutorial/26_loading_states.md +0 -42
- data/doc/tutorial/27_performance.md +0 -43
- data/doc/tutorial/28_color_schemes.md +0 -47
- data/doc/tutorial/29_configuration.md +0 -124
- data/doc/tutorial/30_going_further.md +0 -17
- data/doc/tutorial/index.md +0 -17
- data/examples/app_fractal_dashboard/README.md +0 -60
- data/examples/app_fractal_dashboard/app.rb +0 -63
- data/examples/app_fractal_dashboard/dashboard/base.rb +0 -73
- data/examples/app_fractal_dashboard/dashboard/update_helpers.rb +0 -86
- data/examples/app_fractal_dashboard/dashboard/update_manual.rb +0 -87
- data/examples/app_fractal_dashboard/dashboard/update_router.rb +0 -43
- data/examples/app_fractal_dashboard/fragments/custom_shell_input.rb +0 -81
- data/examples/app_fractal_dashboard/fragments/custom_shell_modal.rb +0 -82
- data/examples/app_fractal_dashboard/fragments/custom_shell_output.rb +0 -90
- data/examples/app_fractal_dashboard/fragments/disk_usage.rb +0 -47
- data/examples/app_fractal_dashboard/fragments/network_panel.rb +0 -45
- data/examples/app_fractal_dashboard/fragments/ping.rb +0 -47
- data/examples/app_fractal_dashboard/fragments/stats_panel.rb +0 -45
- data/examples/app_fractal_dashboard/fragments/system_info.rb +0 -47
- data/examples/app_fractal_dashboard/fragments/uptime.rb +0 -47
- data/examples/tutorial/01/app.rb +0 -50
- data/examples/tutorial/02/app.rb +0 -64
- data/examples/tutorial/03/app.rb +0 -91
- data/examples/tutorial/06_safe_refactoring/app.rb +0 -124
- data/examples/verify_readme_usage/README.md +0 -54
- data/examples/verify_readme_usage/app.rb +0 -47
- data/examples/verify_website_first_app/app.rb +0 -85
- data/examples/verify_website_hello_mvu/app.rb +0 -31
- data/examples/widget_command_system/README.md +0 -70
- data/examples/widget_command_system/app.rb +0 -134
- data/generate_tutorial_stubs.rb +0 -126
- data/mise.toml +0 -8
- data/rbs_collection.lock.yaml +0 -108
- data/rbs_collection.yaml +0 -15
- data/tasks/example_viewer.html.erb +0 -172
- data/tasks/install.rake +0 -29
- data/tasks/resources/build.yml.erb +0 -55
- data/tasks/resources/index.html.erb +0 -44
- data/tasks/resources/rubies.yml +0 -7
- data/tasks/steep.rake +0 -11
- /data/{vendor/goodcop/base.yml → lib/rooibos/rubocop.yml} +0 -0
|
@@ -0,0 +1,34 @@
|
|
|
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
|
+
module Router
|
|
8
|
+
# Collection of forward rules.
|
|
9
|
+
class Forwards < Data
|
|
10
|
+
include Registry[Forward]
|
|
11
|
+
|
|
12
|
+
attr_reader rules: Array[Forward]
|
|
13
|
+
|
|
14
|
+
def initialize: (?rules: Array[Forward]) -> void
|
|
15
|
+
|
|
16
|
+
# Adds a forward rule matching class instances.
|
|
17
|
+
def add_instances_of: (Class klass, ?to: route_target?, ?as: Symbol?, ?broadcast: bool, ?broadcast_to: Array[route_target]?) -> void
|
|
18
|
+
|
|
19
|
+
# Adds a forward rule matching key events.
|
|
20
|
+
def add_events: (Symbol | Array[Symbol] keys, ?to: route_target?, ?as: Symbol?, ?guard: guard?, ?when: guard?, ?unless: guard?) -> void
|
|
21
|
+
|
|
22
|
+
# Adds a forward rule matching routed messages by envelope.
|
|
23
|
+
def add_routed: (Symbol | Array[Symbol] envelopes, ?to: route_target?, ?as: Symbol?) -> void
|
|
24
|
+
|
|
25
|
+
# Adds a forward rule matching a custom predicate.
|
|
26
|
+
def add_custom: (guard predicate, ?to: route_target?, ?as: Symbol?) -> void
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
# Resolves broadcast options into a targets value.
|
|
31
|
+
def resolve_targets: (to: route_target?, broadcast: bool, broadcast_to: Array[route_target]?) -> Forward::targets
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
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
|
+
module Router
|
|
8
|
+
# Normalizes guard options into a callable.
|
|
9
|
+
class Guard < Data
|
|
10
|
+
attr_reader callable: guard?
|
|
11
|
+
|
|
12
|
+
def self.from: (?guard: guard?, ?when: guard?, ?unless: guard?) -> Guard
|
|
13
|
+
|
|
14
|
+
# Effective arity of the guard (2 if no callable).
|
|
15
|
+
def arity: () -> Integer
|
|
16
|
+
|
|
17
|
+
# Evaluates the guard. Returns true if no callable.
|
|
18
|
+
def call: (message, _DataModel) -> boolish
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
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
|
+
module Router
|
|
8
|
+
# Observe rule - matches messages, handles, and continues processing.
|
|
9
|
+
class Observe < Data
|
|
10
|
+
include Rule
|
|
11
|
+
|
|
12
|
+
attr_reader predicate: predicate
|
|
13
|
+
attr_reader action: action
|
|
14
|
+
attr_reader guard: Guard
|
|
15
|
+
|
|
16
|
+
# Applies the action and returns a Transition.
|
|
17
|
+
def apply: (message, _DataModel, Routes) -> Transition
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
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
|
+
module Router
|
|
8
|
+
# Collection of observe rules.
|
|
9
|
+
class Observes < Data
|
|
10
|
+
include Registry[Observe]
|
|
11
|
+
|
|
12
|
+
attr_reader rules: Array[Observe]
|
|
13
|
+
attr_reader actions: Actions
|
|
14
|
+
|
|
15
|
+
def initialize: (?rules: Array[Observe], actions: Actions) -> void
|
|
16
|
+
|
|
17
|
+
# Adds an observe rule matching key events.
|
|
18
|
+
def add_events: (Symbol | Array[Symbol] keys, handler_or_action handler, ?guard: guard?, ?when: guard?, ?unless: guard?) -> void
|
|
19
|
+
|
|
20
|
+
# Adds an observe rule matching routed messages by envelope.
|
|
21
|
+
def add_routed: (Symbol envelope, handler_or_action handler, ?guard: guard?) -> void
|
|
22
|
+
|
|
23
|
+
# Adds an observe rule matching class instances.
|
|
24
|
+
def add_instances_of: (Class klass, handler_or_action handler, ?guard: guard?) -> void
|
|
25
|
+
|
|
26
|
+
# Adds a catch-all observe rule.
|
|
27
|
+
def add_all: (handler_or_action handler, ?guard: guard?, ?when: guard?, ?unless: guard?) -> void
|
|
28
|
+
|
|
29
|
+
# Adds an observe rule matching a custom predicate.
|
|
30
|
+
def add_custom: (guard predicate, handler_or_action handler, ?guard: guard?, ?when: guard?, ?unless: guard?) -> void
|
|
31
|
+
|
|
32
|
+
private
|
|
33
|
+
|
|
34
|
+
# Resolves a Symbol action name to its Action, or wraps a lambda.
|
|
35
|
+
def resolve: (handler_or_action handler) -> action
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
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
|
+
module Router
|
|
8
|
+
# Otherwise rule - routes unhandled messages to a fragment.
|
|
9
|
+
class Otherwise < Data
|
|
10
|
+
include Rule
|
|
11
|
+
|
|
12
|
+
attr_reader target: route_target
|
|
13
|
+
attr_reader guard: Guard
|
|
14
|
+
attr_reader predicate: Predicate::Always
|
|
15
|
+
|
|
16
|
+
def initialize: (target: route_target, ?guard: Guard?) -> void
|
|
17
|
+
|
|
18
|
+
# Routes the message through the target route.
|
|
19
|
+
def apply: (message, _DataModel, Routes) -> Transition
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
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
|
+
module Router
|
|
8
|
+
# Collection of otherwise rules.
|
|
9
|
+
class Otherwises < Data
|
|
10
|
+
include Registry[Otherwise]
|
|
11
|
+
|
|
12
|
+
attr_reader rules: Array[Otherwise]
|
|
13
|
+
|
|
14
|
+
def initialize: (?rules: Array[Otherwise]) -> void
|
|
15
|
+
|
|
16
|
+
# Adds an otherwise rule with optional guard.
|
|
17
|
+
def add: (route_to: route_target, ?guard: guard?, ?when: guard?, ?unless: guard?) -> void
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,51 @@
|
|
|
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
|
+
module Router
|
|
8
|
+
# Predicate classes for message matching.
|
|
9
|
+
module Predicate
|
|
10
|
+
# Matches key events by symbol.
|
|
11
|
+
class Events < Data
|
|
12
|
+
attr_reader keys: Array[Symbol]
|
|
13
|
+
|
|
14
|
+
def initialize: (keys: Symbol | Array[Symbol]) -> void
|
|
15
|
+
def arity: () -> Integer
|
|
16
|
+
def call: (message, _DataModel) -> boolish
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Matches routed messages by single envelope.
|
|
20
|
+
class Routed < Data
|
|
21
|
+
attr_reader envelope: Symbol
|
|
22
|
+
|
|
23
|
+
def arity: () -> Integer
|
|
24
|
+
def call: (message, _DataModel) -> boolish
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Matches routed messages by any of the given envelopes.
|
|
28
|
+
class RoutedEnvelopes < Data
|
|
29
|
+
attr_reader envelopes: Array[Symbol]
|
|
30
|
+
|
|
31
|
+
def initialize: (envelopes: Symbol | Array[Symbol]) -> void
|
|
32
|
+
def arity: () -> Integer
|
|
33
|
+
def call: (message, _DataModel) -> boolish
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Matches messages by class.
|
|
37
|
+
class InstancesOf < Data
|
|
38
|
+
attr_reader klass: Class
|
|
39
|
+
|
|
40
|
+
def arity: () -> Integer
|
|
41
|
+
def call: (message, _DataModel) -> boolish
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Matches all messages.
|
|
45
|
+
class Always < Data
|
|
46
|
+
def arity: () -> Integer
|
|
47
|
+
def call: (message, _DataModel) -> boolish
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
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
|
+
module Router
|
|
8
|
+
# Receive rule - matches messages and delegates to action.
|
|
9
|
+
class Receive < Data
|
|
10
|
+
include Rule
|
|
11
|
+
|
|
12
|
+
attr_reader predicate: predicate
|
|
13
|
+
attr_reader action: action
|
|
14
|
+
attr_reader guard: Guard
|
|
15
|
+
|
|
16
|
+
# Applies the action and returns a Transition.
|
|
17
|
+
def apply: (message, _DataModel, Routes) -> Transition
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
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
|
+
module Router
|
|
8
|
+
# Collection of receive rules.
|
|
9
|
+
class Receives < Data
|
|
10
|
+
include Registry[Receive]
|
|
11
|
+
|
|
12
|
+
attr_reader rules: Array[Receive]
|
|
13
|
+
attr_reader actions: Actions
|
|
14
|
+
|
|
15
|
+
def initialize: (?rules: Array[Receive], actions: Actions) -> void
|
|
16
|
+
|
|
17
|
+
# Adds a receive rule matching key events.
|
|
18
|
+
def add_events: (Symbol | Array[Symbol] keys, handler_or_action handler, ?guard: guard?, ?when: guard?, ?unless: guard?) -> void
|
|
19
|
+
|
|
20
|
+
# Adds a receive rule matching routed messages by envelope.
|
|
21
|
+
def add_routed: (Symbol envelope, handler_or_action handler, ?guard: guard?) -> void
|
|
22
|
+
|
|
23
|
+
# Adds a receive rule matching class instances.
|
|
24
|
+
def add_instances_of: (Class klass, handler_or_action handler, ?guard: guard?) -> void
|
|
25
|
+
|
|
26
|
+
# Adds a catch-all receive rule.
|
|
27
|
+
def add_all: (handler_or_action handler, ?guard: guard?, ?when: guard?, ?unless: guard?) -> void
|
|
28
|
+
|
|
29
|
+
# Adds a receive rule matching a custom predicate.
|
|
30
|
+
def add_custom: (guard predicate, handler_or_action handler, ?guard: guard?) -> void
|
|
31
|
+
|
|
32
|
+
private
|
|
33
|
+
|
|
34
|
+
# Resolves a Symbol action name to its Action, or wraps a lambda.
|
|
35
|
+
def resolve: (handler_or_action handler) -> action
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
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
|
+
module Router
|
|
8
|
+
# Common behavior for Rule collections.
|
|
9
|
+
# Including classes must define `rules` as a Data member.
|
|
10
|
+
module Registry[T]
|
|
11
|
+
include Enumerable[T]
|
|
12
|
+
|
|
13
|
+
# The underlying rules collection (provided by including Data class).
|
|
14
|
+
def rules: () -> Array[T]
|
|
15
|
+
|
|
16
|
+
# Appends a rule to the collection.
|
|
17
|
+
def add: (T rule) -> Array[T]
|
|
18
|
+
|
|
19
|
+
# Iterates over all rules.
|
|
20
|
+
def each: () { (T) -> void } -> Array[T]
|
|
21
|
+
| () -> Enumerator[T, Array[T]]
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
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
|
+
module Router
|
|
8
|
+
# A configured route to a child fragment.
|
|
9
|
+
class Route < Data
|
|
10
|
+
# Route prefix symbol (model accessor name).
|
|
11
|
+
attr_reader prefix: Symbol
|
|
12
|
+
|
|
13
|
+
# Fragment module with Update callable.
|
|
14
|
+
attr_reader fragment: Module
|
|
15
|
+
|
|
16
|
+
# Optional custom model reader.
|
|
17
|
+
attr_reader read: (^(_DataModel) -> _DataModel)?
|
|
18
|
+
|
|
19
|
+
# Optional custom model writer.
|
|
20
|
+
attr_reader write: (^(_DataModel, _DataModel) -> _DataModel)?
|
|
21
|
+
|
|
22
|
+
def self.new: (
|
|
23
|
+
prefix: Symbol,
|
|
24
|
+
fragment: Module,
|
|
25
|
+
?read: (^(_DataModel) -> _DataModel)?,
|
|
26
|
+
?write: (^(_DataModel, _DataModel) -> _DataModel)?
|
|
27
|
+
) -> instance
|
|
28
|
+
|
|
29
|
+
def initialize: (
|
|
30
|
+
prefix: Symbol,
|
|
31
|
+
fragment: Module,
|
|
32
|
+
?read: (^(_DataModel) -> _DataModel)?,
|
|
33
|
+
?write: (^(_DataModel, _DataModel) -> _DataModel)?
|
|
34
|
+
) -> void
|
|
35
|
+
|
|
36
|
+
# Delegates message to child fragment and merges result.
|
|
37
|
+
def delegate: (message msg, _DataModel model) -> [_DataModel, Command::execution?]
|
|
38
|
+
|
|
39
|
+
private
|
|
40
|
+
|
|
41
|
+
def extract: (_DataModel model) -> _DataModel
|
|
42
|
+
|
|
43
|
+
def merge: (_DataModel model, _DataModel new_child) -> _DataModel
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
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
|
+
module Router
|
|
8
|
+
# Encapsulates dispatch logic - given frozen flow objects, processes messages.
|
|
9
|
+
class RouterUpdate < Data
|
|
10
|
+
attr_reader inward: Flow::Inward
|
|
11
|
+
attr_reader outward: Flow::Outward
|
|
12
|
+
|
|
13
|
+
def initialize: (
|
|
14
|
+
inward: Flow::Inward,
|
|
15
|
+
outward: Flow::Outward
|
|
16
|
+
) -> void
|
|
17
|
+
|
|
18
|
+
# Dispatches a message through the router pipeline.
|
|
19
|
+
def call: (message, _DataModel) -> [_DataModel, Command::execution?]
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
|
|
23
|
+
# Handles inward dispatch (non-bubbled messages).
|
|
24
|
+
def dispatch_inward: (message, _DataModel) -> [_DataModel, Command::execution?]
|
|
25
|
+
|
|
26
|
+
# Extracts bubbles from a Command::Batch and processes them.
|
|
27
|
+
def extract_bubbles_from_batch: (Transition transition) -> Transition
|
|
28
|
+
|
|
29
|
+
# Handles outward dispatch (bubbled messages).
|
|
30
|
+
def dispatch_outward: (message, _DataModel) -> [_DataModel, Command::execution?]
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
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
|
+
module Router
|
|
8
|
+
# Collection of routes - offers add/fetch/broadcast interface.
|
|
9
|
+
class Routes
|
|
10
|
+
include Enumerable[Route]
|
|
11
|
+
|
|
12
|
+
@routes: Set[Route]
|
|
13
|
+
|
|
14
|
+
def initialize: (?Set[Route] routes) -> void
|
|
15
|
+
|
|
16
|
+
# Adds a route to the collection. Returns the route for capture.
|
|
17
|
+
def add: (Route route) -> Route
|
|
18
|
+
|
|
19
|
+
# Resolves a target (Module, Symbol, or Route) to a Route.
|
|
20
|
+
def for: (route_target identifier) -> Route?
|
|
21
|
+
|
|
22
|
+
# Iterates over all routes.
|
|
23
|
+
def each: () { (Route) -> void } -> Set[Route]
|
|
24
|
+
| () -> Enumerator[Route, Set[Route]]
|
|
25
|
+
|
|
26
|
+
# Returns a subset of routes for the given targets.
|
|
27
|
+
def subset: (Array[route_target] targets) -> Routes
|
|
28
|
+
|
|
29
|
+
# Broadcasts a message to all routes, accumulating transitions.
|
|
30
|
+
def broadcast: (message msg, _DataModel model) -> Transition
|
|
31
|
+
|
|
32
|
+
# Broadcasts to a specific subset of routes.
|
|
33
|
+
def broadcast_to: (Array[route_target] targets, message msg, _DataModel model) -> Transition
|
|
34
|
+
|
|
35
|
+
private
|
|
36
|
+
|
|
37
|
+
# Finds the unique route matching the block, raises on ambiguity.
|
|
38
|
+
def unique: (route_target identifier) { (Route) -> boolish } -> Route?
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
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
|
+
module Router
|
|
8
|
+
# Predicate type: callable matching (message, model).
|
|
9
|
+
type predicate = Predicate::Events | Predicate::Routed | Predicate::RoutedEnvelopes
|
|
10
|
+
| Predicate::InstancesOf | Predicate::Always
|
|
11
|
+
| ^(message, _DataModel) -> boolish
|
|
12
|
+
|
|
13
|
+
# Common behavior for routing rules (Forward, Receive, Observe, Otherwise).
|
|
14
|
+
module Rule
|
|
15
|
+
# Provided by including Data class: the message-matching predicate.
|
|
16
|
+
def predicate: () -> predicate
|
|
17
|
+
|
|
18
|
+
# Provided by including Data class: the guard condition.
|
|
19
|
+
def guard: () -> Guard
|
|
20
|
+
|
|
21
|
+
# Provided by including Data class: applies the rule to a message.
|
|
22
|
+
def apply: (message, _DataModel, Routes) -> Transition
|
|
23
|
+
|
|
24
|
+
# Tests predicate and guard.
|
|
25
|
+
def matches?: (Configuration config) -> boolish
|
|
26
|
+
|
|
27
|
+
# Matches and applies if matching. Returns Transition or nil.
|
|
28
|
+
def apply_if_matches: (Configuration config, Routes routes) -> Transition?
|
|
29
|
+
|
|
30
|
+
private
|
|
31
|
+
|
|
32
|
+
def predicate_matches?: (Configuration config) -> boolish
|
|
33
|
+
def guard_passes?: (Configuration config) -> boolish
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|