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.
Files changed (217) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSES/BSD-2-Clause.txt +9 -0
  3. data/REUSE.toml +5 -0
  4. data/exe/.gitkeep +0 -0
  5. data/lib/rooibos/cli/commands/new.rb +24 -0
  6. data/lib/rooibos/command/batch.rb +10 -0
  7. data/lib/rooibos/command/bubble.rb +34 -0
  8. data/lib/rooibos/command/custom.rb +3 -2
  9. data/lib/rooibos/command/deliver.rb +50 -0
  10. data/lib/rooibos/command/http.rb +1 -1
  11. data/lib/rooibos/command/lifecycle.rb +3 -1
  12. data/lib/rooibos/command/outlet.rb +19 -9
  13. data/lib/rooibos/command.rb +107 -3
  14. data/lib/rooibos/configuration.rb +29 -0
  15. data/lib/rooibos/message/bubbled.rb +29 -0
  16. data/lib/rooibos/message.rb +24 -6
  17. data/lib/rooibos/router/action.rb +36 -0
  18. data/lib/rooibos/router/flow/dispatch.rb +39 -0
  19. data/lib/rooibos/router/flow/inward.rb +41 -0
  20. data/lib/rooibos/router/flow/outward.rb +44 -0
  21. data/lib/rooibos/router/guard.rb +56 -0
  22. data/lib/rooibos/router/predicate.rb +65 -0
  23. data/lib/rooibos/router/registry/actions.rb +41 -0
  24. data/lib/rooibos/router/registry/forwards.rb +58 -0
  25. data/lib/rooibos/router/registry/observes.rb +57 -0
  26. data/lib/rooibos/router/registry/otherwises.rb +29 -0
  27. data/lib/rooibos/router/registry/receives.rb +57 -0
  28. data/lib/rooibos/router/registry/routes.rb +59 -0
  29. data/lib/rooibos/router/registry.rb +26 -0
  30. data/lib/rooibos/router/route.rb +42 -0
  31. data/lib/rooibos/router/router_update.rb +53 -0
  32. data/lib/rooibos/router/rule/forward.rb +39 -0
  33. data/lib/rooibos/router/rule/observe.rb +22 -0
  34. data/lib/rooibos/router/rule/otherwise.rb +26 -0
  35. data/lib/rooibos/router/rule/receive.rb +22 -0
  36. data/lib/rooibos/router/rule.rb +40 -0
  37. data/lib/rooibos/router.rb +424 -438
  38. data/lib/rooibos/runtime.rb +37 -52
  39. data/lib/rooibos/test_helper.rb +22 -0
  40. data/lib/rooibos/transition.rb +92 -0
  41. data/lib/rooibos/version.rb +1 -1
  42. data/lib/rooibos.rb +2 -57
  43. data/sig/rooibos/cli.rbs +1 -0
  44. data/sig/rooibos/command.rbs +44 -0
  45. data/sig/rooibos/configuration.rbs +20 -0
  46. data/sig/rooibos/message.rbs +12 -0
  47. data/sig/rooibos/router/action.rbs +33 -0
  48. data/sig/rooibos/router/actions.rbs +27 -0
  49. data/sig/rooibos/router/flow/dispatch.rbs +29 -0
  50. data/sig/rooibos/router/flow/inward.rbs +37 -0
  51. data/sig/rooibos/router/flow/outward.rbs +36 -0
  52. data/sig/rooibos/router/forward.rbs +35 -0
  53. data/sig/rooibos/router/forwards.rbs +34 -0
  54. data/sig/rooibos/router/guard.rbs +21 -0
  55. data/sig/rooibos/router/observe.rbs +20 -0
  56. data/sig/rooibos/router/observes.rbs +38 -0
  57. data/sig/rooibos/router/otherwise.rbs +22 -0
  58. data/sig/rooibos/router/otherwises.rbs +20 -0
  59. data/sig/rooibos/router/predicate.rbs +51 -0
  60. data/sig/rooibos/router/receive.rbs +20 -0
  61. data/sig/rooibos/router/receives.rbs +38 -0
  62. data/sig/rooibos/router/registry.rbs +24 -0
  63. data/sig/rooibos/router/route.rbs +46 -0
  64. data/sig/rooibos/router/router_update.rbs +33 -0
  65. data/sig/rooibos/router/routes.rbs +41 -0
  66. data/sig/rooibos/router/rule.rbs +36 -0
  67. data/sig/rooibos/router.rbs +216 -161
  68. data/sig/rooibos/runtime.rbs +0 -1
  69. data/sig/rooibos/test_helper.rbs +6 -0
  70. data/sig/rooibos/transition.rbs +33 -0
  71. data/sig/rooibos.rbs +0 -10
  72. metadata +144 -198
  73. data/.builds/ruby-3.2.yml +0 -55
  74. data/.builds/ruby-3.3.yml +0 -55
  75. data/.builds/ruby-3.4.yml +0 -55
  76. data/.builds/ruby-4.0.0.yml +0 -55
  77. data/.pre-commit-config.yaml +0 -16
  78. data/.rubocop.yml +0 -8
  79. data/AGENTS.md +0 -108
  80. data/CHANGELOG.md +0 -308
  81. data/README.md +0 -183
  82. data/README.rdoc +0 -374
  83. data/Rakefile +0 -16
  84. data/Steepfile +0 -13
  85. data/doc/best_practices/forms_and_validation.md +0 -20
  86. data/doc/best_practices/http_workflows.md +0 -20
  87. data/doc/best_practices/index.md +0 -26
  88. data/doc/best_practices/lists_and_tables.md +0 -20
  89. data/doc/best_practices/modal_dialogs.md +0 -20
  90. data/doc/best_practices/no_stateful_widgets.md +0 -184
  91. data/doc/best_practices/orchestration.md +0 -20
  92. data/doc/best_practices/streaming_data.md +0 -20
  93. data/doc/contributors/design/commands_and_outlets.md +0 -214
  94. data/doc/contributors/design/mvu_tea_implementations_research.md +0 -373
  95. data/doc/contributors/documentation_plan.md +0 -616
  96. data/doc/contributors/documentation_stub_audit.md +0 -112
  97. data/doc/contributors/documentation_style.md +0 -275
  98. data/doc/contributors/e2e_pty.md +0 -168
  99. data/doc/contributors/maybe_stateful_router.md +0 -56
  100. data/doc/contributors/specs/earliest_tutorial_steps_per_story.md +0 -70
  101. data/doc/contributors/specs/file_browser.md +0 -789
  102. data/doc/contributors/specs/file_browser_stories.md +0 -784
  103. data/doc/contributors/specs/tutorials_to_stories.rb +0 -167
  104. data/doc/contributors/todo/scrollbar.md +0 -118
  105. data/doc/contributors/tutorial_old/01_project_setup.md +0 -20
  106. data/doc/contributors/tutorial_old/02_hello_world.md +0 -24
  107. data/doc/contributors/tutorial_old/03_adding_state.md +0 -26
  108. data/doc/contributors/tutorial_old/06_organizing_your_code.md +0 -20
  109. data/doc/contributors/tutorial_old/07_your_first_command.md +0 -21
  110. data/doc/contributors/tutorial_old/08_the_preview_pane.md +0 -20
  111. data/doc/contributors/tutorial_old/09_loading_states.md +0 -20
  112. data/doc/contributors/tutorial_old/10_testing_your_app.md +0 -20
  113. data/doc/contributors/tutorial_old/11_polish_and_refine.md +0 -20
  114. data/doc/contributors/tutorial_old/12_going_further.md +0 -20
  115. data/doc/contributors/tutorial_old/index.md +0 -20
  116. data/doc/custom.css +0 -22
  117. data/doc/essentials/commands.md +0 -20
  118. data/doc/essentials/index.md +0 -31
  119. data/doc/essentials/messages.md +0 -21
  120. data/doc/essentials/models.md +0 -21
  121. data/doc/essentials/shortcuts.md +0 -19
  122. data/doc/essentials/the_elm_architecture.md +0 -24
  123. data/doc/essentials/the_runtime.md +0 -21
  124. data/doc/essentials/update_functions.md +0 -20
  125. data/doc/essentials/views.md +0 -22
  126. data/doc/getting_started/for_go_developers.md +0 -16
  127. data/doc/getting_started/for_python_developers.md +0 -16
  128. data/doc/getting_started/for_rails_developers.md +0 -17
  129. data/doc/getting_started/for_ratatui_ruby_developers.md +0 -17
  130. data/doc/getting_started/for_react_developers.md +0 -17
  131. data/doc/getting_started/index.md +0 -52
  132. data/doc/getting_started/install.md +0 -20
  133. data/doc/getting_started/quickstart.md +0 -20
  134. data/doc/getting_started/ruby_primer.md +0 -19
  135. data/doc/getting_started/why_rooibos.md +0 -20
  136. data/doc/images/verify_readme_usage.png +0 -0
  137. data/doc/images/widget_cmd_exec.png +0 -0
  138. data/doc/index.md +0 -93
  139. data/doc/scaling_up/async_patterns.md +0 -20
  140. data/doc/scaling_up/command_composition.md +0 -20
  141. data/doc/scaling_up/custom_commands.md +0 -21
  142. data/doc/scaling_up/fractal_architecture.md +0 -20
  143. data/doc/scaling_up/index.md +0 -30
  144. data/doc/scaling_up/message_routing.md +0 -20
  145. data/doc/scaling_up/ractor_safety.md +0 -20
  146. data/doc/scaling_up/testing.md +0 -21
  147. data/doc/troubleshooting/common_errors.md +0 -20
  148. data/doc/troubleshooting/debugging.md +0 -21
  149. data/doc/troubleshooting/index.md +0 -23
  150. data/doc/troubleshooting/performance.md +0 -20
  151. data/doc/tutorial/01_project_setup.md +0 -44
  152. data/doc/tutorial/02_hello_world.md +0 -45
  153. data/doc/tutorial/03_static_file_list.md +0 -44
  154. data/doc/tutorial/04_arrow_navigation.md +0 -47
  155. data/doc/tutorial/05_real_files.md +0 -45
  156. data/doc/tutorial/06_safe_refactoring.md +0 -21
  157. data/doc/tutorial/07_red_first_tdd.md +0 -26
  158. data/doc/tutorial/08_file_metadata.md +0 -42
  159. data/doc/tutorial/09_text_preview.md +0 -44
  160. data/doc/tutorial/10_directory_tree.md +0 -42
  161. data/doc/tutorial/11_pane_focus.md +0 -40
  162. data/doc/tutorial/12_sorting.md +0 -41
  163. data/doc/tutorial/13_filtering.md +0 -43
  164. data/doc/tutorial/14_toggle_hidden.md +0 -41
  165. data/doc/tutorial/15_text_input_widget.md +0 -43
  166. data/doc/tutorial/16_rename_files.md +0 -42
  167. data/doc/tutorial/17_confirmation_dialogs.md +0 -43
  168. data/doc/tutorial/18_progress_indicators.md +0 -43
  169. data/doc/tutorial/19_atomic_operations.md +0 -42
  170. data/doc/tutorial/20_external_editor.md +0 -42
  171. data/doc/tutorial/21_modal_overlays.md +0 -41
  172. data/doc/tutorial/22_error_handling.md +0 -43
  173. data/doc/tutorial/23_terminal_capabilities.md +0 -53
  174. data/doc/tutorial/24_mouse_events.md +0 -43
  175. data/doc/tutorial/25_resize_events.md +0 -43
  176. data/doc/tutorial/26_loading_states.md +0 -42
  177. data/doc/tutorial/27_performance.md +0 -43
  178. data/doc/tutorial/28_color_schemes.md +0 -47
  179. data/doc/tutorial/29_configuration.md +0 -124
  180. data/doc/tutorial/30_going_further.md +0 -17
  181. data/doc/tutorial/index.md +0 -17
  182. data/examples/app_fractal_dashboard/README.md +0 -60
  183. data/examples/app_fractal_dashboard/app.rb +0 -63
  184. data/examples/app_fractal_dashboard/dashboard/base.rb +0 -73
  185. data/examples/app_fractal_dashboard/dashboard/update_helpers.rb +0 -86
  186. data/examples/app_fractal_dashboard/dashboard/update_manual.rb +0 -87
  187. data/examples/app_fractal_dashboard/dashboard/update_router.rb +0 -43
  188. data/examples/app_fractal_dashboard/fragments/custom_shell_input.rb +0 -81
  189. data/examples/app_fractal_dashboard/fragments/custom_shell_modal.rb +0 -82
  190. data/examples/app_fractal_dashboard/fragments/custom_shell_output.rb +0 -90
  191. data/examples/app_fractal_dashboard/fragments/disk_usage.rb +0 -47
  192. data/examples/app_fractal_dashboard/fragments/network_panel.rb +0 -45
  193. data/examples/app_fractal_dashboard/fragments/ping.rb +0 -47
  194. data/examples/app_fractal_dashboard/fragments/stats_panel.rb +0 -45
  195. data/examples/app_fractal_dashboard/fragments/system_info.rb +0 -47
  196. data/examples/app_fractal_dashboard/fragments/uptime.rb +0 -47
  197. data/examples/tutorial/01/app.rb +0 -50
  198. data/examples/tutorial/02/app.rb +0 -64
  199. data/examples/tutorial/03/app.rb +0 -91
  200. data/examples/tutorial/06_safe_refactoring/app.rb +0 -124
  201. data/examples/verify_readme_usage/README.md +0 -54
  202. data/examples/verify_readme_usage/app.rb +0 -47
  203. data/examples/verify_website_first_app/app.rb +0 -85
  204. data/examples/verify_website_hello_mvu/app.rb +0 -31
  205. data/examples/widget_command_system/README.md +0 -70
  206. data/examples/widget_command_system/app.rb +0 -134
  207. data/generate_tutorial_stubs.rb +0 -126
  208. data/mise.toml +0 -8
  209. data/rbs_collection.lock.yaml +0 -108
  210. data/rbs_collection.yaml +0 -15
  211. data/tasks/example_viewer.html.erb +0 -172
  212. data/tasks/install.rake +0 -29
  213. data/tasks/resources/build.yml.erb +0 -55
  214. data/tasks/resources/index.html.erb +0 -44
  215. data/tasks/resources/rubies.yml +0 -7
  216. data/tasks/steep.rake +0 -11
  217. /data/{vendor/goodcop/base.yml → lib/rooibos/rubocop.yml} +0 -0
