milktea 0.1.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.
data/README.md ADDED
@@ -0,0 +1,382 @@
1
+ # Milktea
2
+
3
+ [![Gem Version](https://badge.fury.io/rb/milktea.svg)](https://badge.fury.io/rb/milktea)
4
+ [![Ruby](https://github.com/elct9620/milktea/workflows/Ruby/badge.svg)](https://github.com/elct9620/milktea/actions)
5
+
6
+ A Terminal User Interface (TUI) framework for Ruby, inspired by [Bubble Tea](https://github.com/charmbracelet/bubbletea) from Go. Milktea brings the power of the Elm Architecture to Ruby, enabling you to build rich, interactive command-line applications with composable components and reactive state management.
7
+
8
+ ## Features
9
+
10
+ - 🏗️ **Elm Architecture**: Immutable state management with predictable message flow
11
+ - 📦 **Container Layouts**: Flexbox-style layouts for terminal interfaces
12
+ - 🔄 **Hot Reloading**: Instant feedback during development (similar to web frameworks)
13
+ - 📱 **Responsive Design**: Automatic adaptation to terminal resize events
14
+ - 🧩 **Composable Components**: Build complex UIs from simple, reusable models
15
+ - 🎨 **Rich Terminal Support**: Leverage TTY gems for advanced terminal features
16
+
17
+ ## Installation
18
+
19
+ Add Milktea to your application's Gemfile:
20
+
21
+ ```ruby
22
+ gem 'milktea'
23
+ ```
24
+
25
+ Or install directly:
26
+
27
+ ```bash
28
+ gem install milktea
29
+ ```
30
+
31
+ For development versions:
32
+
33
+ ```ruby
34
+ gem 'milktea', git: 'https://github.com/elct9620/milktea'
35
+ ```
36
+
37
+ ## Quick Start
38
+
39
+ Here's a simple "Hello World" application:
40
+
41
+ ```ruby
42
+ require 'milktea'
43
+
44
+ class HelloModel < Milktea::Model
45
+ def view
46
+ "Hello, #{state[:name]}! Count: #{state[:count]}"
47
+ end
48
+
49
+ def update(message)
50
+ case message
51
+ when Milktea::Message::KeyPress
52
+ case message.value
53
+ when "+"
54
+ [with(count: state[:count] + 1), Milktea::Message::None.new]
55
+ when "q"
56
+ [self, Milktea::Message::Exit.new]
57
+ else
58
+ [self, Milktea::Message::None.new]
59
+ end
60
+ else
61
+ [self, Milktea::Message::None.new]
62
+ end
63
+ end
64
+
65
+ private
66
+
67
+ def default_state
68
+ { name: "World", count: 0 }
69
+ end
70
+ end
71
+
72
+ # Simple approach using Application class
73
+ class MyApp < Milktea::Application
74
+ root "HelloModel"
75
+ end
76
+
77
+ MyApp.boot
78
+ ```
79
+
80
+ ## Core Concepts
81
+
82
+ ### Models & Elm Architecture
83
+
84
+ Milktea follows the Elm Architecture pattern with three core concepts:
85
+
86
+ - **Model**: Immutable state container
87
+ - **View**: Pure function that renders state to string
88
+ - **Update**: Handles messages and returns new state + side effects
89
+
90
+ ```ruby
91
+ class CounterModel < Milktea::Model
92
+ def view
93
+ "Count: #{state[:count]} (Press +/- to change, q to quit)"
94
+ end
95
+
96
+ def update(message)
97
+ case message
98
+ when Milktea::Message::KeyPress
99
+ handle_keypress(message)
100
+ when Milktea::Message::Resize
101
+ # Rebuild model with fresh class for new screen dimensions
102
+ [with, Milktea::Message::None.new]
103
+ else
104
+ [self, Milktea::Message::None.new]
105
+ end
106
+ end
107
+
108
+ private
109
+
110
+ def default_state
111
+ { count: 0 }
112
+ end
113
+
114
+ def handle_keypress(message)
115
+ case message.value
116
+ when "+"
117
+ [with(count: state[:count] + 1), Milktea::Message::None.new]
118
+ when "-"
119
+ [with(count: state[:count] - 1), Milktea::Message::None.new]
120
+ when "q"
121
+ [self, Milktea::Message::Exit.new]
122
+ else
123
+ [self, Milktea::Message::None.new]
124
+ end
125
+ end
126
+ end
127
+ ```
128
+
129
+ ### Container Layout System
130
+
131
+ Milktea provides a flexbox-inspired layout system for building complex terminal interfaces:
132
+
133
+ ```ruby
134
+ class AppLayout < Milktea::Container
135
+ direction :column
136
+ child HeaderModel, flex: 1
137
+ child ContentModel, flex: 3
138
+ child FooterModel, flex: 1
139
+ end
140
+
141
+ class SidebarLayout < Milktea::Container
142
+ direction :row
143
+ child SidebarModel, flex: 1
144
+ child MainContentModel, flex: 3
145
+ end
146
+ ```
147
+
148
+ #### Key Container Features:
149
+
150
+ - **Direction**: `:row` or `:column` (default: `:column`)
151
+ - **Flex Properties**: Control size ratios between children
152
+ - **State Mapping**: Pass specific state portions to children
153
+ - **Bounds Calculation**: Automatic layout calculation and propagation
154
+
155
+ ```ruby
156
+ class AdvancedContainer < Milktea::Container
157
+ direction :row
158
+
159
+ # Pass specific state to children with state mappers
160
+ child SidebarModel, ->(state) { { items: state[:sidebar_items] } }, flex: 1
161
+ child ContentModel, ->(state) { state.slice(:title, :content) }, flex: 2
162
+ child InfoModel, flex: 1
163
+ end
164
+ ```
165
+
166
+ ### Hot Reloading (Development Feature)
167
+
168
+ Milktea supports hot reloading for rapid development iteration:
169
+
170
+ ```ruby
171
+ # Configure hot reloading
172
+ Milktea.configure do |config|
173
+ config.autoload_dirs = ["app/models", "lib/components"]
174
+ config.hot_reloading = true
175
+ end
176
+
177
+ class DevelopmentModel < Milktea::Model
178
+ def update(message)
179
+ case message
180
+ when Milktea::Message::Reload
181
+ # Hot reload detected - rebuild with fresh class
182
+ [with, Milktea::Message::None.new]
183
+ # ... other message handling
184
+ end
185
+ end
186
+ end
187
+ ```
188
+
189
+ When files change, Milktea automatically detects the changes and sends `Message::Reload` events. Simply handle this message by rebuilding your model with `[with, Milktea::Message::None.new]` to pick up the latest code changes.
190
+
191
+ ### Terminal Resize Handling
192
+
193
+ Milktea automatically detects terminal resize events and provides a simple pattern for responsive layouts:
194
+
195
+ ```ruby
196
+ class ResponsiveApp < Milktea::Container
197
+ direction :column
198
+ child HeaderModel, flex: 1
199
+ child DynamicContentModel, flex: 4
200
+
201
+ def update(message)
202
+ case message
203
+ when Milktea::Message::Resize
204
+ # Only root model needs resize handling
205
+ # All children automatically recalculate bounds
206
+ [with, Milktea::Message::None.new]
207
+ when Milktea::Message::KeyPress
208
+ handle_keypress(message)
209
+ else
210
+ [self, Milktea::Message::None.new]
211
+ end
212
+ end
213
+ end
214
+ ```
215
+
216
+ #### Resize Handling Key Points:
217
+
218
+ - **Root-Level Only**: Only the root model needs to handle `Message::Resize`
219
+ - **Automatic Cascading**: Child components automatically adapt to new dimensions
220
+ - **Bounds Recalculation**: Container layouts automatically recalculate flex distributions
221
+ - **Screen Methods**: Use `screen_width`, `screen_height`, `screen_size` for responsive logic
222
+
223
+ ## Examples
224
+
225
+ Explore the `examples/` directory for comprehensive demonstrations:
226
+
227
+ - **[Container Layout](examples/container_layout.rb)**: Flexbox-style layouts with resize support
228
+ - **[Hot Reload Demo](examples/hot_reload_demo.rb)**: Development workflow with instant updates
229
+
230
+ Run examples:
231
+
232
+ ```bash
233
+ ruby examples/container_layout.rb
234
+ ruby examples/hot_reload_demo.rb
235
+ ```
236
+
237
+ ## Advanced Features
238
+
239
+ ### Dynamic Child Resolution
240
+
241
+ Use symbols to dynamically resolve child components:
242
+
243
+ ```ruby
244
+ class DynamicContainer < Milktea::Container
245
+ direction :column
246
+ child :header_component, flex: 1 # Calls header_component method
247
+ child ContentModel, flex: 3 # Direct class reference
248
+
249
+ private
250
+
251
+ def header_component
252
+ state[:show_advanced] ? AdvancedHeader : SimpleHeader
253
+ end
254
+ end
255
+ ```
256
+
257
+ ### Custom Message Handling
258
+
259
+ Create custom messages for complex interactions:
260
+
261
+ ```ruby
262
+ # Define custom message
263
+ CustomAction = Data.define(:action_type, :payload)
264
+
265
+ class CustomModel < Milktea::Model
266
+ def update(message)
267
+ case message
268
+ when CustomAction
269
+ handle_custom_action(message)
270
+ # ... standard message handling
271
+ end
272
+ end
273
+
274
+ private
275
+
276
+ def handle_custom_action(message)
277
+ case message.action_type
278
+ when :save
279
+ # Handle save action
280
+ [with(saved: true), Milktea::Message::None.new]
281
+ when :load
282
+ # Handle load action
283
+ [with(data: message.payload), Milktea::Message::None.new]
284
+ end
285
+ end
286
+ end
287
+ ```
288
+
289
+ ### Application vs Manual Setup
290
+
291
+ Choose between high-level Application class or manual setup:
292
+
293
+ ```ruby
294
+ # High-level Application approach (recommended)
295
+ class MyApp < Milktea::Application
296
+ root "MainModel"
297
+ end
298
+
299
+ MyApp.boot
300
+
301
+ # Manual setup (advanced)
302
+ config = Milktea.configure do |c|
303
+ c.autoload_dirs = ["app/models"]
304
+ c.hot_reloading = true
305
+ end
306
+
307
+ loader = Milktea::Loader.new(config)
308
+ loader.hot_reload if config.hot_reloading?
309
+
310
+ model = MainModel.new
311
+ program = Milktea::Program.new(model, config: config)
312
+ program.run
313
+ ```
314
+
315
+ ## API Reference
316
+
317
+ ### Core Classes
318
+
319
+ - **`Milktea::Model`**: Base class for all UI components
320
+ - **`Milktea::Container`**: Layout container with flexbox-style properties
321
+ - **`Milktea::Application`**: High-level application wrapper
322
+ - **`Milktea::Program`**: Main application runtime
323
+ - **`Milktea::Message`**: Standard message types (KeyPress, Exit, Resize, Reload)
324
+
325
+ ### Message System
326
+
327
+ - **`Message::KeyPress`**: Keyboard input events
328
+ - **`Message::Exit`**: Application termination
329
+ - **`Message::Resize`**: Terminal size changes
330
+ - **`Message::Reload`**: Hot reload events
331
+ - **`Message::None`**: No-operation message
332
+
333
+ For detailed API documentation, see the [documentation website](https://rubydoc.info/gems/milktea).
334
+
335
+ ## Development
336
+
337
+ After checking out the repo:
338
+
339
+ ```bash
340
+ bin/setup # Install dependencies
341
+ bundle exec rake spec # Run tests
342
+ bundle exec rake rubocop # Check code style
343
+ bundle exec rake # Run all checks
344
+ bin/console # Interactive prompt
345
+ ```
346
+
347
+ ### Testing
348
+
349
+ Milktea uses RSpec for testing. Run specific tests:
350
+
351
+ ```bash
352
+ bundle exec rspec spec/milktea/model_spec.rb
353
+ bundle exec rspec spec/milktea/container_spec.rb:42 # Specific line
354
+ ```
355
+
356
+ ### Code Quality
357
+
358
+ The project uses RuboCop for code formatting:
359
+
360
+ ```bash
361
+ bundle exec rake rubocop:autocorrect # Fix auto-correctable issues
362
+ ```
363
+
364
+ ## Contributing
365
+
366
+ Bug reports and pull requests are welcome on GitHub at https://github.com/elct9620/milktea.
367
+
368
+ 1. Fork the repository
369
+ 2. Create your feature branch (`git checkout -b feature/my-new-feature`)
370
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
371
+ 4. Push to the branch (`git push origin feature/my-new-feature`)
372
+ 5. Create a Pull Request
373
+
374
+ ## License
375
+
376
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
377
+
378
+ ## Acknowledgments
379
+
380
+ - Inspired by [Bubble Tea](https://github.com/charmbracelet/bubbletea) - Go TUI framework
381
+ - Built on the [TTY toolkit](https://ttytoolkit.org/) ecosystem
382
+ - Follows [Elm Architecture](https://guide.elm-lang.org/architecture/) principles
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rspec/core/rake_task"
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ require "rubocop/rake_task"
9
+
10
+ RuboCop::RakeTask.new
11
+
12
+ task default: %i[spec rubocop]
@@ -0,0 +1,119 @@
1
+ # Development Log - 2025-07-03
2
+
3
+ ## What's New
4
+
5
+ #### Renderer Abstraction for Clean Separation of Concerns
6
+
7
+ The Milktea framework now features a dedicated `Renderer` class that handles all terminal user interface rendering operations. This new abstraction brings several benefits to TUI developers:
8
+
9
+ - **Screen Management**: Automatic screen clearing and cursor positioning using the `tty-cursor` gem ensures clean rendering without visual artifacts
10
+ - **Output Flexibility**: Support for custom output streams allows easy testing with `StringIO` and potential future support for different output formats
11
+ - **Lifecycle Methods**: Clear `setup_screen()` and `restore_screen()` methods handle terminal state management, ensuring proper cleanup when programs exit
12
+ - **Clean API**: Simple `render(model)` method that takes care of all rendering complexities internally
13
+
14
+ This separation allows developers to focus on their application logic while the renderer handles the intricacies of terminal manipulation.
15
+
16
+ #### Full Keyboard Event Handling
17
+
18
+ Interactive TUI applications now have access to comprehensive keyboard input through integration with `TTY::Reader`. The new `KeyPress` message type provides rich event data:
19
+
20
+ - **Complete Key Information**: Access to both raw key values and character representations
21
+ - **Modifier Key Support**: Built-in tracking of Ctrl, Alt, and Shift states enables complex keyboard shortcuts
22
+ - **Non-blocking Input**: Keyboard events are read without blocking the main event loop, maintaining responsive applications
23
+ - **Graceful Interrupt Handling**: Ctrl+C is properly handled through TTY::Reader's error mode, preventing abrupt terminations
24
+
25
+ This enhancement empowers developers to create sophisticated keyboard-driven interfaces with minimal effort.
26
+
27
+ #### Counter Example Application
28
+
29
+ A new example demonstrates best practices for building Milktea applications. The counter showcases:
30
+
31
+ - **State Management**: Proper use of immutable state updates through the `Model#with` method
32
+ - **User Interaction**: Intuitive keyboard controls (+/k for increment, -/j for decrement, r for reset, q for quit)
33
+ - **Clean UI**: Clear instructions and visual feedback demonstrate effective TUI design
34
+ - **Architecture Patterns**: Real-world application of the Elm Architecture within the Ruby ecosystem
35
+
36
+ This example serves as both a learning resource and a template for new TUI applications.
37
+
38
+ ## What's Fixed
39
+
40
+ #### Screen Clearing and Rendering Artifacts
41
+
42
+ **Problem**: Previous renders would leave visual artifacts on screen, creating a messy user experience as old content remained visible beneath new renders.
43
+
44
+ **Solution**: The new Renderer class now properly clears the entire screen and resets the cursor to position (0,0) before each render cycle. This ensures each frame starts with a clean slate, eliminating any overlap or ghosting effects from previous renders.
45
+
46
+ **Impact**: TUI applications now provide a clean, professional appearance with smooth visual updates that don't leave traces of previous states.
47
+
48
+ #### Hardcoded Exit Key Limitations
49
+
50
+ **Problem**: The framework previously hardcoded certain keys for exiting applications, limiting developer control over keyboard interactions and preventing custom exit strategies.
51
+
52
+ **Solution**: Removed all hardcoded exit keys from the Program class. Models now have complete control over keyboard event handling, including when and how to terminate the application.
53
+
54
+ **Impact**: Developers can now implement custom exit confirmations, save prompts, or completely different key bindings for application termination, providing full control over the user experience.
55
+
56
+ ## Design Decisions
57
+
58
+ #### Renderer as a Separate Component
59
+
60
+ **Context**: The Program class was becoming complex, handling both event loop management and rendering responsibilities. This violated the single responsibility principle and made testing difficult.
61
+
62
+ **Choice**: Extract all rendering logic into a dedicated Renderer class that can be injected into the Program.
63
+
64
+ **Rationale**: This separation provides multiple benefits:
65
+ - Easier unit testing through dependency injection
66
+ - Potential for alternative renderer implementations (e.g., web-based output)
67
+ - Cleaner Program class focused solely on event loop management
68
+ - Better adherence to SOLID principles
69
+
70
+ This decision aligns with the framework's clean architecture approach and makes the codebase more maintainable and extensible.
71
+
72
+ #### Enhanced Testing Philosophy
73
+
74
+ **Context**: The existing RSpec tests were using various patterns, some of which tested implementation details rather than behavior.
75
+
76
+ **Choice**: Established comprehensive testing guidelines emphasizing behavioral testing over implementation testing.
77
+
78
+ **Rationale**: The new guidelines promote:
79
+ - Using spy patterns for cleaner delegation tests
80
+ - Avoiding private instance variable testing
81
+ - Leveraging RSpec's built-in matchers like `output`
82
+ - Focusing on public API behavior
83
+
84
+ These practices lead to more maintainable tests that don't break with internal refactoring, while still ensuring correctness.
85
+
86
+ #### Non-blocking Keyboard Input
87
+
88
+ **Context**: TUI applications need to remain responsive while waiting for user input, but blocking I/O operations can freeze the interface.
89
+
90
+ **Choice**: Implement keyboard reading using TTY::Reader's non-blocking `read_keypress` method within the main event loop.
91
+
92
+ **Rationale**: This approach ensures:
93
+ - The event loop continues processing messages and timers while waiting for input
94
+ - Applications can implement animations or real-time updates
95
+ - Better user experience with responsive interfaces
96
+ - Alignment with modern event-driven programming patterns
97
+
98
+ ## Impact
99
+
100
+ These changes significantly enhance the Milktea framework's usability and architecture. Ruby developers building TUI applications now have:
101
+
102
+ - **Better Separation of Concerns**: Clear boundaries between rendering, input handling, and application logic
103
+ - **More Control**: Full ownership of keyboard handling and application behavior
104
+ - **Improved Testing**: Cleaner patterns for writing maintainable test suites
105
+ - **Professional Output**: Artifact-free rendering for polished user interfaces
106
+ - **Learning Resources**: Practical examples demonstrating framework best practices
107
+
108
+ The framework now provides a more solid foundation for building sophisticated terminal applications while maintaining the simplicity and elegance of the Elm Architecture.
109
+
110
+ ## Files Modified
111
+
112
+ - `lib/milktea/renderer.rb` - New Renderer class for TUI rendering
113
+ - `lib/milktea/program.rb` - Refactored to use Renderer and handle keyboard events
114
+ - `lib/milktea/message.rb` - Added KeyPress message type
115
+ - `examples/counter.rb` - New counter example application
116
+ - `examples/simple.rb` - Updated with keyboard interaction
117
+ - `spec/milktea/renderer_spec.rb` - Tests for new Renderer class
118
+ - `spec/milktea/program_spec.rb` - Updated tests for refactored Program
119
+ - `CLAUDE.md` - Enhanced RSpec testing guidelines
@@ -0,0 +1,129 @@
1
+ # Development Log - 2025-07-04 (Session 2)
2
+
3
+ ## What's New
4
+
5
+ #### Working Hot Reloading System with Production-Ready Example
6
+ Successfully implemented a fully functional hot reloading system for Milktea applications, complete with a comprehensive demonstration example. The system enables developers to modify TUI components in real-time while applications are running, dramatically improving development velocity and iteration speed.
7
+
8
+ Key features include:
9
+ - **Live code reloading**: Edit model files and see changes immediately without restarting
10
+ - **Automatic class refresh**: Uses `Kernel.const_get` to ensure fresh class definitions are loaded
11
+ - **Graceful degradation**: Works with or without the Listen gem for file watching
12
+ - **Interactive demo**: Complete example showing parent-child model reloading with clear instructions
13
+
14
+ #### Independent Loader Architecture
15
+ Redesigned the Loader system to be completely self-contained, eliminating problematic circular dependencies that were preventing proper Model loading. The new architecture separates concerns cleanly and provides a simpler API for developers.
16
+
17
+ The Loader now:
18
+ - Takes a config object and extracts what it needs internally
19
+ - Automatically handles hot reloading based on configuration
20
+ - Operates independently from the core framework components
21
+ - Provides a single `start` method that handles all initialization
22
+
23
+ #### Comprehensive Hot Reloading Documentation
24
+ Added extensive documentation to CLAUDE.md covering all critical aspects of hot reloading setup and troubleshooting. This includes configuration requirements, implementation gotchas, and step-by-step testing procedures that will be essential for future development.
25
+
26
+ ## What's Fixed
27
+
28
+ #### Circular Dependency Resolution
29
+ Resolved critical circular dependencies in the original Loader design where Config needed Runtime to create Loader, but Loader needed Config's runtime and app_path. This was causing Model loading failures and tight coupling between components.
30
+
31
+ **Root cause**: The original design tried to inject dependencies through Config, creating a circular reference loop.
32
+
33
+ **Solution**: Made Loader completely independent by having it extract needed values from a passed config object, eliminating the circular dependency chain.
34
+
35
+ #### Hot Reloading Class Reference Issues
36
+ Fixed fundamental issue where hot reloading wasn't working because `self.class.new` was returning cached/stale class objects instead of freshly reloaded classes.
37
+
38
+ **Root cause**: Ruby's `self.class` returns the class object that was loaded when the instance was created, not the current definition.
39
+
40
+ **Solution**: Replaced `self.class.new` with `Kernel.const_get(self.class.name).new` in the Model#with method to ensure fresh class definitions are used.
41
+
42
+ #### Zeitwerk Configuration for Examples
43
+ Corrected app_dir configuration for examples directory to work with Zeitwerk's autoloading requirements. Examples lack Gemfile and other project structure, requiring special path handling.
44
+
45
+ **Impact**: Hot reloading now works correctly for standalone examples, demonstrating the system's flexibility across different project structures.
46
+
47
+ #### Message::Reload Event Handling
48
+ Implemented proper reload event handling in models using the `with` method to rebuild instances with fresh class definitions. This ensures the entire model tree is updated when code changes are detected.
49
+
50
+ ## Design Decisions
51
+
52
+ #### Loader Independence from Framework Core
53
+ **Context**: The original design embedded Loader configuration within the Config class, creating tight coupling and circular dependencies.
54
+
55
+ **Decision**: Make Loader a completely independent utility that takes a config object and operates autonomously.
56
+
57
+ **Rationale**: This design provides several key benefits:
58
+ - Eliminates circular dependencies that were causing loading failures
59
+ - Separates development tooling from core framework functionality
60
+ - Simplifies the API for users (single `loader.start()` call)
61
+ - Allows Program to focus solely on TUI concerns
62
+ - Makes testing easier with clear dependency boundaries
63
+
64
+ This decision reinforces the Clean Architecture principle of dependency inversion, where high-level modules (core framework) don't depend on low-level modules (development tools).
65
+
66
+ #### Kernel.const_get for Dynamic Class Loading
67
+ **Context**: Hot reloading requires getting fresh class definitions after code changes, but `self.class` returns cached objects.
68
+
69
+ **Decision**: Use `Kernel.const_get(self.class.name).new(merged_state)` instead of `self.class.new(merged_state)` in Model#with.
70
+
71
+ **Rationale**: This approach ensures that:
72
+ - Fresh class definitions are used after Zeitwerk reloads classes
73
+ - The hot reloading system works reliably across all model types
74
+ - No additional complexity is introduced to the Model API
75
+ - The change is backward compatible and doesn't affect normal operation
76
+
77
+ The trade-off is slightly more dynamic code, but this is isolated to the development scenario and provides essential functionality.
78
+
79
+ #### App Directory Configuration Strategy
80
+ **Context**: Zeitwerk requires specific directory structures, and examples have different project layouts than full applications.
81
+
82
+ **Decision**: Require app_dir to point directly to the models directory, with full paths for examples.
83
+
84
+ **Rationale**: This decision acknowledges current Zeitwerk limitations while providing a working solution:
85
+ - Enables immediate hot reloading functionality
86
+ - Provides clear path configuration examples
87
+ - Documents the constraint for future improvement
88
+ - Allows examples to work alongside full applications
89
+
90
+ Noted in documentation that this will be improved in future refactoring to be more flexible.
91
+
92
+ #### Message-Driven Reload Communication
93
+ **Context**: Hot reloading needs to trigger model rebuilding when code changes are detected.
94
+
95
+ **Decision**: Use the existing Message system with `Message::Reload` events rather than creating a separate callback mechanism.
96
+
97
+ **Rationale**: This maintains consistency with the framework's event-driven architecture:
98
+ - Leverages existing message processing infrastructure
99
+ - Keeps reload handling within the normal update cycle
100
+ - Provides predictable behavior that follows Elm Architecture patterns
101
+ - Allows models to handle reloading as part of their normal message processing
102
+
103
+ ## Impact
104
+
105
+ The completion of the hot reloading system represents a major milestone for the Milktea framework's developer experience. These changes provide:
106
+
107
+ **For TUI Application Developers**: Hot reloading dramatically reduces development time by eliminating the need to restart applications when making changes. Developers can now iterate on UI layouts, business logic, and interactions in real-time, seeing results immediately.
108
+
109
+ **For Framework Architecture**: The Loader independence eliminates a significant architectural debt and provides a clean foundation for future development tooling. The separation of concerns makes the framework more modular and testable.
110
+
111
+ **For Example Development**: The working hot reloading example serves as both a demonstration and a template for developers setting up their own applications with hot reloading capabilities.
112
+
113
+ **For Project Documentation**: The comprehensive CLAUDE.md documentation ensures that critical setup knowledge is preserved and accessible to future contributors and users.
114
+
115
+ The changes demonstrate the framework's maturity in supporting professional development workflows while maintaining the simplicity and elegance of the core TUI architecture.
116
+
117
+ ## Files Modified
118
+
119
+ - `lib/milktea/loader.rb` - Redesigned to be independent from Config, automatic hot_reload handling
120
+ - `lib/milktea/model.rb` - Updated Model#with to use Kernel.const_get for fresh class definitions
121
+ - `lib/milktea/config.rb` - Removed loader from Config class to eliminate circular dependencies
122
+ - `lib/milktea/program.rb` - Removed loader logic to focus on core TUI functionality
123
+ - `examples/hot_reload_demo.rb` - Updated to use new independent Loader pattern
124
+ - `examples/hot_reload_demo/models/demo_model.rb` - Added Message::Reload handling with proper rebuilding
125
+ - `examples/hot_reload_demo/models/status_model.rb` - Child model demonstrating nested reloading
126
+ - `spec/milktea/loader_spec.rb` - Updated tests for new constructor and automatic hot_reload behavior
127
+ - `spec/milktea/config_spec.rb` - Removed loader-related tests to match simplified Config
128
+ - `CLAUDE.md` - Added comprehensive Hot Reloading Development section with setup and troubleshooting
129
+ - `ARCHITECTURE.md` - Updated to reflect new optional Loader system design patterns