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
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
<!--
|
|
2
|
-
SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
|
|
3
|
-
SPDX-License-Identifier: CC-BY-SA-4.0
|
|
4
|
-
-->
|
|
5
|
-
|
|
6
|
-
# Message Processing
|
|
7
|
-
|
|
8
|
-
The runtime processes messages one at a time.
|
|
9
|
-
|
|
10
|
-
You build interactive apps. Events arrive from everywhere: keyboard, mouse,
|
|
11
|
-
timers, HTTP responses. Coordinating concurrent results feels complex.
|
|
12
|
-
|
|
13
|
-
Rooibos handles the concurrency. Your `update` function handles exactly one message
|
|
14
|
-
per invocation. The runtime schedules everything else.
|
|
15
|
-
|
|
16
|
-
## Recurring Ticks
|
|
17
|
-
|
|
18
|
-
For animations or polling, re-dispatch the tick in your update function:
|
|
19
|
-
|
|
20
|
-
```ruby
|
|
21
|
-
def update(msg, model)
|
|
22
|
-
case msg
|
|
23
|
-
when [:tick, _elapsed]
|
|
24
|
-
[model.with(frame: model.frame + 1), Command.tick(0.016, :tick)]
|
|
25
|
-
end
|
|
26
|
-
end
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
Can a tick and a keyboard event arrive at the same time?
|
|
30
|
-
|
|
31
|
-
No. The runtime serializes all messages. Each frame, it polls for user input,
|
|
32
|
-
calls `update` with any event it finds, and dispatches the returned command.
|
|
33
|
-
Then it drains the background channel, calling `update` once for each queued
|
|
34
|
-
message. Two events that occur in the same frame become two sequential calls.
|
|
35
|
-
Each returns its own command. They never collide.
|
|
36
|
-
|
|
37
|
-
## When to Use Command.batch
|
|
38
|
-
|
|
39
|
-
Use `Command.batch` when a single message triggers multiple effects:
|
|
40
|
-
|
|
41
|
-
```ruby
|
|
42
|
-
when :init
|
|
43
|
-
[model, Command.batch(
|
|
44
|
-
Command.tick(0.016, :tick),
|
|
45
|
-
Command.http(get: "/api/data", :loaded)
|
|
46
|
-
)]
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
This differs from "two messages arrived simultaneously." Here, you send two
|
|
50
|
-
commands at once. Even if both complete in exactly the same time, their results
|
|
51
|
-
arrive as two distinct calls to `update`.
|
|
@@ -1,258 +0,0 @@
|
|
|
1
|
-
<!--
|
|
2
|
-
SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
|
|
3
|
-
|
|
4
|
-
SPDX-License-Identifier: CC-BY-SA-4.0
|
|
5
|
-
-->
|
|
6
|
-
|
|
7
|
-
# MVU/TEA Decomposition Strategies Analysis
|
|
8
|
-
|
|
9
|
-
## Decomposition Style Categories
|
|
10
|
-
|
|
11
|
-
### FRACTAL Style (Recursive MVU Triads)
|
|
12
|
-
Each component/module is a complete MVU unit with its own Model, Update, and View. Components nest recursively, parent delegates to children. Child components are self-contained and can be composed.
|
|
13
|
-
|
|
14
|
-
### SLICE Style (Domain-Segregated State)
|
|
15
|
-
State is partitioned by domain/feature, but update/view logic may be centralized or cross-cutting. Each slice typically has Model + Update, with views potentially pulling from multiple slices.
|
|
16
|
-
|
|
17
|
-
### HYBRID
|
|
18
|
-
Combines both patterns - some aspects use fractal composition, others use slice partitioning.
|
|
19
|
-
|
|
20
|
-
### NO DECOMPOSITION
|
|
21
|
-
Framework does not provide explicit support for breaking down complex applications.
|
|
22
|
-
|
|
23
|
-
---
|
|
24
|
-
|
|
25
|
-
## Framework Categorization
|
|
26
|
-
|
|
27
|
-
### 🟢 FRACTAL Decomposition
|
|
28
|
-
|
|
29
|
-
#### **1. Elm (Original TEA)**
|
|
30
|
-
- **Style**: Fractal (historically, with evolution)
|
|
31
|
-
- **Terminology**: "Nested TEA", "Modules", "Translator Pattern" / "OutMsg Pattern"
|
|
32
|
-
- **Details**:
|
|
33
|
-
- Originally promoted recursive MVU triads (child modules with own Model/Msg/update/view)
|
|
34
|
-
- Parent uses `Html.map` and `Cmd.map` to transform child messages
|
|
35
|
-
- **Evolution**: Elm 0.19 de-emphasized deep nesting due to boilerplate
|
|
36
|
-
- Current recommendation: Shallow nesting, reusable view functions over deep component trees
|
|
37
|
-
- "Translator Pattern" for child-to-parent communication (child returns OutMsg for parent)
|
|
38
|
-
- **Composition**: Yes, via `Html.map` / `Cmd.map` and OutMsg pattern
|
|
39
|
-
|
|
40
|
-
#### **2. Bubble Tea (Go)**
|
|
41
|
-
- **Style**: Fractal
|
|
42
|
-
- **Terminology**: "Tree of Models", "Nested Models", "Child Components"
|
|
43
|
-
- **Details**:
|
|
44
|
-
- Each component has its own `Model` struct with `Init()`, `Update()`, `View()` methods
|
|
45
|
-
- Parent embeds child models as fields
|
|
46
|
-
- Parent routes messages to children based on state (often using session/state enum)
|
|
47
|
-
- View composition combines child view strings
|
|
48
|
-
- Uses "Bubbles" library for pre-built components
|
|
49
|
-
- **Composition**: Yes, explicit message routing in parent's Update
|
|
50
|
-
|
|
51
|
-
#### **3. Iced (Rust)**
|
|
52
|
-
- **Style**: Fractal
|
|
53
|
-
- **Terminology**: "Nested components", "Message routing", "`.map()` transformation"
|
|
54
|
-
- **Details**:
|
|
55
|
-
- Each component can have State + Message enum + update + view
|
|
56
|
-
- Parent's Message enum wraps child Message types
|
|
57
|
-
- Uses `.map()` to transform child messages/commands/elements to parent context
|
|
58
|
-
- `Subscription::batch()` for combining child subscriptions
|
|
59
|
-
- Note: `Component` trait deprecated in 0.13+ (violated single source of truth)
|
|
60
|
-
- **Composition**: Yes, via `.map()` transformation
|
|
61
|
-
|
|
62
|
-
#### **4. Elmish (F#/Fable)**
|
|
63
|
-
- **Style**: Fractal
|
|
64
|
-
- **Terminology**: "Nested TEA", "Child modules"
|
|
65
|
-
- **Details**:
|
|
66
|
-
- Direct port of Elm Architecture to F#
|
|
67
|
-
- Each module has `Model * Cmd<Msg>` init, `update`, `view`
|
|
68
|
-
- Parent maps child messages and commands
|
|
69
|
-
- Used with React for rendering
|
|
70
|
-
- **Composition**: Yes, same as Elm
|
|
71
|
-
|
|
72
|
-
#### **5. Hyperapp (JavaScript)**
|
|
73
|
-
- **Style**: Fractal-lite
|
|
74
|
-
- **Terminology**: No specific term (minimal framework)
|
|
75
|
-
- **Details**:
|
|
76
|
-
- Unified global state, but can be structured recursively
|
|
77
|
-
- Effects can be nested in init array `[state, effect1, effect2]`
|
|
78
|
-
- Very lightweight (1KB), minimal opinions
|
|
79
|
-
- **Composition**: Limited, more state-tree focused than component-focused
|
|
80
|
-
|
|
81
|
-
---
|
|
82
|
-
|
|
83
|
-
### 🔵 SLICE Decomposition
|
|
84
|
-
|
|
85
|
-
#### **6. Redux (JavaScript/React)**
|
|
86
|
-
- **Style**: PURE SLICE
|
|
87
|
-
- **Terminology**: "Slices", "Reducers", "State combination"
|
|
88
|
-
- **Details**:
|
|
89
|
-
- `createSlice` creates domain-specific state + reducers
|
|
90
|
-
- Each slice has `name`, `initialState`, `reducers`
|
|
91
|
-
- Slices combined via `configureStore({ reducer: { user: userSlice, posts: postsSlice } })`
|
|
92
|
-
- Views (React components) can access any slice via selectors
|
|
93
|
-
- **NOT strictly MVU** (no built-in effects), but pattern is similar
|
|
94
|
-
- **Composition**: Yes, via `combineReducers` / `configureStore`
|
|
95
|
-
- **Notable**: Slices have reducers, but no dedicated views - views are separate React components
|
|
96
|
-
|
|
97
|
-
---
|
|
98
|
-
|
|
99
|
-
### 🟡 HYBRID Decomposition
|
|
100
|
-
|
|
101
|
-
#### **7. TCA (Swift - The Composable Architecture)**
|
|
102
|
-
- **Style**: HYBRID (Fractal-ish with powerful scoping)
|
|
103
|
-
- **Terminology**: "Reducers", "Scoping", "Pullback", "Child features", "Composition"
|
|
104
|
-
- **Details**:
|
|
105
|
-
- Each "feature" is a `Reducer` with nested `State` and `Action` types
|
|
106
|
-
- Uses `.scope()` to focus parent state/actions on child domain
|
|
107
|
-
- Can compose reducers horizontally (siblings) or vertically (parent-child)
|
|
108
|
-
- **More sophisticated than pure fractal**: dependency injection, effects management, testing tools
|
|
109
|
-
- Parent doesn't just delegate - uses lenses/scoping to project state
|
|
110
|
-
- **Composition**: Yes, via `Reducer` composition operators and scoping
|
|
111
|
-
|
|
112
|
-
#### **8. Flutter Bloc**
|
|
113
|
-
- **Style**: HYBRID
|
|
114
|
-
- **Terminology**: "BloC per feature/screen", "Nested BloCs", "BlocProvider", "MultiBlocProvider"
|
|
115
|
-
- **Details**:
|
|
116
|
-
- Recommended pattern: one Bloc/Cubit per screen or feature
|
|
117
|
-
- BloCs can be nested via `BlocProvider` (dependency injection)
|
|
118
|
-
- `MultiBlocProvider` for multiple BloCs in widget tree
|
|
119
|
-
- **Not pure fractal**: BloCs don't nest MVU triads, they're separate event-driven state machines
|
|
120
|
-
- **Not pure slice**: Each BloC is feature-specific, views are Flutter widgets
|
|
121
|
-
- **Composition**: Yes, via provider pattern (DI), not via direct delegation
|
|
122
|
-
|
|
123
|
-
#### **9. Android MVI (Kotlin)**
|
|
124
|
-
- **Style**: HYBRID
|
|
125
|
-
- **Terminology**: "ViewModel per feature", "StateFlow", "Intent channels"
|
|
126
|
-
- **Details**:
|
|
127
|
-
- Each ViewModel manages feature state via `StateFlow`
|
|
128
|
-
- Intents sent to ViewModel via `SharedFlow` or `Channel`
|
|
129
|
-
- ViewModels can be scoped to fragments/activities
|
|
130
|
-
- **Not pure fractal**: ViewModels are independent state machines, not nested MVU
|
|
131
|
-
- **Not pure slice**: Each ViewModel is feature-bound
|
|
132
|
-
- **Composition**: Limited, mostly via ViewModel scoping and shared state
|
|
133
|
-
|
|
134
|
-
#### **10. Meiosis (JavaScript)**
|
|
135
|
-
- **Style**: HYBRID
|
|
136
|
-
- **Terminology**: "Services", "Nested components" (optional), "Initial model composition"
|
|
137
|
-
- **Details**:
|
|
138
|
-
- Flexible pattern, not opinionated
|
|
139
|
-
- Can compose via `initialModel` merging
|
|
140
|
-
- "meiosis-setup" library helps with nested components and services
|
|
141
|
-
- View-library agnostic
|
|
142
|
-
- **Composition**: Yes, but flexible/manual
|
|
143
|
-
|
|
144
|
-
---
|
|
145
|
-
|
|
146
|
-
### ⚫ NO EXPLICIT DECOMPOSITION
|
|
147
|
-
|
|
148
|
-
#### **11. SAM Pattern (JavaScript)**
|
|
149
|
-
- **Style**: No explicit decomposition support
|
|
150
|
-
- **Terminology**: N/A
|
|
151
|
-
- **Details**:
|
|
152
|
-
- Single Model (state tree)
|
|
153
|
-
- Single State Representation function
|
|
154
|
-
- Actions propose mutations
|
|
155
|
-
- Based on TLA+ formalism
|
|
156
|
-
- **Philosophical**: Focused on temporal logic and correctness, less on composition
|
|
157
|
-
- **Composition**: Not a focus
|
|
158
|
-
|
|
159
|
-
---
|
|
160
|
-
|
|
161
|
-
### 🟣 OTHER / MINIMAL DOCUMENTATION
|
|
162
|
-
|
|
163
|
-
#### **12-16. .NET Implementations**
|
|
164
|
-
- **Fabulous (F#/MAUI)**: Likely **FRACTAL** (F# MVU port, similar to Elmish)
|
|
165
|
-
- **BlazorMVU (C#/Blazor)**: Likely **FRACTAL** (Elm-inspired)
|
|
166
|
-
- **MauiReactor (C#/MAUI)**: Likely **FRACTAL** (MVU for .NET MAUI)
|
|
167
|
-
- **MVUX (.NET/Uno)**: **HYBRID** (Model-View-Update eXtended, data binding focus)
|
|
168
|
-
- **ngx-mvu (Angular)**: Likely **HYBRID** (Angular + MVU concepts)
|
|
169
|
-
|
|
170
|
-
---
|
|
171
|
-
|
|
172
|
-
## Summary Table
|
|
173
|
-
|
|
174
|
-
| Framework | Style | Terminology |
|
|
175
|
-
|-----------|-------|-------------|
|
|
176
|
-
| **Elm** | Fractal (evolved) | Nested TEA, Modules, Translator/OutMsg Pattern |
|
|
177
|
-
| **Bubble Tea** | Fractal | Tree of Models, Nested Models, Child Components |
|
|
178
|
-
| **Iced** | Fractal | Nested components, Message routing, `.map()` |
|
|
179
|
-
| **Elmish** | Fractal | Nested TEA, Child modules |
|
|
180
|
-
| **Hyperapp** | Fractal-lite | (minimal framework, no specific term) |
|
|
181
|
-
| **Redux** | **SLICE** | **Slices**, Reducers, State combination |
|
|
182
|
-
| **TCA** | **HYBRID** | Reducers, Scoping, Pullback, Child features |
|
|
183
|
-
| **Flutter Bloc** | **HYBRID** | BloC per feature, Nested BloCs, Providers |
|
|
184
|
-
| **Android MVI** | **HYBRID** | ViewModel per feature, StateFlow, Intents |
|
|
185
|
-
| **Meiosis** | **HYBRID** | Services, Nested components (optional) |
|
|
186
|
-
| **SAM** | None | N/A (TLA+ formalism focus) |
|
|
187
|
-
| Fabulous | Fractal (likely) | (F# MVU) |
|
|
188
|
-
| BlazorMVU | Fractal (likely) | (Elm-inspired) |
|
|
189
|
-
| MauiReactor | Fractal (likely) | (MVU for MAUI) |
|
|
190
|
-
| MVUX | Hybrid (likely) | (Extended MVU, data binding) |
|
|
191
|
-
| ngx-mvu | Hybrid (likely) | (Angular + MVU) |
|
|
192
|
-
|
|
193
|
-
---
|
|
194
|
-
|
|
195
|
-
## Key Insights
|
|
196
|
-
|
|
197
|
-
### Fractal Pattern Characteristics:
|
|
198
|
-
1. ✅ **Complete MVU triads** for each component
|
|
199
|
-
2. ✅ **Recursive composition** (components contain components)
|
|
200
|
-
3. ✅ **Message delegation** (parent forwards to child)
|
|
201
|
-
4. ✅ **View composition** (parent combines child views)
|
|
202
|
-
5. ❌ **High boilerplate** (Elm community moved away from deep nesting)
|
|
203
|
-
|
|
204
|
-
**Examples**: Elm (original), Bubble Tea, Iced, Elmish
|
|
205
|
-
|
|
206
|
-
### Slice Pattern Characteristics:
|
|
207
|
-
1. ✅ **Domain-partitioned state** (slices by feature)
|
|
208
|
-
2. ✅ **Flat composition** (slices are siblings, not nested)
|
|
209
|
-
3. ✅ **Centralized view** (views pull from multiple slices)
|
|
210
|
-
4. ✅ **Low boilerplate** (slices are simple)
|
|
211
|
-
5. ❌ **No per-slice views** (views are separate layer)
|
|
212
|
-
|
|
213
|
-
**Example**: Redux (pure slice pattern)
|
|
214
|
-
|
|
215
|
-
### Hybrid Pattern Characteristics:
|
|
216
|
-
1. ✅ **Feature-scoped state** (like slices)
|
|
217
|
-
2. ✅ **Independent update logic** (like fractal)
|
|
218
|
-
3. ✅ **Flexible composition** (dependency injection, scoping)
|
|
219
|
-
4. ✅ **Reduced boilerplate** (compared to pure fractal)
|
|
220
|
-
5. ⚠️ **Framework-specific** (each does it differently)
|
|
221
|
-
|
|
222
|
-
**Examples**: TCA (scoping/pullback), Flutter Bloc (providers), Android MVI (ViewModels)
|
|
223
|
-
|
|
224
|
-
---
|
|
225
|
-
|
|
226
|
-
## Where Does Rooibos Fit?
|
|
227
|
-
|
|
228
|
-
### Current State: **FRACTAL**
|
|
229
|
-
- Fragments have `Model`, `INITIAL`, `UPDATE`, `VIEW`
|
|
230
|
-
- Parents delegate to children via `Rooibos.delegate`
|
|
231
|
-
- Message routing via `Rooibos.route`
|
|
232
|
-
- Router DSL for declarative composition
|
|
233
|
-
|
|
234
|
-
### With Init Callable: **ENHANCED FRACTAL**
|
|
235
|
-
Your `Init` proposal strengthens the fractal pattern by:
|
|
236
|
-
1. ✅ Enabling **parameterized initialization** (like Iced's `flags`)
|
|
237
|
-
2. ✅ Supporting **initial commands** (like Elm's `(Model, Cmd)`)
|
|
238
|
-
3. ✅ Allowing **parent-to-child props** (React-style, but fractal)
|
|
239
|
-
4. ✅ Maintaining **complete MVU triads** (Model, Init, Update, View)
|
|
240
|
-
|
|
241
|
-
This is **closer to Iced** (Rust) than Elm, as Iced explicitly supports flags for initialization and has evolved beyond Elm's original design.
|
|
242
|
-
|
|
243
|
-
---
|
|
244
|
-
|
|
245
|
-
## Recommendation
|
|
246
|
-
|
|
247
|
-
Rooibos should **embrace the modern fractal pattern** with:
|
|
248
|
-
- **Complete MVU triads per fragment**: `Model`, `Init`, `Update`, `View`
|
|
249
|
-
- **Parameterized initialization**: `Init` accepts flags/props
|
|
250
|
-
- **Explicit composition**: Parent calls child `Init`, routes messages, composes views
|
|
251
|
-
|
|
252
|
-
This positions Rooibos as:
|
|
253
|
-
- **Functional** (like Elm/Elmish/Iced)
|
|
254
|
-
- **Composable** (fractal pattern)
|
|
255
|
-
- **Modern** (Init callable, not static constants)
|
|
256
|
-
- **Parameterizable** (flags/props support)
|
|
257
|
-
|
|
258
|
-
**NOT** like Redux (slice pattern) or TCA/Bloc (OOP/hybrid patterns).
|