@@ -1,373 +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 Implementation Research
8
-
9
- ## Summary
10
-
11
- Research on Model-View-Update (MVU) / The Elm Architecture (TEA) implementations across 15+ frameworks and languages, focusing on initialization patterns.
12
-
13
- ## Complete List of MVU/TEA Implementations
14
-
15
- ### 1. **Elm** (Original - JavaScript/Web)
16
- - **Language**: Elm
17
- - **Domain**: Web applications
18
- - **Init Pattern**: `init : () -> (Model, Cmd Msg)`
19
- - Takes no arguments (unit type)
20
- - Returns tuple of `(Model, Cmd Msg)`
21
- - The `Model` is the initial state
22
- - The `Cmd Msg` is an initial command/effect
23
-
24
- ### 2. **Bubble Tea** (Go/TUI)
25
- - **Language**: Go
26
- - **Domain**: Terminal UIs
27
- - **Repository**: charmbracelet/bubbletea
28
- - **Init Pattern**: `func (m Model) Init() tea.Cmd`
29
- - Method on model struct
30
- - Returns initial command (`tea.Cmd`)
31
- - Model itself is initialized before `Init()` is called
32
- - Can return `nil` if no initial command needed
33
-
34
- ### 3. **TCA (The Composable Architecture)** (Swift)
35
- - **Language**: Swift
36
- - **Domain**: iOS/macOS apps
37
- - **Repository**: pointfreeco/swift-composable-architecture
38
- - **Init Pattern**: `Store(initialState: State, reducer:)`
39
- - Initial state passed to Store constructor
40
- - Reducers handle all state transitions
41
- - Heavy use of property wrappers for integration with SwiftUI
42
-
43
- ### 4. **Flutter Bloc** (Dart/Flutter)
44
- - **Language**: Dart
45
- - **Domain**: Mobile (iOS/Android), Web, Desktop
46
- - **Init Pattern**: Constructor-based
47
- ```dart
48
- class MyBloc extends Bloc<Event, State> {
49
- MyBloc() : super(InitialState()) { ... }
50
- }
51
- ```
52
- - Initial state passed to `super()` in constructor
53
- - Can dispatch events in constructor for async initialization
54
- - Often uses separate `Initial` state class
55
-
56
- ### 5. **Android MVI** (Kotlin/Android)
57
- - **Language**: Kotlin
58
- - **Domain**: Android apps
59
- - **Init Pattern**: ViewModel with StateFlow
60
- ```kotlin
61
- private val _state = MutableStateFlow(UiState.initial())
62
- val state: StateFlow<UiState> = _state
63
- ```
64
- - Initial state typically from a factory method or default constructor
65
- - ViewModel initializes `StateFlow` with initial state
66
- - Intents sent to ViewModel via Channel or SharedFlow
67
-
68
- ### 6. **Redux** (JavaScript/React)
69
- - **Language**: JavaScript/TypeScript
70
- - **Domain**: Web (primarily React, but library-agnostic)
71
- - **Init Pattern**: Reducer default state
72
- ```javascript
73
- // Redux Toolkit
74
- const slice = createSlice({
75
- name: 'counter',
76
- initialState: { value: 0 },
77
- reducers: { ... }
78
- })
79
- ```
80
- - Initial state defined in slice or as reducer default parameter
81
- - Not strictly MVU (no built-in effects), but similar
82
- - Redux Thunk/Saga add effect handling
83
-
84
- ### 7. **Iced** (Rust/GUI)
85
- - **Language**: Rust
86
- - **Domain**: Cross-platform GUI
87
- - **Init Pattern**: `Application::new()` trait method
88
- ```rust
89
- impl Application for MyApp {
90
- fn new(_flags: Flags) -> (Self, Command<Message>) {
91
- (initial_state, initial_command)
92
- }
93
- }
94
- ```
95
- - Returns tuple `(State, Command)`
96
- - Accepts `flags` parameter for runtime context
97
- - **NOTABLE**: Flags pattern allows parameterization!
98
-
99
- ### 8. **Elmish** (F#/Fable)
100
- - **Language**: F#
101
- - **Domain**: Web (compiles to JavaScript via Fable)
102
- - **Init Pattern**: `init : unit -> Model * Cmd<Msg>`
103
- - F# implementation of Elm Architecture
104
- - Returns tuple of Model and Cmd
105
- - Often used with React for rendering
106
-
107
- ### 9. **Hyperapp** (JavaScript/Web)
108
- - **Language**: JavaScript
109
- - **Domain**: Web
110
- - **Init Pattern**:
111
- ```javascript
112
- app({
113
- init: initialState, // or [state, ...effects]
114
- view: ...,
115
- node: ...
116
- })
117
- ```
118
- - Can be plain object for state only
119
- - Can be array `[state, ...effects]` to run effects on startup
120
- - Very lightweight (1KB)
121
-
122
- ### 10. **Meiosis** (JavaScript/Web)
123
- - **Language**: JavaScript
124
- - **Domain**: Web (view-library agnostic)
125
- - **Init Pattern**:
126
- ```javascript
127
- meiosis.run({
128
- initialModel: { ... },
129
- renderer: ...,
130
- rootComponent: ...
131
- })
132
- ```
133
- - Emphasizes plain functions and objects
134
- - Works with Flyd or Mithril Stream
135
- - Very flexible, minimal abstraction
136
-
137
- ### 11. **SAM Pattern** (JavaScript)
138
- - **Language**: JavaScript
139
- - **Domain**: Web
140
- - **Init Pattern**: State predicate initializes state machine
141
- - Based on TLA+ (Temporal Logic of Actions)
142
- - Model holds data, State is representation
143
- - Init is a state predicate for initial conditions
144
-
145
- ### 12. **Fabulous** (F#/MAUI)
146
- - **Language**: F#
147
- - **Domain**: Mobile (via .NET MAUI)
148
- - **Init Pattern**: MVU pattern for F#
149
- - Similar to Elmish
150
- - `init : unit -> Model * Cmd<Msg>`
151
-
152
- ### 13. **BlazorMVU** (.NET/Blazor)
153
- - **Language**: C#
154
- - **Domain**: Web (Blazor)
155
- - **Init Pattern**: Inspired by Elm and F# MVU
156
- - Brings MVU to C# ecosystem
157
- - Initial state typically in component initialization
158
-
159
- ### 14. **MauiReactor** (.NET/MAUI)
160
- - **Language**: C#
161
- - **Domain**: Cross-platform mobile/desktop
162
- - **Init Pattern**: MVU for .NET MAUI
163
- - State-driven UI updates
164
- - Functional approach to MAUI development
165
-
166
- ### 15. **MVUX** (.NET)
167
- - **Language**: C#
168
- - **Domain**: Cross-platform (Uno Platform)
169
- - **Init Pattern**: Model-View-Update eXtended
170
- - Extends MVU with data binding
171
- - Immutable models
172
- - Feed-based reactive updates
173
-
174
- ### 16. **ngx-mvu (Angular MVU)** (TypeScript/Angular)
175
- - **Language**: TypeScript
176
- - **Domain**: Web (Angular)
177
- - **Init Pattern**: Applies Elm Architecture to Angular
178
- - Structured approach to Angular apps
179
- - Similar update/model/view separation
180
-
181
- ## Initialization Patterns Analysis
182
-
183
- ### Pattern 1: Tuple Return (Most Common)
184
- **Frameworks**: Elm, Bubble Tea, Iced, Elmish, Hyperapp (array variant)
185
-
186
- ```
187
- init : Flags -> (Model, Command)
188
- ```
189
-
190
- **Characteristics**:
191
- - Returns both initial state AND initial effect/command
192
- - Highly composable (can combine child inits)
193
- - **Flags/context parameter** for runtime initialization
194
-
195
- **Example (Iced - Rust)**:
196
- ```rust
197
- fn new(flags: Flags) -> (MyApp, Command<Message>) {
198
- let initial_state = MyApp { count: flags.initial_count };
199
- let initial_cmd = Command::none();
200
- (initial_state, initial_cmd)
201
- }
202
- ```
203
-
204
- ### Pattern 2: Method on Model
205
- **Frameworks**: Bubble Tea
206
-
207
- ```go
208
- func (m Model) Init() tea.Cmd {
209
- return fetchDataCmd()
210
- }
211
- ```
212
-
213
- **Characteristics**:
214
- - Model constructed first, then `Init()` called
215
- - Only returns command, state already set
216
- - Less composable (harder to combine states)
217
-
218
- ### Pattern 3: Constructor/Factory
219
- **Frameworks**: Flutter Bloc, Android MVI, Redux, TCA
220
-
221
- ```dart
222
- MyBloc() : super(InitialState()) {
223
- // optional: dispatch initial events
224
- }
225
- ```
226
-
227
- **Characteristics**:
228
- - Initial state in constructor parameter
229
- - Effects/commands dispatched separately (if at all)
230
- - OOP-style initialization
231
-
232
- ### Pattern 4: Property/Config Object
233
- **Frameworks**: Hyperapp, Meiosis
234
-
235
- ```javascript
236
- app({
237
- init: { count: 0 }, // or [state, effect1, effect2]
238
- view: ...,
239
- update: ...
240
- })
241
- ```
242
-
243
- **Characteristics**:
244
- - Declarative initialization
245
- - Can combine state + effects in array format
246
- - Very flexible
247
-
248
- ## Key Findings for Rooibos
249
-
250
- ### ✅ **Flags/Props Pattern is Proven**
251
- **Iced (Rust)** explicitly uses a `flags` parameter in `new()`:
252
- ```rust
253
- fn new(flags: Flags) -> (State, Command) { ... }
254
- ```
255
-
256
- This directly supports your proposal for:
257
- - Root fragments: `Init.(argv:, env:)`
258
- - Child fragments: `Init.(theme: :dark, debug: true)`
259
-
260
- ### ✅ **Tuple Return (Model, Command) is Standard**
261
- Almost all functional MVU implementations return `(state, command)`:
262
- - Elm: `(Model, Cmd Msg)`
263
- - Iced: `(State, Command<Message>)`
264
- - Elmish: `(Model, Cmd<Msg>)`
265
- - Hyperapp: `[state, ...effects]` (array variant)
266
-
267
- Your proposal aligns perfectly: `Init = ->(flags) { [model, command] }`
268
-
269
- ### ✅ **DWIM Return Values**
270
- Hyperapp allows both:
271
- - `init: state` (no command)
272
- - `init: [state, cmd1, cmd2]` (with effects)
273
-
274
- This supports your DWIM proposal:
275
- ```ruby
276
- Init = -> { Model.new(...) } # Just model
277
- Init = -> { [Model.new(...), some_cmd] } # With command
278
- ```
279
-
280
- ### ⚠️ **Composition is Critical**
281
- The OOP frameworks (Bloc, MVI, TCA) struggle with composition:
282
- - Hard to combine child states in parent's init
283
- - Usually rely on dependency injection or external configuration
284
-
285
- Functional MVU frameworks excel here:
286
- ```elm
287
- -- Elm example
288
- init flags =
289
- let
290
- (childModel1, childCmd1) = Child1.init flags.theme
291
- (childModel2, childCmd2) = Child2.init flags.debug
292
- in
293
- ( { child1 = childModel1, child2 = childModel2 }
294
- , Cmd.batch [Cmd.map Child1Msg childCmd1, Cmd.map Child2Msg childCmd2]
295
- )
296
- ```
297
-
298
- Your proposal enables this exact pattern in Ruby!
299
-
300
- ### 📊 **No Framework Uses Static Constants**
301
- **CRITICAL**: Not a single MVU framework uses a static constant for initial state in the way we currently do with `INITIAL` or `MODEL`.
302
-
303
- All use one of:
304
- 1. **Callable with flags** (Elm, Iced, Elmish)
305
- 2 **Method on instance** (Bubble Tea)
306
- 3. **Constructor parameter** (Bloc, MVI, TCA)
307
- 4. **Config property** (Hyperapp, Meiosis)
308
-
309
- The static constant pattern appears to be **unique to our current implementation** and is unsupported by the broader MVU ecosystem.
310
-
311
- ## Recommendations
312
-
313
- ### 1. **Adopt `Init` Callable with Flags**
314
- Most aligned with functional MVU tradition (Elm, Iced, Elmish).
315
-
316
- ```ruby
317
- Init = ->(theme: :dark, env: {}) do
318
- [Model.new(theme: theme), nil]
319
- end
320
- ```
321
-
322
- ### 2. **Support Tuple Return**
323
- Follow Elm/Iced pattern: `[model, command]`
324
-
325
- ### 3. **Enable DWIM**
326
- Like Hyperapp, support both:
327
- - `Model.new(...)` (no command)
328
- - `[Model.new(...), cmd]` (with command)
329
-
330
- ### 4. **Fractal Composition Example**
331
- From Elm/Iced patterns:
332
-
333
- ```ruby
334
-
335
- module Dashboard
336
- Init = ->(theme: :dark) do
337
- stats_model, stats_cmd = StatsPanel::Init.(theme: theme)
338
- network_model, network_cmd = NetworkPanel::Init.(theme: theme)
339
-
340
- model = Model.new(stats: stats_model, network: network_model)
341
- command = Command.batch(
342
- Rooibos.route(stats_cmd, :stats),
343
- Rooibos.route(network_cmd, :network)
344
- )
345
-
346
- [model, command]
347
- end
348
- end
349
- ```
350
-
351
- ### 5. **Runtime Integration**
352
- From Iced/Elm patterns:
353
-
354
- ```ruby
355
- Rooibos.run(
356
- fragment: App,
357
- argv: ARGV,
358
- env: ENV
359
- )
360
- # Internally calls: model, cmd = App::Init.(argv: ARGV, env: ENV)
361
- ```
362
-
363
- ## Conclusion
364
-
365
- Your `Init` callable proposal is **strongly validated** by existing MVU/TEA implementations:
366
-
367
- 1. ✅ Flags/props for parameterization (Iced, Elm)
368
- 2. ✅ Tuple return of `(model, command)` (Elm, Iced, Elmish)
369
- 3. ✅ DWIM flexibility (Hyperapp)
370
- 4. ✅ Composition-first (all functional MVU)
371
- 5. ❌ Static constants are **not used** by any major framework
372
-
373
- The pattern is battle-tested across **15+ implementations** in production systems ranging from web apps to mobile to desktop GUIs.