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.
Files changed (119) hide show
  1. checksums.yaml +4 -4
  2. data/.gem_rbs_collection/ast/2.4/.rbs_meta.yaml +9 -0
  3. data/.gem_rbs_collection/ast/2.4/ast.rbs +73 -0
  4. data/.gem_rbs_collection/minitest/5.25/.rbs_meta.yaml +9 -0
  5. data/.gem_rbs_collection/minitest/5.25/minitest/abstract_reporter.rbs +52 -0
  6. data/.gem_rbs_collection/minitest/5.25/minitest/assertion.rbs +17 -0
  7. data/.gem_rbs_collection/minitest/5.25/minitest/assertions.rbs +590 -0
  8. data/.gem_rbs_collection/minitest/5.25/minitest/backtrace_filter.rbs +23 -0
  9. data/.gem_rbs_collection/minitest/5.25/minitest/bench_spec.rbs +102 -0
  10. data/.gem_rbs_collection/minitest/5.25/minitest/benchmark.rbs +259 -0
  11. data/.gem_rbs_collection/minitest/5.25/minitest/composite_reporter.rbs +25 -0
  12. data/.gem_rbs_collection/minitest/5.25/minitest/compress.rbs +13 -0
  13. data/.gem_rbs_collection/minitest/5.25/minitest/error_on_warning.rbs +3 -0
  14. data/.gem_rbs_collection/minitest/5.25/minitest/expectation.rbs +2 -0
  15. data/.gem_rbs_collection/minitest/5.25/minitest/expectations.rbs +21 -0
  16. data/.gem_rbs_collection/minitest/5.25/minitest/guard.rbs +64 -0
  17. data/.gem_rbs_collection/minitest/5.25/minitest/mock.rbs +64 -0
  18. data/.gem_rbs_collection/minitest/5.25/minitest/parallel/executor.rbs +46 -0
  19. data/.gem_rbs_collection/minitest/5.25/minitest/parallel/test/class_methods.rbs +5 -0
  20. data/.gem_rbs_collection/minitest/5.25/minitest/parallel/test.rbs +3 -0
  21. data/.gem_rbs_collection/minitest/5.25/minitest/parallel.rbs +2 -0
  22. data/.gem_rbs_collection/minitest/5.25/minitest/pride_io.rbs +62 -0
  23. data/.gem_rbs_collection/minitest/5.25/minitest/pride_lol.rbs +19 -0
  24. data/.gem_rbs_collection/minitest/5.25/minitest/progress_reporter.rbs +11 -0
  25. data/.gem_rbs_collection/minitest/5.25/minitest/reportable.rbs +53 -0
  26. data/.gem_rbs_collection/minitest/5.25/minitest/reporter.rbs +5 -0
  27. data/.gem_rbs_collection/minitest/5.25/minitest/result.rbs +28 -0
  28. data/.gem_rbs_collection/minitest/5.25/minitest/runnable.rbs +163 -0
  29. data/.gem_rbs_collection/minitest/5.25/minitest/skip.rbs +6 -0
  30. data/.gem_rbs_collection/minitest/5.25/minitest/spec/dsl/instance_methods.rbs +48 -0
  31. data/.gem_rbs_collection/minitest/5.25/minitest/spec/dsl.rbs +129 -0
  32. data/.gem_rbs_collection/minitest/5.25/minitest/spec.rbs +11 -0
  33. data/.gem_rbs_collection/minitest/5.25/minitest/statistics_reporter.rbs +81 -0
  34. data/.gem_rbs_collection/minitest/5.25/minitest/summary_reporter.rbs +18 -0
  35. data/.gem_rbs_collection/minitest/5.25/minitest/test/lifecycle_hooks.rbs +92 -0
  36. data/.gem_rbs_collection/minitest/5.25/minitest/test.rbs +69 -0
  37. data/.gem_rbs_collection/minitest/5.25/minitest/unexpected_error.rbs +12 -0
  38. data/.gem_rbs_collection/minitest/5.25/minitest/unexpected_warning.rbs +6 -0
  39. data/.gem_rbs_collection/minitest/5.25/minitest/unit/test_case.rbs +3 -0
  40. data/.gem_rbs_collection/minitest/5.25/minitest/unit.rbs +4 -0
  41. data/.gem_rbs_collection/minitest/5.25/minitest.rbs +115 -0
  42. data/.gem_rbs_collection/parallel/1.20/.rbs_meta.yaml +9 -0
  43. data/.gem_rbs_collection/parallel/1.20/parallel.rbs +86 -0
  44. data/.gem_rbs_collection/parser/3.2/.rbs_meta.yaml +9 -0
  45. data/.gem_rbs_collection/parser/3.2/manifest.yaml +7 -0
  46. data/.gem_rbs_collection/parser/3.2/parser.rbs +193 -0
  47. data/.gem_rbs_collection/parser/3.2/polyfill.rbs +4 -0
  48. data/.gem_rbs_collection/rainbow/3.0/.rbs_meta.yaml +9 -0
  49. data/.gem_rbs_collection/rainbow/3.0/global.rbs +7 -0
  50. data/.gem_rbs_collection/rainbow/3.0/presenter.rbs +209 -0
  51. data/.gem_rbs_collection/rainbow/3.0/rainbow.rbs +5 -0
  52. data/.gem_rbs_collection/rake/13.0/.rbs_meta.yaml +9 -0
  53. data/.gem_rbs_collection/rake/13.0/manifest.yaml +2 -0
  54. data/.gem_rbs_collection/rake/13.0/rake.rbs +39 -0
  55. data/.gem_rbs_collection/regexp_parser/2.8/.rbs_meta.yaml +9 -0
  56. data/.gem_rbs_collection/regexp_parser/2.8/regexp_parser.rbs +17 -0
  57. data/.gem_rbs_collection/rubocop/1.57/.rbs_meta.yaml +9 -0
  58. data/.gem_rbs_collection/rubocop/1.57/rubocop.rbs +129 -0
  59. data/.gem_rbs_collection/rubocop-ast/1.30/.rbs_meta.yaml +9 -0
  60. data/.gem_rbs_collection/rubocop-ast/1.30/rubocop-ast.rbs +771 -0
  61. data/.gem_rbs_collection/simplecov/0.22/.rbs_meta.yaml +9 -0
  62. data/.gem_rbs_collection/simplecov/0.22/simplecov.rbs +54 -0
  63. data/README.md +138 -247
  64. data/Steepfile +19 -0
  65. data/docs/advanced-features.md +625 -0
  66. data/docs/api-guide.md +509 -0
  67. data/docs/error-handling.md +684 -0
  68. data/examples/README.md +95 -42
  69. data/examples/context_demo.rb +112 -0
  70. data/examples/data_pipeline_demo.rb +231 -0
  71. data/examples/parallel_progress_demo.rb +72 -0
  72. data/examples/quick_start.rb +4 -4
  73. data/examples/reexecution_demo.rb +127 -0
  74. data/examples/{section_configuration.rb → section_demo.rb} +49 -60
  75. data/lib/taski/context.rb +52 -0
  76. data/lib/taski/execution/coordinator.rb +63 -0
  77. data/lib/taski/execution/parallel_progress_display.rb +201 -0
  78. data/lib/taski/execution/registry.rb +72 -0
  79. data/lib/taski/execution/task_wrapper.rb +255 -0
  80. data/lib/taski/section.rb +26 -254
  81. data/lib/taski/static_analysis/analyzer.rb +34 -0
  82. data/lib/taski/static_analysis/dependency_graph.rb +90 -0
  83. data/lib/taski/static_analysis/visitor.rb +114 -0
  84. data/lib/taski/task.rb +173 -0
  85. data/lib/taski/version.rb +1 -1
  86. data/lib/taski.rb +45 -39
  87. data/rbs_collection.lock.yaml +116 -0
  88. data/rbs_collection.yaml +19 -0
  89. data/sig/taski.rbs +269 -62
  90. metadata +97 -32
  91. data/examples/advanced_patterns.rb +0 -119
  92. data/examples/progress_demo.rb +0 -166
  93. data/examples/tree_demo.rb +0 -205
  94. data/lib/taski/dependency_analyzer.rb +0 -232
  95. data/lib/taski/exceptions.rb +0 -17
  96. data/lib/taski/logger.rb +0 -158
  97. data/lib/taski/logging/formatter_factory.rb +0 -34
  98. data/lib/taski/logging/formatter_interface.rb +0 -19
  99. data/lib/taski/logging/json_formatter.rb +0 -26
  100. data/lib/taski/logging/simple_formatter.rb +0 -16
  101. data/lib/taski/logging/structured_formatter.rb +0 -44
  102. data/lib/taski/progress/display_colors.rb +0 -17
  103. data/lib/taski/progress/display_manager.rb +0 -117
  104. data/lib/taski/progress/output_capture.rb +0 -105
  105. data/lib/taski/progress/spinner_animation.rb +0 -49
  106. data/lib/taski/progress/task_formatter.rb +0 -25
  107. data/lib/taski/progress/task_status.rb +0 -38
  108. data/lib/taski/progress/terminal_controller.rb +0 -35
  109. data/lib/taski/progress_display.rb +0 -57
  110. data/lib/taski/reference.rb +0 -40
  111. data/lib/taski/task/base.rb +0 -91
  112. data/lib/taski/task/define_api.rb +0 -156
  113. data/lib/taski/task/dependency_resolver.rb +0 -73
  114. data/lib/taski/task/exports_api.rb +0 -29
  115. data/lib/taski/task/instance_management.rb +0 -201
  116. data/lib/taski/tree_colors.rb +0 -91
  117. data/lib/taski/utils/dependency_resolver_helper.rb +0 -85
  118. data/lib/taski/utils/tree_display_helper.rb +0 -68
  119. data/lib/taski/utils.rb +0 -107
