ratatui_ruby-tea 0.3.1 → 0.4.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/AGENTS.md +42 -2
- data/CHANGELOG.md +76 -0
- data/README.md +8 -5
- data/doc/concepts/async_work.md +164 -0
- data/doc/concepts/commands.md +528 -0
- data/doc/concepts/message_processing.md +51 -0
- data/doc/contributors/WIP/decomposition_strategies_analysis.md +258 -0
- data/doc/contributors/WIP/implementation_plan.md +405 -0
- data/doc/contributors/WIP/init_callable_proposal.md +341 -0
- data/doc/contributors/WIP/mvu_tea_implementations_research.md +372 -0
- data/doc/contributors/WIP/runtime_refactoring_status.md +47 -0
- data/doc/contributors/WIP/task.md +36 -0
- data/doc/contributors/WIP/v0.4.0_todo.md +468 -0
- data/doc/contributors/design/commands_and_outlets.md +11 -1
- data/doc/contributors/priorities.md +22 -24
- data/examples/app_fractal_dashboard/app.rb +3 -7
- data/examples/app_fractal_dashboard/dashboard/base.rb +15 -16
- data/examples/app_fractal_dashboard/dashboard/update_helpers.rb +8 -8
- data/examples/app_fractal_dashboard/dashboard/update_manual.rb +11 -11
- data/examples/app_fractal_dashboard/dashboard/update_router.rb +4 -4
- data/examples/app_fractal_dashboard/{bags → fragments}/custom_shell_input.rb +8 -4
- data/examples/app_fractal_dashboard/fragments/custom_shell_modal.rb +82 -0
- data/examples/app_fractal_dashboard/{bags → fragments}/custom_shell_output.rb +8 -4
- data/examples/app_fractal_dashboard/{bags → fragments}/disk_usage.rb +13 -10
- data/examples/app_fractal_dashboard/{bags → fragments}/network_panel.rb +12 -12
- data/examples/app_fractal_dashboard/{bags → fragments}/ping.rb +12 -8
- data/examples/app_fractal_dashboard/{bags → fragments}/stats_panel.rb +12 -12
- data/examples/app_fractal_dashboard/{bags → fragments}/system_info.rb +11 -7
- data/examples/app_fractal_dashboard/{bags → fragments}/uptime.rb +11 -7
- data/examples/verify_readme_usage/README.md +7 -4
- data/examples/verify_readme_usage/app.rb +7 -4
- data/lib/ratatui_ruby/tea/command/all.rb +71 -0
- data/lib/ratatui_ruby/tea/command/batch.rb +79 -0
- data/lib/ratatui_ruby/tea/command/custom.rb +1 -1
- data/lib/ratatui_ruby/tea/command/http.rb +194 -0
- data/lib/ratatui_ruby/tea/command/lifecycle.rb +136 -0
- data/lib/ratatui_ruby/tea/command/outlet.rb +59 -27
- data/lib/ratatui_ruby/tea/command/wait.rb +82 -0
- data/lib/ratatui_ruby/tea/command.rb +245 -64
- data/lib/ratatui_ruby/tea/message/all.rb +47 -0
- data/lib/ratatui_ruby/tea/message/http_response.rb +63 -0
- data/lib/ratatui_ruby/tea/message/system/batch.rb +63 -0
- data/lib/ratatui_ruby/tea/message/system/stream.rb +69 -0
- data/lib/ratatui_ruby/tea/message/timer.rb +48 -0
- data/lib/ratatui_ruby/tea/message.rb +40 -0
- data/lib/ratatui_ruby/tea/router.rb +11 -11
- data/lib/ratatui_ruby/tea/runtime.rb +320 -185
- data/lib/ratatui_ruby/tea/shortcuts.rb +2 -2
- data/lib/ratatui_ruby/tea/test_helper.rb +58 -0
- data/lib/ratatui_ruby/tea/version.rb +1 -1
- data/lib/ratatui_ruby/tea.rb +44 -10
- data/rbs_collection.lock.yaml +1 -17
- data/sig/concurrent.rbs +72 -0
- data/sig/ratatui_ruby/tea/command.rbs +141 -37
- data/sig/ratatui_ruby/tea/message.rbs +123 -0
- data/sig/ratatui_ruby/tea/router.rbs +1 -1
- data/sig/ratatui_ruby/tea/runtime.rbs +39 -6
- data/sig/ratatui_ruby/tea/test_helper.rbs +12 -0
- data/sig/ratatui_ruby/tea.rbs +24 -4
- metadata +63 -11
- data/examples/app_fractal_dashboard/bags/custom_shell_modal.rb +0 -73
- data/lib/ratatui_ruby/tea/command/cancellation_token.rb +0 -135
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
#--
|
|
4
|
+
# SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
|
|
5
|
+
# SPDX-License-Identifier: LGPL-3.0-or-later
|
|
6
|
+
#++
|
|
7
|
+
|
|
8
|
+
module RatatuiRuby
|
|
9
|
+
module Tea
|
|
10
|
+
module Message
|
|
11
|
+
module System
|
|
12
|
+
# Streaming message from a system command.
|
|
13
|
+
#
|
|
14
|
+
# Streaming commands send incremental output instead of batching. Each line
|
|
15
|
+
# is a separate message, followed by a completion message.
|
|
16
|
+
#
|
|
17
|
+
# This message includes predicates to distinguish stdout, stderr, and
|
|
18
|
+
# completion events for pattern matching workflows.
|
|
19
|
+
#
|
|
20
|
+
# Use it to handle <tt>Command.system(..., stream: true)</tt> output.
|
|
21
|
+
#
|
|
22
|
+
# === Example
|
|
23
|
+
#
|
|
24
|
+
# case msg
|
|
25
|
+
# in { type: :system_stream, envelope: :build, stream: :stdout, content: }
|
|
26
|
+
# model.with(log: model[:log] + content)
|
|
27
|
+
# in { type: :system_stream, envelope: :build, stream: :complete, status: 0 }
|
|
28
|
+
# model.with(success: true)
|
|
29
|
+
# end
|
|
30
|
+
#
|
|
31
|
+
Stream = Data.define(:envelope, :stream, :content, :status) do
|
|
32
|
+
include Predicates
|
|
33
|
+
|
|
34
|
+
# Returns <tt>true</tt> for system stream messages.
|
|
35
|
+
def system?
|
|
36
|
+
true
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Returns <tt>true</tt> for stdout messages.
|
|
40
|
+
def stdout?
|
|
41
|
+
stream == :stdout
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Returns <tt>true</tt> for stderr messages.
|
|
45
|
+
def stderr?
|
|
46
|
+
stream == :stderr
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Returns <tt>true</tt> for complete messages.
|
|
50
|
+
def complete?
|
|
51
|
+
stream == :complete
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Deconstructs for pattern matching.
|
|
55
|
+
#
|
|
56
|
+
# Returns a hash with <tt>:type</tt>, <tt>:envelope</tt>, <tt>:stream</tt>,
|
|
57
|
+
# and either <tt>:content</tt> (for stdout/stderr) or <tt>:status</tt> (for complete).
|
|
58
|
+
def deconstruct_keys(_keys)
|
|
59
|
+
if complete?
|
|
60
|
+
{ type: :system_stream, envelope:, stream:, status: }
|
|
61
|
+
else
|
|
62
|
+
{ type: :system_stream, envelope:, stream:, content: }
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
#--
|
|
4
|
+
# SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
|
|
5
|
+
# SPDX-License-Identifier: LGPL-3.0-or-later
|
|
6
|
+
#++
|
|
7
|
+
|
|
8
|
+
module RatatuiRuby
|
|
9
|
+
module Tea
|
|
10
|
+
module Message
|
|
11
|
+
# Response from a timer command.
|
|
12
|
+
#
|
|
13
|
+
# Timer commands fire after a delay. Pattern matching in UPDATE distinguishes
|
|
14
|
+
# multiple timers. Without structured responses, timers return bare symbols—hard
|
|
15
|
+
# to extend with elapsed time or other metadata.
|
|
16
|
+
#
|
|
17
|
+
# This response includes the envelope for routing and elapsed time. Include
|
|
18
|
+
# Predicates for safe predicate calls on any message.
|
|
19
|
+
#
|
|
20
|
+
# Use it to handle +Command.wait+ or +Command.tick+ completions.
|
|
21
|
+
#
|
|
22
|
+
# === Example
|
|
23
|
+
#
|
|
24
|
+
# case msg
|
|
25
|
+
# in { type: :timer, envelope: :dismiss }
|
|
26
|
+
# model.with(notification: nil)
|
|
27
|
+
# in { type: :timer, envelope: :animate, elapsed: }
|
|
28
|
+
# model.with(frame: next_frame(elapsed))
|
|
29
|
+
# end
|
|
30
|
+
#
|
|
31
|
+
Timer = Data.define(:envelope, :elapsed) do
|
|
32
|
+
include Predicates
|
|
33
|
+
|
|
34
|
+
# Returns +true+ for timer responses.
|
|
35
|
+
def timer?
|
|
36
|
+
true
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Deconstructs for pattern matching.
|
|
40
|
+
#
|
|
41
|
+
# Returns a hash with <tt>:type</tt>, <tt>:envelope</tt>, and <tt>:elapsed</tt>.
|
|
42
|
+
def deconstruct_keys(_keys)
|
|
43
|
+
{ type: :timer, envelope:, elapsed: }
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
#--
|
|
4
|
+
# SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
|
|
5
|
+
# SPDX-License-Identifier: LGPL-3.0-or-later
|
|
6
|
+
#++
|
|
7
|
+
|
|
8
|
+
module RatatuiRuby
|
|
9
|
+
module Tea
|
|
10
|
+
# Messages sent from commands to update functions.
|
|
11
|
+
#
|
|
12
|
+
# All built-in response types live here. Each includes the +Predicates+
|
|
13
|
+
# mixin for safe predicate calls.
|
|
14
|
+
module Message
|
|
15
|
+
# Fallback predicate mixin.
|
|
16
|
+
#
|
|
17
|
+
# Returns +false+ for any unknown predicate method (ending in +?+).
|
|
18
|
+
# Include in custom message types for safe predicate calls.
|
|
19
|
+
module Predicates
|
|
20
|
+
# Returns +false+ for unknown predicate methods.
|
|
21
|
+
def method_missing(name, *args, **kwargs, &block)
|
|
22
|
+
return false if name.to_s.end_with?("?") && args.empty? && kwargs.empty?
|
|
23
|
+
|
|
24
|
+
super
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Responds to all predicate methods.
|
|
28
|
+
def respond_to_missing?(name, *)
|
|
29
|
+
name.to_s.end_with?("?")
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
require_relative "message/timer"
|
|
37
|
+
require_relative "message/http_response"
|
|
38
|
+
require_relative "message/system/batch"
|
|
39
|
+
require_relative "message/system/stream"
|
|
40
|
+
require_relative "message/all"
|
|
@@ -9,16 +9,16 @@ module RatatuiRuby
|
|
|
9
9
|
module Tea
|
|
10
10
|
# Declarative DSL for Fractal Architecture.
|
|
11
11
|
#
|
|
12
|
-
# Large applications decompose into
|
|
13
|
-
# UPDATE, and VIEW. Parent
|
|
12
|
+
# Large applications decompose into fragments. Each fragment has its own Model,
|
|
13
|
+
# UPDATE, and VIEW. Parent fragments route messages to child fragments and compose views.
|
|
14
14
|
# Writing this routing logic by hand is tedious and error-prone.
|
|
15
15
|
#
|
|
16
16
|
# Include this module to declare routes and keymaps. Call +from_router+ to
|
|
17
17
|
# generate an UPDATE lambda that handles routing automatically.
|
|
18
18
|
#
|
|
19
|
-
# A *
|
|
20
|
-
# <tt>UPDATE</tt>, and <tt>VIEW</tt> constants.
|
|
21
|
-
# delegate to child
|
|
19
|
+
# A *fragment* is a module containing <tt>Model</tt>, <tt>INITIAL</tt>,
|
|
20
|
+
# <tt>UPDATE</tt>, and <tt>VIEW</tt> constants. Fragments compose: parent fragments
|
|
21
|
+
# delegate to child fragments.
|
|
22
22
|
#
|
|
23
23
|
# === Example
|
|
24
24
|
#
|
|
@@ -171,13 +171,13 @@ module RatatuiRuby
|
|
|
171
171
|
|
|
172
172
|
# Process message and return [model, command] tuple.
|
|
173
173
|
def call(message, model)
|
|
174
|
-
# 1. Try routing prefixed messages to child
|
|
175
|
-
@routes.each do |prefix,
|
|
176
|
-
|
|
177
|
-
result = Tea.delegate(message, prefix,
|
|
174
|
+
# 1. Try routing prefixed messages to child fragments
|
|
175
|
+
@routes.each do |prefix, fragment|
|
|
176
|
+
fragment_update = fragment.const_get(:Update)
|
|
177
|
+
result = Tea.delegate(message, prefix, fragment_update, model.public_send(prefix))
|
|
178
178
|
if result
|
|
179
|
-
|
|
180
|
-
return [model.with(prefix =>
|
|
179
|
+
new_fragment_model, command = result
|
|
180
|
+
return [model.with(prefix => new_fragment_model), command] #: [_DataModel, Command::execution?]
|
|
181
181
|
end
|
|
182
182
|
end
|
|
183
183
|
|