taski 0.2.2 → 0.3.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/README.md +130 -7
- data/examples/README.md +13 -1
- data/examples/section_configuration.rb +212 -0
- data/examples/tree_demo.rb +125 -0
- data/lib/taski/dependency_analyzer.rb +104 -45
- data/lib/taski/exceptions.rb +3 -0
- data/lib/taski/logger.rb +7 -62
- data/lib/taski/logging/formatter_factory.rb +34 -0
- data/lib/taski/logging/formatter_interface.rb +19 -0
- data/lib/taski/logging/json_formatter.rb +26 -0
- data/lib/taski/logging/simple_formatter.rb +16 -0
- data/lib/taski/logging/structured_formatter.rb +44 -0
- data/lib/taski/progress/display_colors.rb +17 -0
- data/lib/taski/progress/display_manager.rb +115 -0
- data/lib/taski/progress/output_capture.rb +105 -0
- data/lib/taski/progress/spinner_animation.rb +46 -0
- data/lib/taski/progress/task_formatter.rb +25 -0
- data/lib/taski/progress/task_status.rb +38 -0
- data/lib/taski/progress/terminal_controller.rb +35 -0
- data/lib/taski/progress_display.rb +23 -320
- data/lib/taski/section.rb +268 -0
- data/lib/taski/task/base.rb +11 -32
- data/lib/taski/task/dependency_resolver.rb +4 -64
- data/lib/taski/task/instance_management.rb +28 -15
- data/lib/taski/tree_colors.rb +91 -0
- data/lib/taski/utils/dependency_resolver_helper.rb +85 -0
- data/lib/taski/utils/tree_display_helper.rb +71 -0
- data/lib/taski/version.rb +1 -1
- data/lib/taski.rb +4 -0
- metadata +20 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0c018d3aa27087ea7f87e11e01833ffe9c2e6118cc59af29f7f718b7706d108f
|
4
|
+
data.tar.gz: c18eb90fcfab955b8576b6329ee5df932fcdb8cfed9079c8705656c9e8b90de9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ea18fc4b07667fd17f2a37356c6a92c54daeadd4f7ad986d5e6131a4a717baf985548845789a17f8b5f5508de70354359a7413b957510d080b041c2f9cde6067
|
7
|
+
data.tar.gz: '08d4ce07b0bcde870805a2d5b0daf38d6a3cb850bc0e4da8b197c71b906d9f854fc8c97963362bd7b404b1709ded3d2d53975314bc31b19aab3967bdba903a19'
|
data/README.md
CHANGED
@@ -6,7 +6,7 @@
|
|
6
6
|
|
7
7
|
> **🚧 Development Status:** Taski is currently under active development. Not yet recommended for production use.
|
8
8
|
|
9
|
-
**Taski** is a Ruby framework for building task dependency graphs with automatic resolution and execution. It provides
|
9
|
+
**Taski** is a Ruby framework for building task dependency graphs with automatic resolution and execution. It provides three APIs: static dependencies through **Exports**, dynamic dependencies through **Define**, and abstraction layers through **Section**.
|
10
10
|
|
11
11
|
> **Name Origin**: "Taski" comes from the Japanese word "襷" (tasuki), a sash used in relay races. Just like how runners pass the sash to the next teammate, tasks in Taski pass dependencies to one another in a continuous chain.
|
12
12
|
|
@@ -97,19 +97,61 @@ EnvironmentConfig.build
|
|
97
97
|
# => Environment: production
|
98
98
|
```
|
99
99
|
|
100
|
+
### Section API - Abstraction Layers
|
101
|
+
|
102
|
+
For environment-specific implementations with clean interfaces:
|
103
|
+
|
104
|
+
```ruby
|
105
|
+
class DatabaseSection < Taski::Section
|
106
|
+
interface :host, :port
|
107
|
+
|
108
|
+
def impl # No 'self' needed!
|
109
|
+
ENV['RAILS_ENV'] == 'production' ? Production : Development
|
110
|
+
end
|
111
|
+
|
112
|
+
class Production < Taski::Task
|
113
|
+
def build
|
114
|
+
@host = "prod-db.example.com"
|
115
|
+
@port = 5432
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
class Development < Taski::Task
|
120
|
+
def build
|
121
|
+
@host = "localhost"
|
122
|
+
@port = 5432
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
apply_auto_exports # DRY - auto-adds exports to nested tasks
|
127
|
+
end
|
128
|
+
|
129
|
+
# Usage is simple - Section works like any Task
|
130
|
+
class App < Taski::Task
|
131
|
+
def build
|
132
|
+
puts "DB: #{DatabaseSection.host}:#{DatabaseSection.port}"
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
App.build # => DB: localhost:5432
|
137
|
+
```
|
138
|
+
|
100
139
|
### When to Use Each API
|
101
140
|
|
102
141
|
- **Define API**: Best for dynamic runtime dependencies. Cannot contain side effects in definition blocks. Dependencies are analyzed at class definition time, not runtime.
|
103
142
|
- **Exports API**: Ideal for static dependencies. Supports side effects in build methods.
|
143
|
+
- **Section API**: Perfect for abstraction layers where you need different implementations based on runtime conditions while maintaining static analysis capabilities.
|
104
144
|
|
105
145
|
| Use Case | API | Example |
|
106
146
|
|----------|-----|---------|
|
107
147
|
| Configuration values | Exports | File paths, settings |
|
108
|
-
| Environment-specific logic | Define | Different services per env |
|
148
|
+
| Environment-specific logic | Define/Section | Different services per env |
|
109
149
|
| Side effects | Exports | Database connections, I/O |
|
110
150
|
| Conditional processing | Define | Algorithm selection |
|
151
|
+
| Implementation abstraction | Section | Database/API adapters |
|
152
|
+
| Multi-environment configs | Section | Dev/Test/Prod settings |
|
111
153
|
|
112
|
-
**Note**: Define API analyzes dependencies when the class is defined. Conditional dependencies like `ENV['USE_NEW'] ? TaskA : TaskB` will only include the task selected at class definition time, not runtime.
|
154
|
+
**Note**: Define API analyzes dependencies when the class is defined. Conditional dependencies like `ENV['USE_NEW'] ? TaskA : TaskB` will only include the task selected at class definition time, not runtime. Use Section API when you need true runtime selection.
|
113
155
|
|
114
156
|
## ✨ Key Features
|
115
157
|
|
@@ -118,6 +160,86 @@ EnvironmentConfig.build
|
|
118
160
|
- **Circular Dependency Detection**: Clear error messages with detailed paths
|
119
161
|
- **Granular Execution**: Build individual tasks or complete graphs
|
120
162
|
- **Memory Management**: Built-in reset mechanisms
|
163
|
+
- **Progress Display**: Visual feedback with spinners and output capture
|
164
|
+
- **Dependency Tree Visualization**: Visual representation of task relationships
|
165
|
+
|
166
|
+
### Dependency Tree Visualization
|
167
|
+
|
168
|
+
Visualize task dependencies with the `tree` method:
|
169
|
+
|
170
|
+
```ruby
|
171
|
+
class Database < Taski::Task
|
172
|
+
exports :connection
|
173
|
+
def build; @connection = "db-conn"; end
|
174
|
+
end
|
175
|
+
|
176
|
+
class Cache < Taski::Task
|
177
|
+
exports :redis_url
|
178
|
+
def build; @redis_url = "redis://localhost"; end
|
179
|
+
end
|
180
|
+
|
181
|
+
class Config < Taski::Task
|
182
|
+
exports :settings
|
183
|
+
def build
|
184
|
+
@settings = {
|
185
|
+
database: Database.connection,
|
186
|
+
cache: Cache.redis_url
|
187
|
+
}
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
class WebServer < Taski::Task
|
192
|
+
def build
|
193
|
+
puts "Starting with #{Config.settings}"
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
puts WebServer.tree
|
198
|
+
# => WebServer
|
199
|
+
# => └── Config
|
200
|
+
# => ├── Database
|
201
|
+
# => └── Cache
|
202
|
+
|
203
|
+
# Sections also appear in dependency trees
|
204
|
+
puts AppServer.tree
|
205
|
+
# => AppServer
|
206
|
+
# => └── DatabaseSection
|
207
|
+
```
|
208
|
+
|
209
|
+
### Progress Display
|
210
|
+
|
211
|
+
Taski provides visual feedback during task execution with animated spinners and real-time output capture:
|
212
|
+
|
213
|
+
```ruby
|
214
|
+
class LongRunningTask < Taski::Task
|
215
|
+
def build
|
216
|
+
puts "Starting process..."
|
217
|
+
sleep(1.0)
|
218
|
+
puts "Processing data..."
|
219
|
+
puts "Almost done..."
|
220
|
+
sleep(0.5)
|
221
|
+
puts "Completed!"
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
LongRunningTask.build
|
226
|
+
# During execution shows:
|
227
|
+
# ⠧ LongRunningTask
|
228
|
+
# Starting process...
|
229
|
+
# Processing data...
|
230
|
+
# Almost done...
|
231
|
+
# Completed!
|
232
|
+
#
|
233
|
+
# After completion shows:
|
234
|
+
# ✅ LongRunningTask (1500ms)
|
235
|
+
```
|
236
|
+
|
237
|
+
**Progress Display Features:**
|
238
|
+
- **Spinner Animation**: Dots-style spinner during task execution
|
239
|
+
- **Output Capture**: Real-time display of task output (last 5 lines)
|
240
|
+
- **Status Indicators**: ✅ for success, ❌ for failure
|
241
|
+
- **Execution Time**: Shows task duration after completion
|
242
|
+
- **TTY Detection**: Clean output when redirected to files
|
121
243
|
|
122
244
|
### Granular Task Execution
|
123
245
|
|
@@ -190,7 +312,7 @@ class FileTask < Taski::Task
|
|
190
312
|
def clean
|
191
313
|
# ❌ Bad: Raises error if file doesn't exist
|
192
314
|
# File.delete(@output_file)
|
193
|
-
|
315
|
+
|
194
316
|
# ✅ Good: Check before delete
|
195
317
|
File.delete(@output_file) if File.exist?(@output_file)
|
196
318
|
end
|
@@ -207,7 +329,7 @@ rescue Taski::CircularDependencyError => e
|
|
207
329
|
end
|
208
330
|
# => Circular dependency: Circular dependency detected!
|
209
331
|
# => Cycle: TaskA → TaskB → TaskA
|
210
|
-
# =>
|
332
|
+
# =>
|
211
333
|
# => The dependency chain is:
|
212
334
|
# => 1. TaskA is trying to build → TaskB
|
213
335
|
# => 2. TaskB is trying to build → TaskA
|
@@ -234,8 +356,9 @@ bundle exec rake test
|
|
234
356
|
- **Task Base**: Core framework
|
235
357
|
- **Exports API**: Static dependency resolution
|
236
358
|
- **Define API**: Dynamic dependency resolution
|
359
|
+
- **Section API**: Abstraction layer with runtime implementation selection
|
237
360
|
- **Instance Management**: Thread-safe lifecycle
|
238
|
-
- **Dependency Resolver**: Topological sorting
|
361
|
+
- **Dependency Resolver**: Topological sorting with Section support
|
239
362
|
|
240
363
|
## Contributing
|
241
364
|
|
@@ -247,4 +370,4 @@ MIT License
|
|
247
370
|
|
248
371
|
---
|
249
372
|
|
250
|
-
**Taski** - Build dependency graphs with elegant Ruby code. 🚀
|
373
|
+
**Taski** - Build dependency graphs with elegant Ruby code. 🚀
|
data/examples/README.md
CHANGED
@@ -30,7 +30,17 @@ ruby examples/progress_demo.rb > build.log 2>&1
|
|
30
30
|
cat build.log
|
31
31
|
```
|
32
32
|
|
33
|
-
### 3. **[
|
33
|
+
### 3. **[section_configuration.rb](section_configuration.rb)** - Section-based Configuration Management
|
34
|
+
- Dynamic implementation selection with Taski::Section
|
35
|
+
- Environment-specific configuration
|
36
|
+
- Section dependency resolution
|
37
|
+
- Complex configuration hierarchies
|
38
|
+
|
39
|
+
```bash
|
40
|
+
ruby examples/section_configuration.rb
|
41
|
+
```
|
42
|
+
|
43
|
+
### 4. **[advanced_patterns.rb](advanced_patterns.rb)** - Complex Dependency Patterns
|
34
44
|
- Mixed Exports API and Define API usage
|
35
45
|
- Environment-specific dependencies
|
36
46
|
- Feature flags and conditional logic
|
@@ -44,6 +54,8 @@ ruby examples/advanced_patterns.rb
|
|
44
54
|
|
45
55
|
- **Exports API**: Static dependencies with `exports :property`
|
46
56
|
- **Define API**: Dynamic dependencies with `define :property, -> { ... }`
|
57
|
+
- **Section API**: Dynamic implementation selection with `Taski::Section`
|
58
|
+
- **Dependency Resolution**: Automatic dependency detection for sections
|
47
59
|
- **Progress Display**: Rich terminal output with spinners and colors
|
48
60
|
- **Output Capture**: Tail-style display of task output
|
49
61
|
- **Environment Configuration**: Different behavior based on runtime settings
|
@@ -0,0 +1,212 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
# Section Configuration Example
|
5
|
+
# This example demonstrates how to use Taski::Section for dynamic implementation
|
6
|
+
# selection and dependency resolution with configuration management.
|
7
|
+
#
|
8
|
+
# Key Features Demonstrated:
|
9
|
+
# 1. DRY Principle: No need to duplicate 'exports' declarations in nested Task classes
|
10
|
+
# - interface declaration automatically adds exports to nested Task classes
|
11
|
+
# 2. Consistent API: impl must return Task classes - .build is called automatically
|
12
|
+
# 3. Dynamic Implementation Selection: Different implementations based on environment
|
13
|
+
# 4. Dependency Resolution: Sections are properly detected in dependency analysis
|
14
|
+
# 5. Tree Visualization: Sections appear in dependency trees
|
15
|
+
|
16
|
+
require_relative "../lib/taski"
|
17
|
+
|
18
|
+
# Example 1: Database Configuration Section
|
19
|
+
# This section provides database configuration with different implementations
|
20
|
+
# for development and production environments
|
21
|
+
class DatabaseSection < Taski::Section
|
22
|
+
# Define the interface that implementations must provide
|
23
|
+
interface :host, :port, :username, :password, :database_name, :pool_size
|
24
|
+
|
25
|
+
# Select implementation based on environment
|
26
|
+
# Note: Must return a Task class - .build is automatically called
|
27
|
+
# No 'self' needed - just define as instance method!
|
28
|
+
def impl
|
29
|
+
if ENV["RAILS_ENV"] == "production"
|
30
|
+
Production
|
31
|
+
else
|
32
|
+
Development
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# Production implementation with secure settings
|
37
|
+
# Note: exports are automatically inherited from interface declaration
|
38
|
+
class Production < Taski::Task
|
39
|
+
def build
|
40
|
+
@host = "prod-db.example.com"
|
41
|
+
@port = 5432
|
42
|
+
@username = "app_user"
|
43
|
+
@password = ENV["DB_PASSWORD"] || "secure_password"
|
44
|
+
@database_name = "myapp_production"
|
45
|
+
@pool_size = 25
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# Development implementation with local settings
|
50
|
+
# Note: exports are automatically inherited from interface declaration
|
51
|
+
class Development < Taski::Task
|
52
|
+
def build
|
53
|
+
@host = "localhost"
|
54
|
+
@port = 5432
|
55
|
+
@username = "dev_user"
|
56
|
+
@password = "dev_password"
|
57
|
+
@database_name = "myapp_development"
|
58
|
+
@pool_size = 5
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# Apply auto-exports after all nested Task classes are defined
|
63
|
+
apply_auto_exports
|
64
|
+
end
|
65
|
+
|
66
|
+
# Example 2: API Configuration Section
|
67
|
+
# This section provides API endpoints and credentials
|
68
|
+
class ApiSection < Taski::Section
|
69
|
+
interface :base_url, :api_key, :timeout, :retry_count
|
70
|
+
|
71
|
+
# No 'self' needed - just define as instance method!
|
72
|
+
def impl
|
73
|
+
# Select based on feature flag
|
74
|
+
# Note: Must return a Task class - .build is automatically called
|
75
|
+
if ENV["USE_STAGING_API"] == "true"
|
76
|
+
Staging
|
77
|
+
else
|
78
|
+
Production
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# Note: exports are automatically inherited from interface declaration - DRY principle!
|
83
|
+
class Production < Taski::Task
|
84
|
+
def build
|
85
|
+
@base_url = "https://api.example.com/v1"
|
86
|
+
@api_key = ENV["PROD_API_KEY"] || "prod-key-123"
|
87
|
+
@timeout = 30
|
88
|
+
@retry_count = 3
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
# Note: exports are automatically inherited from interface declaration - DRY principle!
|
93
|
+
class Staging < Taski::Task
|
94
|
+
def build
|
95
|
+
@base_url = "https://staging-api.example.com/v1"
|
96
|
+
@api_key = ENV["STAGING_API_KEY"] || "staging-key-456"
|
97
|
+
@timeout = 60
|
98
|
+
@retry_count = 1
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
# Apply auto-exports after all nested Task classes are defined
|
103
|
+
apply_auto_exports
|
104
|
+
end
|
105
|
+
|
106
|
+
# Example 3: Task that depends on multiple sections
|
107
|
+
class ApplicationSetup < Taski::Task
|
108
|
+
exports :config_summary
|
109
|
+
|
110
|
+
def build
|
111
|
+
puts "Setting up application with configuration:"
|
112
|
+
puts "Database: #{DatabaseSection.host}:#{DatabaseSection.port}/#{DatabaseSection.database_name}"
|
113
|
+
puts "API: #{ApiSection.base_url}"
|
114
|
+
puts "Pool size: #{DatabaseSection.pool_size}"
|
115
|
+
puts "API timeout: #{ApiSection.timeout}s"
|
116
|
+
|
117
|
+
@config_summary = {
|
118
|
+
database: {
|
119
|
+
host: DatabaseSection.host,
|
120
|
+
port: DatabaseSection.port,
|
121
|
+
database: DatabaseSection.database_name,
|
122
|
+
pool_size: DatabaseSection.pool_size
|
123
|
+
},
|
124
|
+
api: {
|
125
|
+
base_url: ApiSection.base_url,
|
126
|
+
timeout: ApiSection.timeout,
|
127
|
+
retry_count: ApiSection.retry_count
|
128
|
+
}
|
129
|
+
}
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
# Example 4: Complex dependency chain with sections
|
134
|
+
class DatabaseConnection < Taski::Task
|
135
|
+
exports :connection
|
136
|
+
|
137
|
+
def build
|
138
|
+
puts "Connecting to database..."
|
139
|
+
# Use section configuration to create connection
|
140
|
+
connection_string = "postgresql://#{DatabaseSection.username}:#{DatabaseSection.password}@#{DatabaseSection.host}:#{DatabaseSection.port}/#{DatabaseSection.database_name}"
|
141
|
+
@connection = "Connected to: #{connection_string} (pool: #{DatabaseSection.pool_size})"
|
142
|
+
puts @connection
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
class ApiClient < Taski::Task
|
147
|
+
exports :client
|
148
|
+
|
149
|
+
def build
|
150
|
+
puts "Initializing API client..."
|
151
|
+
@client = "API Client: #{ApiSection.base_url} (timeout: #{ApiSection.timeout}s, retries: #{ApiSection.retry_count})"
|
152
|
+
puts @client
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
class Application < Taski::Task
|
157
|
+
def build
|
158
|
+
puts "\n=== Starting Application ==="
|
159
|
+
|
160
|
+
# Dependencies are automatically resolved
|
161
|
+
# DatabaseConnection and ApiClient will be built first
|
162
|
+
# which triggers building of their respective sections
|
163
|
+
|
164
|
+
puts "\nDatabase ready: #{DatabaseConnection.connection}"
|
165
|
+
puts "API ready: #{ApiClient.client}"
|
166
|
+
|
167
|
+
puts "\nApplication configuration summary:"
|
168
|
+
puts ApplicationSetup.config_summary.inspect
|
169
|
+
|
170
|
+
puts "\n=== Application Started Successfully ==="
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
# Demo script
|
175
|
+
if __FILE__ == $0
|
176
|
+
puts "Taski Section Configuration Example"
|
177
|
+
puts "=" * 50
|
178
|
+
|
179
|
+
puts "\n1. Development Environment (default)"
|
180
|
+
ENV["RAILS_ENV"] = "development"
|
181
|
+
ENV["USE_STAGING_API"] = "false"
|
182
|
+
|
183
|
+
# Reset all tasks to ensure fresh build
|
184
|
+
[DatabaseSection, ApiSection, ApplicationSetup, DatabaseConnection, ApiClient, Application].each(&:reset!)
|
185
|
+
|
186
|
+
Application.build
|
187
|
+
|
188
|
+
puts "\n" + "=" * 50
|
189
|
+
puts "\n2. Production Environment with Staging API"
|
190
|
+
ENV["RAILS_ENV"] = "production"
|
191
|
+
ENV["USE_STAGING_API"] = "true"
|
192
|
+
|
193
|
+
# Reset all tasks to see different configuration
|
194
|
+
[DatabaseSection, ApiSection, ApplicationSetup, DatabaseConnection, ApiClient, Application].each(&:reset!)
|
195
|
+
|
196
|
+
Application.build
|
197
|
+
|
198
|
+
puts "\n" + "=" * 50
|
199
|
+
puts "\n3. Dependency Tree Visualization"
|
200
|
+
puts "\nApplication dependency tree:"
|
201
|
+
puts Application.tree
|
202
|
+
|
203
|
+
puts "\nDatabaseConnection dependency tree:"
|
204
|
+
puts DatabaseConnection.tree
|
205
|
+
|
206
|
+
puts "\nApiClient dependency tree:"
|
207
|
+
puts ApiClient.tree
|
208
|
+
|
209
|
+
puts "\n" + "=" * 50
|
210
|
+
puts "\nSection dependency resolution successfully demonstrated!"
|
211
|
+
puts "Notice how sections appear in the dependency trees and logs."
|
212
|
+
end
|
data/examples/tree_demo.rb
CHANGED
@@ -76,5 +76,130 @@ puts WebServer.tree
|
|
76
76
|
puts "\nConfig dependencies:"
|
77
77
|
puts Config.tree
|
78
78
|
|
79
|
+
puts "\n🔧 Section-based Architecture (Dynamic Implementation Selection):"
|
80
|
+
|
81
|
+
# Create database section with multiple implementation options
|
82
|
+
class DatabaseSection < Taski::Section
|
83
|
+
interface :connection_string, :pool_size
|
84
|
+
|
85
|
+
def self.impl
|
86
|
+
if ENV["DATABASE"] == "postgres"
|
87
|
+
PostgresImplementation
|
88
|
+
elsif ENV["DATABASE"] == "mysql"
|
89
|
+
MysqlImplementation
|
90
|
+
else
|
91
|
+
SQLiteImplementation
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
class PostgresImplementation < Taski::Task
|
96
|
+
exports :connection_string, :pool_size
|
97
|
+
|
98
|
+
def build
|
99
|
+
Logger.log_level
|
100
|
+
@connection_string = "postgresql://localhost/production_app"
|
101
|
+
@pool_size = 20
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
class MysqlImplementation < Taski::Task
|
106
|
+
exports :connection_string, :pool_size
|
107
|
+
|
108
|
+
def build
|
109
|
+
Logger.log_level
|
110
|
+
@connection_string = "mysql://localhost/production_app"
|
111
|
+
@pool_size = 15
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
class SQLiteImplementation < Taski::Task
|
116
|
+
exports :connection_string, :pool_size
|
117
|
+
|
118
|
+
def build
|
119
|
+
@connection_string = "sqlite:///tmp/development.db"
|
120
|
+
@pool_size = 1
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
# Cache section with Redis/Memory options
|
126
|
+
class CacheSection < Taski::Section
|
127
|
+
interface :cache_url
|
128
|
+
|
129
|
+
def self.impl
|
130
|
+
if ENV["CACHE"] == "redis"
|
131
|
+
RedisCache
|
132
|
+
else
|
133
|
+
MemoryCache
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
class RedisCache < Taski::Task
|
138
|
+
exports :cache_url
|
139
|
+
def build
|
140
|
+
DatabaseSection.connection_string
|
141
|
+
@cache_url = "redis://localhost:6379"
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
class MemoryCache < Taski::Task
|
146
|
+
exports :cache_url
|
147
|
+
def build
|
148
|
+
@cache_url = "memory://local"
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
puts "\n📋 Section Trees (Show Available Implementations):"
|
154
|
+
puts "\nDatabaseSection.tree:"
|
155
|
+
puts DatabaseSection.tree
|
156
|
+
|
157
|
+
puts "\nCacheSection.tree:"
|
158
|
+
puts CacheSection.tree
|
159
|
+
|
160
|
+
puts "\n🔍 Individual Implementation Trees (Show Actual Dependencies):"
|
161
|
+
puts "\nDatabaseSection::PostgresImplementation.tree:"
|
162
|
+
puts DatabaseSection::PostgresImplementation.tree
|
163
|
+
|
164
|
+
puts "\nDatabaseSection::SQLiteImplementation.tree:"
|
165
|
+
puts DatabaseSection::SQLiteImplementation.tree
|
166
|
+
|
167
|
+
puts "\nCacheSection::RedisCache.tree:"
|
168
|
+
puts CacheSection::RedisCache.tree
|
169
|
+
|
170
|
+
puts "\n🔄 Section vs Implementation Comparison:"
|
171
|
+
puts "Section shows POSSIBLE implementations:"
|
172
|
+
puts DatabaseSection.tree
|
173
|
+
puts "\nBut implementation shows ACTUAL dependencies:"
|
174
|
+
puts DatabaseSection::PostgresImplementation.tree
|
175
|
+
|
176
|
+
puts "\n💡 Workflow:"
|
177
|
+
puts "1. Use DatabaseSection.tree to see what implementations are available"
|
178
|
+
puts "2. Use DatabaseSection::PostgresImplementation.tree to see specific dependencies"
|
179
|
+
puts "3. Runtime selects implementation based on ENV variables"
|
180
|
+
|
181
|
+
puts "\n🎨 Colored Tree Display (if TTY supports colors):"
|
182
|
+
|
183
|
+
# Enable colors for demonstration
|
184
|
+
Taski::TreeColors.enabled = true
|
185
|
+
|
186
|
+
puts "\nDatabaseSection.tree (with colors):"
|
187
|
+
puts DatabaseSection.tree(color: true)
|
188
|
+
|
189
|
+
puts "\nCacheSection.tree (with colors):"
|
190
|
+
puts CacheSection.tree(color: true)
|
191
|
+
|
192
|
+
puts "\nDatabaseSection::PostgresImplementation.tree (with colors):"
|
193
|
+
puts DatabaseSection::PostgresImplementation.tree(color: true)
|
194
|
+
|
195
|
+
puts "\n🎯 Color Legend:"
|
196
|
+
puts "#{Taski::TreeColors.section("Blue")} = Section names (dynamic selection layer)"
|
197
|
+
puts "#{Taski::TreeColors.task("Green")} = Task names (concrete implementations)"
|
198
|
+
puts "#{Taski::TreeColors.implementations("Yellow")} = Implementation candidates"
|
199
|
+
puts "#{Taski::TreeColors.connector("Gray")} = Tree connectors"
|
200
|
+
|
201
|
+
# Reset colors to auto-detection
|
202
|
+
Taski::TreeColors.enabled = nil
|
203
|
+
|
79
204
|
puts "\n▶️ Building Application (to verify dependencies work):"
|
80
205
|
Application.build
|