@@ -0,0 +1,9 @@
1
+ ---
2
+ name: simplecov
3
+ version: '0.22'
4
+ source:
5
+ type: git
6
+ name: ruby/gem_rbs_collection
7
+ revision: 3a33fa6f8e486f880c80ca401f2be1c1f621cf11
8
+ remote: https://github.com/ruby/gem_rbs_collection.git
9
+ repo_dir: gems
@@ -0,0 +1,54 @@
1
+ module SimpleCov
2
+ extend Configuration
3
+
4
+ VERSION: String
5
+
6
+ def self.collate: (Array[String] result_filenames) -> void
7
+
8
+ def self.start: (?(String | Symbol | nil) profile) ?{ [self: Configuration] -> void } -> void
9
+
10
+ module Configuration
11
+ type filter = String
12
+ | Regexp
13
+ | Filter[untyped]
14
+ | ^(SourceFile source_file) -> boolish
15
+ | Array[filter]
16
+
17
+ type criterion = :line | :branch
18
+
19
+ def add_filter: (filter filter_argument) -> void
20
+ | { (SourceFile source_file) -> boolish } -> void
21
+
22
+ def add_group: (String group_name, filter filter_argument) -> untyped
23
+ | (String group_name) { (SourceFile source_file) -> boolish } -> void
24
+
25
+ def command_name: (String name) -> void
26
+
27
+ def enable_coverage: (criterion criterion) -> void
28
+
29
+ def enable_coverage_for_eval: () -> void
30
+
31
+ def filters: () -> Array[Filter[untyped]]
32
+
33
+ def primary_coverage: (criterion criterion) -> void
34
+
35
+ def root: (?String? root) -> String?
36
+ end
37
+
38
+ class SourceFile
39
+ attr_reader filename: String?
40
+
41
+ def lines: () -> Array[Line]
42
+
43
+ class Line
44
+ end
45
+ end
46
+
47
+ class Filter[T]
48
+ attr_reader filter_argument: T
49
+
50
+ def initialize: (T filter_argument) -> void
51
+
52
+ def matches?: (SourceFile source_file) -> boolish
53
+ end
54
+ end
data/README.md CHANGED
@@ -6,331 +6,220 @@
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 three APIs: static dependencies through **Exports**, dynamic dependencies through **Define**, and abstraction layers through **Section**.
9
+ **Taski** is a Ruby framework for building task dependency graphs with automatic resolution and **parallel execution**.
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
 
