taski 0.3.1 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gem_rbs_collection/ast/2.4/.rbs_meta.yaml +9 -0
- data/.gem_rbs_collection/ast/2.4/ast.rbs +73 -0
- data/.gem_rbs_collection/minitest/5.25/.rbs_meta.yaml +9 -0
- data/.gem_rbs_collection/minitest/5.25/minitest/abstract_reporter.rbs +52 -0
- data/.gem_rbs_collection/minitest/5.25/minitest/assertion.rbs +17 -0
- data/.gem_rbs_collection/minitest/5.25/minitest/assertions.rbs +590 -0
- data/.gem_rbs_collection/minitest/5.25/minitest/backtrace_filter.rbs +23 -0
- data/.gem_rbs_collection/minitest/5.25/minitest/bench_spec.rbs +102 -0
- data/.gem_rbs_collection/minitest/5.25/minitest/benchmark.rbs +259 -0
- data/.gem_rbs_collection/minitest/5.25/minitest/composite_reporter.rbs +25 -0
- data/.gem_rbs_collection/minitest/5.25/minitest/compress.rbs +13 -0
- data/.gem_rbs_collection/minitest/5.25/minitest/error_on_warning.rbs +3 -0
- data/.gem_rbs_collection/minitest/5.25/minitest/expectation.rbs +2 -0
- data/.gem_rbs_collection/minitest/5.25/minitest/expectations.rbs +21 -0
- data/.gem_rbs_collection/minitest/5.25/minitest/guard.rbs +64 -0
- data/.gem_rbs_collection/minitest/5.25/minitest/mock.rbs +64 -0
- data/.gem_rbs_collection/minitest/5.25/minitest/parallel/executor.rbs +46 -0
- data/.gem_rbs_collection/minitest/5.25/minitest/parallel/test/class_methods.rbs +5 -0
- data/.gem_rbs_collection/minitest/5.25/minitest/parallel/test.rbs +3 -0
- data/.gem_rbs_collection/minitest/5.25/minitest/parallel.rbs +2 -0
- data/.gem_rbs_collection/minitest/5.25/minitest/pride_io.rbs +62 -0
- data/.gem_rbs_collection/minitest/5.25/minitest/pride_lol.rbs +19 -0
- data/.gem_rbs_collection/minitest/5.25/minitest/progress_reporter.rbs +11 -0
- data/.gem_rbs_collection/minitest/5.25/minitest/reportable.rbs +53 -0
- data/.gem_rbs_collection/minitest/5.25/minitest/reporter.rbs +5 -0
- data/.gem_rbs_collection/minitest/5.25/minitest/result.rbs +28 -0
- data/.gem_rbs_collection/minitest/5.25/minitest/runnable.rbs +163 -0
- data/.gem_rbs_collection/minitest/5.25/minitest/skip.rbs +6 -0
- data/.gem_rbs_collection/minitest/5.25/minitest/spec/dsl/instance_methods.rbs +48 -0
- data/.gem_rbs_collection/minitest/5.25/minitest/spec/dsl.rbs +129 -0
- data/.gem_rbs_collection/minitest/5.25/minitest/spec.rbs +11 -0
- data/.gem_rbs_collection/minitest/5.25/minitest/statistics_reporter.rbs +81 -0
- data/.gem_rbs_collection/minitest/5.25/minitest/summary_reporter.rbs +18 -0
- data/.gem_rbs_collection/minitest/5.25/minitest/test/lifecycle_hooks.rbs +92 -0
- data/.gem_rbs_collection/minitest/5.25/minitest/test.rbs +69 -0
- data/.gem_rbs_collection/minitest/5.25/minitest/unexpected_error.rbs +12 -0
- data/.gem_rbs_collection/minitest/5.25/minitest/unexpected_warning.rbs +6 -0
- data/.gem_rbs_collection/minitest/5.25/minitest/unit/test_case.rbs +3 -0
- data/.gem_rbs_collection/minitest/5.25/minitest/unit.rbs +4 -0
- data/.gem_rbs_collection/minitest/5.25/minitest.rbs +115 -0
- data/.gem_rbs_collection/parallel/1.20/.rbs_meta.yaml +9 -0
- data/.gem_rbs_collection/parallel/1.20/parallel.rbs +86 -0
- data/.gem_rbs_collection/parser/3.2/.rbs_meta.yaml +9 -0
- data/.gem_rbs_collection/parser/3.2/manifest.yaml +7 -0
- data/.gem_rbs_collection/parser/3.2/parser.rbs +193 -0
- data/.gem_rbs_collection/parser/3.2/polyfill.rbs +4 -0
- data/.gem_rbs_collection/rainbow/3.0/.rbs_meta.yaml +9 -0
- data/.gem_rbs_collection/rainbow/3.0/global.rbs +7 -0
- data/.gem_rbs_collection/rainbow/3.0/presenter.rbs +209 -0
- data/.gem_rbs_collection/rainbow/3.0/rainbow.rbs +5 -0
- data/.gem_rbs_collection/rake/13.0/.rbs_meta.yaml +9 -0
- data/.gem_rbs_collection/rake/13.0/manifest.yaml +2 -0
- data/.gem_rbs_collection/rake/13.0/rake.rbs +39 -0
- data/.gem_rbs_collection/regexp_parser/2.8/.rbs_meta.yaml +9 -0
- data/.gem_rbs_collection/regexp_parser/2.8/regexp_parser.rbs +17 -0
- data/.gem_rbs_collection/rubocop/1.57/.rbs_meta.yaml +9 -0
- data/.gem_rbs_collection/rubocop/1.57/rubocop.rbs +129 -0
- data/.gem_rbs_collection/rubocop-ast/1.30/.rbs_meta.yaml +9 -0
- data/.gem_rbs_collection/rubocop-ast/1.30/rubocop-ast.rbs +771 -0
- data/.gem_rbs_collection/simplecov/0.22/.rbs_meta.yaml +9 -0
- data/.gem_rbs_collection/simplecov/0.22/simplecov.rbs +54 -0
- data/README.md +138 -247
- data/Steepfile +19 -0
- data/docs/advanced-features.md +625 -0
- data/docs/api-guide.md +509 -0
- data/docs/error-handling.md +684 -0
- data/examples/README.md +95 -42
- data/examples/context_demo.rb +112 -0
- data/examples/data_pipeline_demo.rb +231 -0
- data/examples/parallel_progress_demo.rb +72 -0
- data/examples/quick_start.rb +4 -4
- data/examples/reexecution_demo.rb +127 -0
- data/examples/{section_configuration.rb → section_demo.rb} +49 -60
- data/lib/taski/context.rb +52 -0
- data/lib/taski/execution/coordinator.rb +63 -0
- data/lib/taski/execution/parallel_progress_display.rb +201 -0
- data/lib/taski/execution/registry.rb +72 -0
- data/lib/taski/execution/task_wrapper.rb +255 -0
- data/lib/taski/section.rb +26 -254
- data/lib/taski/static_analysis/analyzer.rb +34 -0
- data/lib/taski/static_analysis/dependency_graph.rb +90 -0
- data/lib/taski/static_analysis/visitor.rb +114 -0
- data/lib/taski/task.rb +173 -0
- data/lib/taski/version.rb +1 -1
- data/lib/taski.rb +45 -39
- data/rbs_collection.lock.yaml +116 -0
- data/rbs_collection.yaml +19 -0
- data/sig/taski.rbs +269 -62
- metadata +97 -32
- data/examples/advanced_patterns.rb +0 -119
- data/examples/progress_demo.rb +0 -166
- data/examples/tree_demo.rb +0 -205
- data/lib/taski/dependency_analyzer.rb +0 -232
- data/lib/taski/exceptions.rb +0 -17
- data/lib/taski/logger.rb +0 -158
- data/lib/taski/logging/formatter_factory.rb +0 -34
- data/lib/taski/logging/formatter_interface.rb +0 -19
- data/lib/taski/logging/json_formatter.rb +0 -26
- data/lib/taski/logging/simple_formatter.rb +0 -16
- data/lib/taski/logging/structured_formatter.rb +0 -44
- data/lib/taski/progress/display_colors.rb +0 -17
- data/lib/taski/progress/display_manager.rb +0 -117
- data/lib/taski/progress/output_capture.rb +0 -105
- data/lib/taski/progress/spinner_animation.rb +0 -49
- data/lib/taski/progress/task_formatter.rb +0 -25
- data/lib/taski/progress/task_status.rb +0 -38
- data/lib/taski/progress/terminal_controller.rb +0 -35
- data/lib/taski/progress_display.rb +0 -57
- data/lib/taski/reference.rb +0 -40
- data/lib/taski/task/base.rb +0 -91
- data/lib/taski/task/define_api.rb +0 -156
- data/lib/taski/task/dependency_resolver.rb +0 -73
- data/lib/taski/task/exports_api.rb +0 -29
- data/lib/taski/task/instance_management.rb +0 -201
- data/lib/taski/tree_colors.rb +0 -91
- data/lib/taski/utils/dependency_resolver_helper.rb +0 -85
- data/lib/taski/utils/tree_display_helper.rb +0 -68
- data/lib/taski/utils.rb +0 -107
data/docs/api-guide.md
ADDED
|
@@ -0,0 +1,509 @@
|
|
|
1
|
+
# API Guide
|
|
2
|
+
|
|
3
|
+
This guide provides detailed documentation for Taski's three APIs: Exports, Define, and Section.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
Taski provides three complementary APIs for different dependency scenarios:
|
|
8
|
+
|
|
9
|
+
- **Exports API**: Static dependencies with side effects
|
|
10
|
+
- **Define API**: Dynamic dependencies without side effects
|
|
11
|
+
- **Section API**: Runtime implementation selection
|
|
12
|
+
|
|
13
|
+
## Exports API - Static Dependencies
|
|
14
|
+
|
|
15
|
+
The Exports API is ideal for static values and operations with side effects.
|
|
16
|
+
|
|
17
|
+
### Basic Usage
|
|
18
|
+
|
|
19
|
+
```ruby
|
|
20
|
+
class ConfigLoader < Taski::Task
|
|
21
|
+
exports :app_name, :version, :database_url
|
|
22
|
+
|
|
23
|
+
def run
|
|
24
|
+
@app_name = "MyApp"
|
|
25
|
+
@version = "1.0.0"
|
|
26
|
+
@database_url = "postgresql://localhost/myapp"
|
|
27
|
+
puts "Configuration loaded"
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
class Server < Taski::Task
|
|
32
|
+
def run
|
|
33
|
+
puts "Starting #{ConfigLoader.app_name} v#{ConfigLoader.version}"
|
|
34
|
+
puts "Database: #{ConfigLoader.database_url}"
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
Server.run
|
|
39
|
+
# => Configuration loaded
|
|
40
|
+
# => Starting MyApp v1.0.0
|
|
41
|
+
# => Database: postgresql://localhost/myapp
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Multiple Dependencies
|
|
45
|
+
|
|
46
|
+
```ruby
|
|
47
|
+
class Database < Taski::Task
|
|
48
|
+
exports :connection
|
|
49
|
+
|
|
50
|
+
def run
|
|
51
|
+
@connection = "db-connection-#{Time.now.to_i}"
|
|
52
|
+
puts "Database connected"
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
class Cache < Taski::Task
|
|
57
|
+
exports :redis_client
|
|
58
|
+
|
|
59
|
+
def run
|
|
60
|
+
@redis_client = "redis-client-#{Time.now.to_i}"
|
|
61
|
+
puts "Cache connected"
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
class Application < Taski::Task
|
|
66
|
+
def run
|
|
67
|
+
puts "App starting with DB: #{Database.connection}"
|
|
68
|
+
puts "App starting with Cache: #{Cache.redis_client}"
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
Application.run
|
|
73
|
+
# => Database connected
|
|
74
|
+
# => Cache connected
|
|
75
|
+
# => App starting with DB: db-connection-1234567890
|
|
76
|
+
# => App starting with Cache: redis-client-1234567890
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### When to Use Exports API
|
|
80
|
+
|
|
81
|
+
- **Static configuration values**: File paths, settings, constants
|
|
82
|
+
- **Side effects**: Database connections, file I/O, network calls
|
|
83
|
+
- **Predictable dependencies**: When the dependency chain is known at class definition time
|
|
84
|
+
|
|
85
|
+
## Define API - Dynamic Dependencies
|
|
86
|
+
|
|
87
|
+
The Define API enables runtime-dependent values without side effects.
|
|
88
|
+
|
|
89
|
+
### Basic Usage
|
|
90
|
+
|
|
91
|
+
```ruby
|
|
92
|
+
class EnvironmentConfig < Taski::Task
|
|
93
|
+
define :database_host, -> {
|
|
94
|
+
case ENV['RAILS_ENV']
|
|
95
|
+
when 'production'
|
|
96
|
+
'prod-db.example.com'
|
|
97
|
+
when 'staging'
|
|
98
|
+
'staging-db.example.com'
|
|
99
|
+
else
|
|
100
|
+
'localhost'
|
|
101
|
+
end
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
define :redis_url, -> {
|
|
105
|
+
case ENV['RAILS_ENV']
|
|
106
|
+
when 'production'
|
|
107
|
+
'redis://prod-redis.example.com:6379'
|
|
108
|
+
else
|
|
109
|
+
'redis://localhost:6379'
|
|
110
|
+
end
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
def run
|
|
114
|
+
puts "Database: #{database_host}"
|
|
115
|
+
puts "Redis: #{redis_url}"
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
ENV['RAILS_ENV'] = 'development'
|
|
120
|
+
EnvironmentConfig.run
|
|
121
|
+
# => Database: localhost
|
|
122
|
+
# => Redis: redis://localhost:6379
|
|
123
|
+
|
|
124
|
+
ENV['RAILS_ENV'] = 'production'
|
|
125
|
+
EnvironmentConfig.reset!
|
|
126
|
+
EnvironmentConfig.run
|
|
127
|
+
# => Database: prod-db.example.com
|
|
128
|
+
# => Redis: redis://prod-redis.example.com:6379
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### Dynamic Dependencies Between Tasks
|
|
132
|
+
|
|
133
|
+
```ruby
|
|
134
|
+
class FeatureFlags < Taski::Task
|
|
135
|
+
define :use_new_algorithm, -> {
|
|
136
|
+
ENV['USE_NEW_ALGORITHM'] == 'true'
|
|
137
|
+
}
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
class DataProcessor < Taski::Task
|
|
141
|
+
define :algorithm, -> {
|
|
142
|
+
FeatureFlags.use_new_algorithm ? 'v2' : 'v1'
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
def run
|
|
146
|
+
puts "Using algorithm: #{algorithm}"
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
ENV['USE_NEW_ALGORITHM'] = 'false'
|
|
151
|
+
DataProcessor.run
|
|
152
|
+
# => Using algorithm: v1
|
|
153
|
+
|
|
154
|
+
ENV['USE_NEW_ALGORITHM'] = 'true'
|
|
155
|
+
DataProcessor.reset!
|
|
156
|
+
DataProcessor.run
|
|
157
|
+
# => Using algorithm: v2
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### Forward References with ref()
|
|
161
|
+
|
|
162
|
+
Use `ref()` when you need to reference a class that's defined later:
|
|
163
|
+
|
|
164
|
+
```ruby
|
|
165
|
+
class EarlyTask < Taski::Task
|
|
166
|
+
define :config, -> {
|
|
167
|
+
ref("LaterTask").settings
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
def run
|
|
171
|
+
puts "Early task using: #{config}"
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
class LaterTask < Taski::Task
|
|
176
|
+
exports :settings
|
|
177
|
+
|
|
178
|
+
def run
|
|
179
|
+
@settings = "late-configuration"
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
EarlyTask.run
|
|
184
|
+
# => Early task using: late-configuration
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
**Important**: Use `ref()` sparingly. Prefer direct class references when possible:
|
|
188
|
+
|
|
189
|
+
```ruby
|
|
190
|
+
# ✅ Preferred
|
|
191
|
+
define :config, -> { LaterTask.settings }
|
|
192
|
+
|
|
193
|
+
# ⚠️ Only when forward declaration needed
|
|
194
|
+
define :config, -> { ref("LaterTask").settings }
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### When to Use Define API
|
|
198
|
+
|
|
199
|
+
- **Environment-specific logic**: Different behavior per environment
|
|
200
|
+
- **Feature flags**: Conditional functionality
|
|
201
|
+
- **Runtime configuration**: Values that change based on current state
|
|
202
|
+
- **No side effects**: Pure computation only
|
|
203
|
+
|
|
204
|
+
## Section API - Abstraction Layers
|
|
205
|
+
|
|
206
|
+
The Section API provides runtime implementation selection with static analysis support.
|
|
207
|
+
|
|
208
|
+
### Basic Usage
|
|
209
|
+
|
|
210
|
+
```ruby
|
|
211
|
+
class DatabaseSection < Taski::Section
|
|
212
|
+
interface :host, :port, :connection_string
|
|
213
|
+
|
|
214
|
+
def impl
|
|
215
|
+
case ENV['RAILS_ENV']
|
|
216
|
+
when 'production'
|
|
217
|
+
ProductionDB
|
|
218
|
+
when 'test'
|
|
219
|
+
TestDB
|
|
220
|
+
else
|
|
221
|
+
DevelopmentDB
|
|
222
|
+
end
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
class ProductionDB < Taski::Task
|
|
226
|
+
def run
|
|
227
|
+
@host = "prod-db.example.com"
|
|
228
|
+
@port = 5432
|
|
229
|
+
@connection_string = "postgresql://#{@host}:#{@port}/myapp_production"
|
|
230
|
+
end
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
class TestDB < Taski::Task
|
|
234
|
+
def run
|
|
235
|
+
@host = ":memory:"
|
|
236
|
+
@port = nil
|
|
237
|
+
@connection_string = "sqlite3::memory:"
|
|
238
|
+
end
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
class DevelopmentDB < Taski::Task
|
|
242
|
+
def run
|
|
243
|
+
@host = "localhost"
|
|
244
|
+
@port = 5432
|
|
245
|
+
@connection_string = "postgresql://#{@host}:#{@port}/myapp_development"
|
|
246
|
+
end
|
|
247
|
+
end
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
class Application < Taski::Task
|
|
251
|
+
def run
|
|
252
|
+
puts "Connecting to: #{DatabaseSection.connection_string}"
|
|
253
|
+
puts "Host: #{DatabaseSection.host}, Port: #{DatabaseSection.port}"
|
|
254
|
+
end
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
ENV['RAILS_ENV'] = 'development'
|
|
258
|
+
Application.run
|
|
259
|
+
# => Connecting to: postgresql://localhost:5432/myapp_development
|
|
260
|
+
# => Host: localhost, Port: 5432
|
|
261
|
+
|
|
262
|
+
ENV['RAILS_ENV'] = 'production'
|
|
263
|
+
DatabaseSection.reset!
|
|
264
|
+
Application.run
|
|
265
|
+
# => Connecting to: postgresql://prod-db.example.com:5432/myapp_production
|
|
266
|
+
# => Host: prod-db.example.com, Port: 5432
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
### Complex Section Hierarchies
|
|
270
|
+
|
|
271
|
+
```ruby
|
|
272
|
+
class LoggingSection < Taski::Section
|
|
273
|
+
interface :logger, :level
|
|
274
|
+
|
|
275
|
+
def impl
|
|
276
|
+
ENV['LOG_FORMAT'] == 'json' ? JsonLogging : SimpleLogging
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
class JsonLogging < Taski::Task
|
|
280
|
+
def run
|
|
281
|
+
@logger = "JsonLogger"
|
|
282
|
+
@level = "INFO"
|
|
283
|
+
end
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
class SimpleLogging < Taski::Task
|
|
287
|
+
def run
|
|
288
|
+
@logger = "SimpleLogger"
|
|
289
|
+
@level = "DEBUG"
|
|
290
|
+
end
|
|
291
|
+
end
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
class ServiceSection < Taski::Section
|
|
295
|
+
interface :api_endpoint, :timeout
|
|
296
|
+
|
|
297
|
+
def impl
|
|
298
|
+
ENV['SERVICE_MODE'] == 'mock' ? MockService : RealService
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
class MockService < Taski::Task
|
|
302
|
+
def run
|
|
303
|
+
@api_endpoint = "http://localhost:3000/mock"
|
|
304
|
+
@timeout = 1
|
|
305
|
+
end
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
class RealService < Taski::Task
|
|
309
|
+
def run
|
|
310
|
+
@api_endpoint = LoggingSection.level == 'DEBUG' ?
|
|
311
|
+
"https://api-debug.example.com" :
|
|
312
|
+
"https://api.example.com"
|
|
313
|
+
@timeout = 30
|
|
314
|
+
end
|
|
315
|
+
end
|
|
316
|
+
end
|
|
317
|
+
|
|
318
|
+
class MainApp < Taski::Task
|
|
319
|
+
def run
|
|
320
|
+
puts "Logger: #{LoggingSection.logger} (#{LoggingSection.level})"
|
|
321
|
+
puts "API: #{ServiceSection.api_endpoint} (timeout: #{ServiceSection.timeout}s)"
|
|
322
|
+
end
|
|
323
|
+
end
|
|
324
|
+
|
|
325
|
+
ENV['LOG_FORMAT'] = 'simple'
|
|
326
|
+
ENV['SERVICE_MODE'] = 'real'
|
|
327
|
+
MainApp.run
|
|
328
|
+
# => Logger: SimpleLogger (DEBUG)
|
|
329
|
+
# => API: https://api-debug.example.com (timeout: 30s)
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
### When to Use Section API
|
|
333
|
+
|
|
334
|
+
- **Implementation abstraction**: Different adapters or strategies
|
|
335
|
+
- **Environment-specific implementations**: Dev/test/prod variations
|
|
336
|
+
- **Conditional implementations**: Based on runtime state
|
|
337
|
+
- **Clean interfaces**: When you want to hide implementation details
|
|
338
|
+
|
|
339
|
+
## API Comparison
|
|
340
|
+
|
|
341
|
+
| Feature | Exports API | Define API | Section API |
|
|
342
|
+
|---------|-------------|------------|-------------|
|
|
343
|
+
| **Side Effects** | ✅ Allowed | ❌ Not allowed | ✅ Allowed |
|
|
344
|
+
| **Static Analysis** | ✅ Full support | ✅ Full support | ✅ Full support |
|
|
345
|
+
| **Runtime Selection** | ❌ No | ✅ Limited | ✅ Full support |
|
|
346
|
+
| **Interface Definition** | ❌ No | ❌ No | ✅ Yes |
|
|
347
|
+
| **Caching** | ✅ Yes | ✅ Yes | ✅ Yes |
|
|
348
|
+
| **Reset Support** | ✅ Yes | ✅ Yes | ✅ Yes |
|
|
349
|
+
|
|
350
|
+
## Best Practices
|
|
351
|
+
|
|
352
|
+
### 1. Choose the Right API
|
|
353
|
+
|
|
354
|
+
```ruby
|
|
355
|
+
# ✅ Good: Static configuration with Exports
|
|
356
|
+
class Config < Taski::Task
|
|
357
|
+
exports :app_name, :version
|
|
358
|
+
def run
|
|
359
|
+
@app_name = "MyApp"
|
|
360
|
+
@version = "1.0.0"
|
|
361
|
+
end
|
|
362
|
+
end
|
|
363
|
+
|
|
364
|
+
# ✅ Good: Environment logic with Define
|
|
365
|
+
class EnvConfig < Taski::Task
|
|
366
|
+
define :debug_mode, -> { ENV['DEBUG'] == 'true' }
|
|
367
|
+
end
|
|
368
|
+
|
|
369
|
+
# ✅ Good: Implementation selection with Section
|
|
370
|
+
class DatabaseSection < Taski::Section
|
|
371
|
+
interface :connection
|
|
372
|
+
def impl
|
|
373
|
+
production? ? PostgreSQL : SQLite
|
|
374
|
+
end
|
|
375
|
+
end
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
### 2. Minimize ref() Usage
|
|
379
|
+
|
|
380
|
+
```ruby
|
|
381
|
+
# ✅ Preferred: Direct reference
|
|
382
|
+
class TaskB < Taski::Task
|
|
383
|
+
exports :value
|
|
384
|
+
def run; @value = "hello"; end
|
|
385
|
+
end
|
|
386
|
+
|
|
387
|
+
class TaskA < Taski::Task
|
|
388
|
+
define :result, -> { TaskB.value.upcase }
|
|
389
|
+
end
|
|
390
|
+
|
|
391
|
+
# ⚠️ Only when necessary: Forward reference
|
|
392
|
+
class TaskA < Taski::Task
|
|
393
|
+
define :result, -> { ref("TaskB").value.upcase }
|
|
394
|
+
end
|
|
395
|
+
|
|
396
|
+
class TaskB < Taski::Task
|
|
397
|
+
exports :value
|
|
398
|
+
def run; @value = "hello"; end
|
|
399
|
+
end
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
### 3. Keep Define Blocks Pure
|
|
403
|
+
|
|
404
|
+
```ruby
|
|
405
|
+
# ✅ Good: Pure computation
|
|
406
|
+
define :config_path, -> {
|
|
407
|
+
ENV['CONFIG_PATH'] || '/etc/myapp/config.yml'
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
# ❌ Bad: Side effects
|
|
411
|
+
define :config, -> {
|
|
412
|
+
File.read('/etc/config.yml') # File I/O is a side effect
|
|
413
|
+
}
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
### 4. Use Clear Interface Definitions
|
|
417
|
+
|
|
418
|
+
```ruby
|
|
419
|
+
# ✅ Good: Clear interface
|
|
420
|
+
class DatabaseSection < Taski::Section
|
|
421
|
+
interface :host, :port, :username, :password, :database
|
|
422
|
+
|
|
423
|
+
# Implementation classes follow interface
|
|
424
|
+
end
|
|
425
|
+
|
|
426
|
+
# ❌ Bad: Unclear interface
|
|
427
|
+
class DatabaseSection < Taski::Section
|
|
428
|
+
# No interface definition - unclear what's available
|
|
429
|
+
end
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
## Advanced Patterns
|
|
433
|
+
|
|
434
|
+
### Conditional Dependencies
|
|
435
|
+
|
|
436
|
+
```ruby
|
|
437
|
+
class OptionalService < Taski::Task
|
|
438
|
+
define :enabled, -> { ENV['OPTIONAL_SERVICE'] == 'true' }
|
|
439
|
+
|
|
440
|
+
def run
|
|
441
|
+
if enabled
|
|
442
|
+
puts "Optional service is enabled"
|
|
443
|
+
else
|
|
444
|
+
puts "Optional service is disabled"
|
|
445
|
+
end
|
|
446
|
+
end
|
|
447
|
+
end
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
### Dependency Injection
|
|
451
|
+
|
|
452
|
+
```ruby
|
|
453
|
+
class ServiceSection < Taski::Section
|
|
454
|
+
interface :client
|
|
455
|
+
|
|
456
|
+
def impl
|
|
457
|
+
case ENV['SERVICE_PROVIDER']
|
|
458
|
+
when 'aws' then AWSService
|
|
459
|
+
when 'gcp' then GCPService
|
|
460
|
+
else LocalService
|
|
461
|
+
end
|
|
462
|
+
end
|
|
463
|
+
|
|
464
|
+
class AWSService < Taski::Task
|
|
465
|
+
def run; @client = "AWS Client"; end
|
|
466
|
+
end
|
|
467
|
+
|
|
468
|
+
class GCPService < Taski::Task
|
|
469
|
+
def run; @client = "GCP Client"; end
|
|
470
|
+
end
|
|
471
|
+
|
|
472
|
+
class LocalService < Taski::Task
|
|
473
|
+
def run; @client = "Local Client"; end
|
|
474
|
+
end
|
|
475
|
+
end
|
|
476
|
+
```
|
|
477
|
+
|
|
478
|
+
### Mixed API Usage
|
|
479
|
+
|
|
480
|
+
```ruby
|
|
481
|
+
class Config < Taski::Task
|
|
482
|
+
exports :base_url
|
|
483
|
+
def run; @base_url = "https://api.example.com"; end
|
|
484
|
+
end
|
|
485
|
+
|
|
486
|
+
class ApiSection < Taski::Section
|
|
487
|
+
interface :endpoint
|
|
488
|
+
|
|
489
|
+
def impl
|
|
490
|
+
ENV['API_VERSION'] == 'v2' ? ApiV2 : ApiV1
|
|
491
|
+
end
|
|
492
|
+
|
|
493
|
+
class ApiV1 < Taski::Task
|
|
494
|
+
def run
|
|
495
|
+
@endpoint = "#{Config.base_url}/v1"
|
|
496
|
+
end
|
|
497
|
+
end
|
|
498
|
+
|
|
499
|
+
class ApiV2 < Taski::Task
|
|
500
|
+
define :version_suffix, -> { ENV['BETA'] == 'true' ? '-beta' : '' }
|
|
501
|
+
|
|
502
|
+
def run
|
|
503
|
+
@endpoint = "#{Config.base_url}/v2#{version_suffix}"
|
|
504
|
+
end
|
|
505
|
+
end
|
|
506
|
+
end
|
|
507
|
+
```
|
|
508
|
+
|
|
509
|
+
This combination shows how all three APIs can work together in a single application.
|