13
+ ## Why Taski?
14
+
15
+ Build complex workflows by defining tasks and their dependencies - Taski automatically resolves execution order and executes them in parallel.
16
+
17
+ - **Automatic Dependency Resolution**: Dependencies detected via static analysis
18
+ - **Parallel Execution**: Independent tasks run concurrently for maximum performance
19
+ - **Two Simple APIs**: Exports (value sharing) and Section (runtime selection)
20
+ - **Real-time Progress**: Visual feedback with parallel task progress display
21
+ - **Thread-Safe**: Built on Monitor-based synchronization for reliable concurrent execution
22
+
13
23
  ## 🚀 Quick Start
14
24
 
15
25
  ```ruby
16
26
  require 'taski'
17
27
 
18
- # Static dependency using Exports API
28
+ # Define tasks with dependencies
19
29
  class DatabaseSetup < Taski::Task
20
30
  exports :connection_string
21
31
 
22
- def build
32
+ def run
23
33
  @connection_string = "postgresql://localhost/myapp"
24
34
  puts "Database configured"
25
35
  end
26
36
  end
27
37
 
38
+ class CacheSetup < Taski::Task
39
+ exports :cache_url
40
+
41
+ def run
42
+ @cache_url = "redis://localhost:6379"
43
+ puts "Cache configured"
44
+ end
45
+ end
46
+
28
47
  class APIServer < Taski::Task
29
- def build
48
+ def run
49
+ # Dependencies execute automatically and in parallel
30
50
  puts "Starting API with #{DatabaseSetup.connection_string}"
51
+ puts "Using cache at #{CacheSetup.cache_url}"
31
52
  end
32
53
  end
33
54
 
34
- APIServer.build
55
+ # Run any task - dependencies resolve and execute in parallel
56
+ APIServer.run
35
57
  # => Database configured
58
+ # => Cache configured
36
59
  # => Starting API with postgresql://localhost/myapp
60
+ # => Using cache at redis://localhost:6379
37
61
  ```
38
62
 
39
- ## 📚 API Guide
40
-
41
- ### Exports API - Static Dependencies
63
+ ## Core Concepts
42
64
 
43
- For simple, predictable dependencies:
65
+ Taski provides two complementary APIs:
44
66
 
67
+ ### 1. Exports API - Value Sharing Between Tasks
45
68
  ```ruby
46
- class ConfigLoader < Taski::Task
47
- exports :app_name, :version
69
+ class Config < Taski::Task
70
+ exports :app_name, :port
48
71
 
49
- def build
72
+ def run
50
73
  @app_name = "MyApp"
51
- @version = "1.0.0"
52
- puts "Config loaded: #{@app_name} v#{@version}"
74
+ @port = 3000
53
75
  end
54
76
  end
55
77
 
56
- class Deployment < Taski::Task
57
- def build
58
- @deploy_url = "https://#{ConfigLoader.app_name}.example.com"
59
- puts "Deploying to #{@deploy_url}"
78
+ class Server < Taski::Task
79
+ def run
80
+ # Automatically depends on Config task
81
+ puts "Starting #{Config.app_name} on port #{Config.port}"
60
82
  end
61
83
  end
62
-
63
- Deployment.build
64
- # => Config loaded: MyApp v1.0.0
65
- # => Deploying to https://MyApp.example.com
66
- ```
67
-
68
- ### Define API - Dynamic Dependencies
69
-
70
- For dependencies that change based on runtime conditions:
71
-
72
- ```ruby
73
- class EnvironmentConfig < Taski::Task
74
- define :database_service, -> {
75
- case ENV['RAILS_ENV']
76
- when 'production'
77
- "production-db.example.com"
78
- else
79
- "localhost:5432"
80
- end
81
- }
82
-
83
- def build
84
- puts "Using database: #{database_service}"
85
- puts "Environment: #{ENV['RAILS_ENV'] || 'development'}"
86
- end
87
- end
88
-
89
- EnvironmentConfig.build
90
- # => Using database: localhost:5432
91
- # => Environment: development
92
-
93
- ENV['RAILS_ENV'] = 'production'
94
- EnvironmentConfig.reset!
95
- EnvironmentConfig.build
96
- # => Using database: production-db.example.com
97
- # => Environment: production
98
84
  ```
99
85
 
100
- ### Section API - Abstraction Layers
101
-
102
- For environment-specific implementations with clean interfaces:
103
-
86
+ ### 2. Section API - Runtime Implementation Selection
104
87
  ```ruby
105
88
  class DatabaseSection < Taski::Section
106
- interface :host, :port
107
-
108
- def impl
109
- ENV['RAILS_ENV'] == 'production' ? Production : Development
110
- end
89
+ interfaces :host, :port
111
90
 
112
- class Production < Taski::Task
113
- def build
114
- @host = "prod-db.example.com"
91
+ # Nested classes automatically inherit interfaces - no exports needed
92
+ class ProductionDB < Taski::Task
93
+ def run
94
+ @host = "prod.example.com"
115
95
  @port = 5432
116
96
  end
117
97
  end
118
98
 
119
- class Development < Taski::Task
120
- def build
99
+ class LocalDB < Taski::Task
100
+ def run
121
101
  @host = "localhost"
122
102
  @port = 5432
123
103
  end
124
104
  end
125
- end
126
105
 
127
- # Usage is simple - Section works like any Task
128
- class App < Taski::Task
129
- def build
130
- puts "DB: #{DatabaseSection.host}:#{DatabaseSection.port}"
131
- end
132
- end
133
-
134
- App.build # => DB: localhost:5432
135
- ```
136
-
137
- ### When to Use Each API
138
-
139
- - **Define API**: Best for dynamic runtime dependencies. Cannot contain side effects in definition blocks. Dependencies are analyzed at class definition time, not runtime.
140
- - **Exports API**: Ideal for static dependencies. Supports side effects in build methods.
141
- - **Section API**: Perfect for abstraction layers where you need different implementations based on runtime conditions while maintaining static analysis capabilities.
142
-
143
- | Use Case | API | Example |
144
- |----------|-----|---------|
145
- | Configuration values | Exports | File paths, settings |
146
- | Environment-specific logic | Define/Section | Different services per env |
147
- | Side effects | Exports | Database connections, I/O |
148
- | Conditional processing | Define | Algorithm selection |
149
- | Implementation abstraction | Section | Database/API adapters |
150
- | Multi-environment configs | Section | Dev/Test/Prod settings |
151
-
152
- **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.
153
-
154
- ## ✨ Key Features
155
-
156
- - **Automatic Dependency Resolution**: Dependencies detected through static analysis
157
- - **Thread-Safe**: Safe for concurrent access
158
- - **Circular Dependency Detection**: Clear error messages with detailed paths
159
- - **Granular Execution**: Build individual tasks or complete graphs
160
- - **Memory Management**: Built-in reset mechanisms
161
- - **Progress Display**: Visual feedback with spinners and output capture
162
- - **Dependency Tree Visualization**: Visual representation of task relationships
163
-
164
- ### Dependency Tree Visualization
165
-
166
- Visualize task dependencies with the `tree` method:
167
-
168
- ```ruby
169
- class Database < Taski::Task
170
- exports :connection
171
- def build; @connection = "db-conn"; end
172
- end
173
-
174
- class Cache < Taski::Task
175
- exports :redis_url
176
- def build; @redis_url = "redis://localhost"; end
177
- end
178
-
179
- class Config < Taski::Task
180
- exports :settings
181
- def build
182
- @settings = {
183
- database: Database.connection,
184
- cache: Cache.redis_url
185
- }
106
+ def impl
107
+ # Select implementation at runtime
108
+ ENV['RAILS_ENV'] == 'production' ? ProductionDB : LocalDB
186
109
  end
187
110
  end
188
111
 
189
- class WebServer < Taski::Task
190
- def build
191
- puts "Starting with #{Config.settings}"
112
+ class App < Taski::Task
113
+ def run
114
+ # Access through Section - implementation selected at runtime
115
+ puts "Connecting to #{DatabaseSection.host}:#{DatabaseSection.port}"
192
116
  end
193
117
  end
194
118
 
195
- puts WebServer.tree
196
- # => WebServer
197
- # => └── Config
198
- # => ├── Database
199
- # => └── Cache
119
+ App.run
120
+ # In development (RAILS_ENV != 'production'):
121
+ # => Connecting to localhost:5432
200
122
 
201
- # Sections also appear in dependency trees
202
- puts AppServer.tree
203
- # => AppServer
204
- # => └── DatabaseSection
123
+ # In production (RAILS_ENV == 'production'):
124
+ # => Connecting to prod.example.com:5432
205
125
  ```
206
126
 
207
- ### Progress Display
127
+ **When to use each:**
128
+ - **Exports**: Share computed values or side effects between tasks
129
+ - **Section**: Switch implementations based on environment or conditions
130
+
131
+ > **Note**: When implementation classes are nested inside a Section, they automatically inherit the Section's `interfaces` as `exports`. External implementations must declare `exports` explicitly.
132
+
133
+ ### 3. Context - Runtime Information Access
208
134
 
209
- Taski provides visual feedback during task execution with animated spinners and real-time output capture:
135
+ Access execution context information from any task:
210
136
 
211
137
  ```ruby
212
- class LongRunningTask < Taski::Task
213
- def build
214
- puts "Starting process..."
215
- sleep(1.0)
216
- puts "Processing data..."
217
- puts "Almost done..."
218
- sleep(0.5)
219
- puts "Completed!"
138
+ class DeployTask < Taski::Task
139
+ def run
140
+ puts "Working directory: #{Taski::Context.working_directory}"
141
+ puts "Started at: #{Taski::Context.started_at}"
142
+ puts "Root task: #{Taski::Context.root_task}"
220
143
  end
221
144
  end
222
-
223
- LongRunningTask.build
224
- # During execution shows:
225
- # ⠧ LongRunningTask
226
- # Starting process...
227
- # Processing data...
228
- # Almost done...
229
- # Completed!
230
- #
231
- # After completion shows:
232
- # ✅ LongRunningTask (1500ms)
233
145
  ```
234
146
 
235
- **Progress Display Features:**
236
- - **Spinner Animation**: Dots-style spinner during task execution
237
- - **Output Capture**: Real-time display of task output (last 5 lines)
238
- - **Status Indicators**: for success, for failure
239
- - **Execution Time**: Shows task duration after completion
240
- - **TTY Detection**: Clean output when redirected to files
241
-
242
- ### Granular Task Execution
147
+ **Available context:**
148
+ - `working_directory`: Directory where execution started
149
+ - `started_at`: Time when execution began
150
+ - `root_task`: The first task class that was called
243
151
 
244
- Execute any task individually - Taski builds only required dependencies:
152
+ > **Note**: Context is not included in dependency analysis - it provides runtime information only.
245
153
 
246
- ```ruby
247
- # Build specific components
248
- ConfigLoader.build # Builds only ConfigLoader
249
- # => Config loaded: MyApp v1.0.0
250
-
251
- EnvironmentConfig.build # Builds EnvironmentConfig and its dependencies
252
- # => Using database: localhost:5432
253
- # => Environment: development
154
+ > **Important**: Tasks must be defined in source files, not dynamically with `Class.new`. Static analysis requires actual source files to detect dependencies.
254
155
 
255
- # Access values (triggers build if needed)
256
- puts ConfigLoader.version # Builds ConfigLoader if not built
257
- # => 1.0.0
258
- ```
156
+ ### 4. Re-execution with `new`
259
157
 
260
- ### Lifecycle Management
261
-
262
- Tasks can define both build and clean methods. Clean operations run in reverse dependency order:
158
+ By default, task results are cached. Use `new` to create a fresh instance for re-execution:
263
159
 
264
160
  ```ruby
265
- class DatabaseSetup < Taski::Task
266
- exports :connection
161
+ class RandomTask < Taski::Task
162
+ exports :value
267
163
 
268
- def build
269
- @connection = "db-connection"
270
- puts "Database connected"
271
- end
272
-
273
- def clean
274
- puts "Database disconnected"
164
+ def run
165
+ @value = rand(1000)
275
166
  end
276
167
  end
277
168
 
278
- class WebServer < Taski::Task
279
- def build
280
- puts "Web server started with #{DatabaseSetup.connection}"
281
- end
282
-
283
- def clean
284
- puts "Web server stopped"
285
- end
286
- end
169
+ # Cached execution (same result)
170
+ RandomTask.value # => 42
171
+ RandomTask.value # => 42 (cached)
287
172
 
288
- WebServer.build
289
- # => Database connected
290
- # => Web server started with db-connection
173
+ # Fresh execution with new
174
+ RandomTask.new.run # => 123 (new instance)
175
+ RandomTask.new.run # => 456 (another new instance)
291
176
 
292
- WebServer.clean
293
- # => Web server stopped
294
- # => Database disconnected
177
+ # Reset all caches
178
+ RandomTask.reset!
179
+ RandomTask.value # => 789 (fresh after reset)
295
180
  ```
296
181
 
297
- ### Clean Method Idempotency
182
+ **When to use:**
183
+ - `TaskClass.run` / `TaskClass.value`: Normal execution with caching (recommended for dependency graphs)
184
+ - `TaskClass.new.run`: Re-execute only this task (dependencies still use cache)
185
+ - `TaskClass.reset!`: Clear all caches and re-execute everything
298
186
 
299
- **Important**: The `clean` method must be idempotent - safe to call multiple times without errors.
187
+ ## Key Features
300
188
 
301
- ```ruby
302
- class FileTask < Taski::Task
303
- exports :output_file
189
+ - **Parallel Execution**: Independent tasks run concurrently using threads
190
+ - **Static Analysis**: Dependencies detected automatically via Prism AST parsing
191
+ - **Thread-Safe**: Monitor-based synchronization ensures safe concurrent access
192
+ - **Progress Display**: Real-time visual feedback with spinner animations and timing
193
+ - **Tree Visualization**: See your dependency graph structure
194
+ - **Graceful Abort**: Stop execution cleanly without starting new tasks (Ctrl+C)
195
+ - **Runtime Context**: Access execution information from any task
304
196
 
305
- def build
306
- @output_file = '/tmp/data.csv'
307
- File.write(@output_file, process_data)
308
- end
197
+ ### Parallel Progress Display
309
198
 
310
- def clean
311
- # ❌ Bad: Raises error if file doesn't exist
312
- # File.delete(@output_file)
199
+ Enable real-time progress visualization:
313
200
 
314
- # ✅ Good: Check before delete
315
- File.delete(@output_file) if File.exist?(@output_file)
316
- end
317
- end
201
+ ```bash
202
+ TASKI_FORCE_PROGRESS=1 ruby your_script.rb
318
203
  ```
319
204
 
320
- ### Error Handling
205
+ Output example:
206
+ ```
207
+ ⠋ DatabaseSetup (running)
208
+ ⠙ CacheSetup (running)
209
+ ✅ DatabaseSetup (123.4ms)
210
+ ✅ CacheSetup (98.2ms)
211
+ ⠸ WebServer (running)
212
+ ✅ WebServer (45.1ms)
213
+ ```
214
+
215
+ ### Tree Visualization
321
216
 
322
217
  ```ruby
323
- begin
324
- TaskWithCircularDep.build
325
- rescue Taski::CircularDependencyError => e
326
- puts "Circular dependency: #{e.message}"
327
- end
328
- # => Circular dependency: Circular dependency detected!
329
- # => Cycle: TaskA → TaskB → TaskA
330
- # =>
331
- # => The dependency chain is:
332
- # => 1. TaskA is trying to build → TaskB
333
- # => 2. TaskB is trying to build → TaskA
218
+ puts WebServer.tree
219
+ # => WebServer
220
+ # => └── Config
221
+ # => ├── Database
222
+ # => └── Cache
334
223
  ```
335
224
 
336
225
  ## 📦 Installation
@@ -346,19 +235,21 @@ bundle install
346
235
  ## 🧪 Testing
347
236
 
348
237
  ```bash
349
- bundle exec rake test
238
+ rake test # Run all tests
239
+ rake standard # Check code style
350
240
  ```
351
241
 
352
- ## 🏛️ Architecture
242
+ ## 📚 Learn More
353
243
 
354
- - **Task Base**: Core framework
355
- - **Exports API**: Static dependency resolution
356
- - **Define API**: Dynamic dependency resolution
357
- - **Section API**: Abstraction layer with runtime implementation selection
358
- - **Instance Management**: Thread-safe lifecycle
359
- - **Dependency Resolver**: Topological sorting with Section support
244
+ - **[Examples](examples/)**: Practical examples from basic to advanced patterns
245
+ - **[Tests](test/)**: Comprehensive test suite showing real-world usage
246
+ - **[Source Code](lib/taski/)**: Clean, well-documented implementation
247
+ - `lib/taski/task.rb` - Core Task implementation with exports API
248
+ - `lib/taski/section.rb` - Section API for runtime selection
249
+ - `lib/taski/execution/` - Parallel execution engine
250
+ - `lib/taski/static_analysis/` - Prism-based dependency analyzer
360
251
 
361
- ## Contributing
252
+ ## Support
362
253
 
363
254
  Bug reports and pull requests welcome at https://github.com/ahogappa/taski.
364
255
 
@@ -368,4 +259,4 @@ MIT License
368
259
 
369
260
  ---
370
261
 
371
- **Taski** - Build dependency graphs with elegant Ruby code. 🚀
262
+ **Taski** - Parallel task execution with automatic dependency resolution. 🚀
data/Steepfile ADDED
@@ -0,0 +1,19 @@
1
+ # Steepfile for Taski gem
2
+
3
+ target :lib do
4
+ signature "sig"
5
+
6
+ check "lib"
7
+
8
+ # Ignore test and temporary files
9
+ ignore "test"
10
+ ignore "tmp"
11
+ ignore "examples"
12
+
13
+ # Standard library dependencies
14
+ library "monitor"
15
+ library "tsort"
16
+
17
+ # Use gems from rbs_collection
18
+ collection_config "rbs_collection.yaml"
19
+ end