taski 0.2.1 → 0.2.3
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 +103 -3
- data/examples/README.md +57 -0
- data/examples/{complex_example.rb → advanced_patterns.rb} +15 -3
- data/examples/progress_demo.rb +166 -0
- data/examples/{readme_example.rb → quick_start.rb} +14 -3
- data/examples/tree_demo.rb +80 -0
- data/lib/taski/dependency_analyzer.rb +41 -9
- data/lib/taski/logger.rb +14 -3
- data/lib/taski/progress_display.rb +356 -0
- data/lib/taski/task/base.rb +51 -0
- data/lib/taski/task/define_api.rb +18 -2
- data/lib/taski/task/dependency_resolver.rb +6 -11
- data/lib/taski/task/instance_management.rb +46 -32
- data/lib/taski/utils.rb +107 -0
- data/lib/taski/version.rb +1 -1
- data/lib/taski.rb +2 -0
- metadata +10 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: da68d3dc067cdf14dd29a438cbf88cc7b00769000682417dc3395eb63f1a1659
|
4
|
+
data.tar.gz: a5ec661eeea77a73f77b07cbc09dfc4aef88fce2e856bac0366a5e32782356cc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 68b3c5ddaf63a71067fea5f3c6fdc47c80e6a020f0e7bd417f8cc03e8f595aa4a3f0b16826bf3d8a65935959ee7a243074c51db4bb766c296d25c73817fe90a8
|
7
|
+
data.tar.gz: ed2a3f80b1a5987c9a2ce8d410c6594c4edd35483a1be9507de0565582facba12e238f2862ae5964af27180431c21b3b80d00887aab8525ee89af2bfb91a507a
|
data/README.md
CHANGED
@@ -99,7 +99,7 @@ EnvironmentConfig.build
|
|
99
99
|
|
100
100
|
### When to Use Each API
|
101
101
|
|
102
|
-
- **Define API**: Best for dynamic runtime dependencies. Cannot contain side effects in definition blocks.
|
102
|
+
- **Define API**: Best for dynamic runtime dependencies. Cannot contain side effects in definition blocks. Dependencies are analyzed at class definition time, not runtime.
|
103
103
|
- **Exports API**: Ideal for static dependencies. Supports side effects in build methods.
|
104
104
|
|
105
105
|
| Use Case | API | Example |
|
@@ -109,6 +109,8 @@ EnvironmentConfig.build
|
|
109
109
|
| Side effects | Exports | Database connections, I/O |
|
110
110
|
| Conditional processing | Define | Algorithm selection |
|
111
111
|
|
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.
|
113
|
+
|
112
114
|
## ✨ Key Features
|
113
115
|
|
114
116
|
- **Automatic Dependency Resolution**: Dependencies detected through static analysis
|
@@ -116,6 +118,81 @@ EnvironmentConfig.build
|
|
116
118
|
- **Circular Dependency Detection**: Clear error messages with detailed paths
|
117
119
|
- **Granular Execution**: Build individual tasks or complete graphs
|
118
120
|
- **Memory Management**: Built-in reset mechanisms
|
121
|
+
- **Progress Display**: Visual feedback with spinners and output capture
|
122
|
+
- **Dependency Tree Visualization**: Visual representation of task relationships
|
123
|
+
|
124
|
+
### Dependency Tree Visualization
|
125
|
+
|
126
|
+
Visualize task dependencies with the `tree` method:
|
127
|
+
|
128
|
+
```ruby
|
129
|
+
class Database < Taski::Task
|
130
|
+
exports :connection
|
131
|
+
def build; @connection = "db-conn"; end
|
132
|
+
end
|
133
|
+
|
134
|
+
class Cache < Taski::Task
|
135
|
+
exports :redis_url
|
136
|
+
def build; @redis_url = "redis://localhost"; end
|
137
|
+
end
|
138
|
+
|
139
|
+
class Config < Taski::Task
|
140
|
+
exports :settings
|
141
|
+
def build
|
142
|
+
@settings = {
|
143
|
+
database: Database.connection,
|
144
|
+
cache: Cache.redis_url
|
145
|
+
}
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
class WebServer < Taski::Task
|
150
|
+
def build
|
151
|
+
puts "Starting with #{Config.settings}"
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
puts WebServer.tree
|
156
|
+
# => WebServer
|
157
|
+
# => └── Config
|
158
|
+
# => ├── Database
|
159
|
+
# => └── Cache
|
160
|
+
```
|
161
|
+
|
162
|
+
### Progress Display
|
163
|
+
|
164
|
+
Taski provides visual feedback during task execution with animated spinners and real-time output capture:
|
165
|
+
|
166
|
+
```ruby
|
167
|
+
class LongRunningTask < Taski::Task
|
168
|
+
def build
|
169
|
+
puts "Starting process..."
|
170
|
+
sleep(1.0)
|
171
|
+
puts "Processing data..."
|
172
|
+
puts "Almost done..."
|
173
|
+
sleep(0.5)
|
174
|
+
puts "Completed!"
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
LongRunningTask.build
|
179
|
+
# During execution shows:
|
180
|
+
# ⠧ LongRunningTask
|
181
|
+
# Starting process...
|
182
|
+
# Processing data...
|
183
|
+
# Almost done...
|
184
|
+
# Completed!
|
185
|
+
#
|
186
|
+
# After completion shows:
|
187
|
+
# ✅ LongRunningTask (1500ms)
|
188
|
+
```
|
189
|
+
|
190
|
+
**Progress Display Features:**
|
191
|
+
- **Spinner Animation**: Dots-style spinner during task execution
|
192
|
+
- **Output Capture**: Real-time display of task output (last 5 lines)
|
193
|
+
- **Status Indicators**: ✅ for success, ❌ for failure
|
194
|
+
- **Execution Time**: Shows task duration after completion
|
195
|
+
- **TTY Detection**: Clean output when redirected to files
|
119
196
|
|
120
197
|
### Granular Task Execution
|
121
198
|
|
@@ -172,6 +249,29 @@ WebServer.clean
|
|
172
249
|
# => Database disconnected
|
173
250
|
```
|
174
251
|
|
252
|
+
### Clean Method Idempotency
|
253
|
+
|
254
|
+
**Important**: The `clean` method must be idempotent - safe to call multiple times without errors.
|
255
|
+
|
256
|
+
```ruby
|
257
|
+
class FileTask < Taski::Task
|
258
|
+
exports :output_file
|
259
|
+
|
260
|
+
def build
|
261
|
+
@output_file = '/tmp/data.csv'
|
262
|
+
File.write(@output_file, process_data)
|
263
|
+
end
|
264
|
+
|
265
|
+
def clean
|
266
|
+
# ❌ Bad: Raises error if file doesn't exist
|
267
|
+
# File.delete(@output_file)
|
268
|
+
|
269
|
+
# ✅ Good: Check before delete
|
270
|
+
File.delete(@output_file) if File.exist?(@output_file)
|
271
|
+
end
|
272
|
+
end
|
273
|
+
```
|
274
|
+
|
175
275
|
### Error Handling
|
176
276
|
|
177
277
|
```ruby
|
@@ -182,7 +282,7 @@ rescue Taski::CircularDependencyError => e
|
|
182
282
|
end
|
183
283
|
# => Circular dependency: Circular dependency detected!
|
184
284
|
# => Cycle: TaskA → TaskB → TaskA
|
185
|
-
# =>
|
285
|
+
# =>
|
186
286
|
# => The dependency chain is:
|
187
287
|
# => 1. TaskA is trying to build → TaskB
|
188
288
|
# => 2. TaskB is trying to build → TaskA
|
@@ -222,4 +322,4 @@ MIT License
|
|
222
322
|
|
223
323
|
---
|
224
324
|
|
225
|
-
**Taski** - Build dependency graphs with elegant Ruby code. 🚀
|
325
|
+
**Taski** - Build dependency graphs with elegant Ruby code. 🚀
|
data/examples/README.md
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
# Taski Examples
|
2
|
+
|
3
|
+
Learn Taski through practical examples, from basic concepts to advanced patterns.
|
4
|
+
|
5
|
+
## Getting Started
|
6
|
+
|
7
|
+
Start with these examples in order:
|
8
|
+
|
9
|
+
### 1. **[quick_start.rb](quick_start.rb)** - Your First Taski Program
|
10
|
+
- Basic task definition with Exports API
|
11
|
+
- Automatic dependency resolution
|
12
|
+
- Simple task execution
|
13
|
+
|
14
|
+
```bash
|
15
|
+
ruby examples/quick_start.rb
|
16
|
+
```
|
17
|
+
|
18
|
+
### 2. **[progress_demo.rb](progress_demo.rb)** - Rich CLI Progress Display
|
19
|
+
- Animated spinner with ANSI colors
|
20
|
+
- Real-time output capture and 5-line tail
|
21
|
+
- Production build scenarios
|
22
|
+
- TTY detection for clean file output
|
23
|
+
|
24
|
+
```bash
|
25
|
+
# Interactive mode with rich spinner
|
26
|
+
ruby examples/progress_demo.rb
|
27
|
+
|
28
|
+
# Clean output mode (no spinner)
|
29
|
+
ruby examples/progress_demo.rb > build.log 2>&1
|
30
|
+
cat build.log
|
31
|
+
```
|
32
|
+
|
33
|
+
### 3. **[advanced_patterns.rb](advanced_patterns.rb)** - Complex Dependency Patterns
|
34
|
+
- Mixed Exports API and Define API usage
|
35
|
+
- Environment-specific dependencies
|
36
|
+
- Feature flags and conditional logic
|
37
|
+
- Task reset and rebuild scenarios
|
38
|
+
|
39
|
+
```bash
|
40
|
+
ruby examples/advanced_patterns.rb
|
41
|
+
```
|
42
|
+
|
43
|
+
## Key Concepts Demonstrated
|
44
|
+
|
45
|
+
- **Exports API**: Static dependencies with `exports :property`
|
46
|
+
- **Define API**: Dynamic dependencies with `define :property, -> { ... }`
|
47
|
+
- **Progress Display**: Rich terminal output with spinners and colors
|
48
|
+
- **Output Capture**: Tail-style display of task output
|
49
|
+
- **Environment Configuration**: Different behavior based on runtime settings
|
50
|
+
- **Error Handling**: Graceful failure with progress indicators
|
51
|
+
|
52
|
+
## Next Steps
|
53
|
+
|
54
|
+
After exploring these examples:
|
55
|
+
- Read the main documentation
|
56
|
+
- Examine the test files for more usage patterns
|
57
|
+
- Check out the source code in `lib/taski/`
|
@@ -1,8 +1,22 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
#
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
# Taski Advanced Patterns
|
5
|
+
#
|
6
|
+
# This example demonstrates advanced Taski patterns:
|
7
|
+
# - Mixed usage of Exports API and Define API
|
8
|
+
# - Environment-specific dependency resolution
|
9
|
+
# - Feature flag integration with dynamic dependencies
|
10
|
+
# - Task reset and rebuild scenarios
|
11
|
+
# - Conditional dependency evaluation
|
12
|
+
#
|
13
|
+
# Run: ruby examples/advanced_patterns.rb
|
3
14
|
|
4
15
|
require_relative "../lib/taski"
|
5
16
|
|
17
|
+
puts "⚡ Advanced Taski Patterns"
|
18
|
+
puts "=" * 40
|
19
|
+
|
6
20
|
# Mock classes for the example
|
7
21
|
class ProductionDB < Taski::Task
|
8
22
|
exports :connection_string
|
@@ -81,8 +95,6 @@ class Application < Taski::Task
|
|
81
95
|
end
|
82
96
|
|
83
97
|
# Test different environments
|
84
|
-
puts "=== Complex Example ==="
|
85
|
-
|
86
98
|
puts "\n1. Development Environment (default):"
|
87
99
|
ENV.delete("RAILS_ENV")
|
88
100
|
ENV.delete("FEATURE_REDIS_CACHE")
|
@@ -0,0 +1,166 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
# Taski Progress Display Demo
|
5
|
+
#
|
6
|
+
# This comprehensive example demonstrates all progress display features:
|
7
|
+
# 1. Basic spinner animation with success/failure indicators
|
8
|
+
# 2. Output capture with 5-line tail display
|
9
|
+
# 3. Real-world build scenario with external command simulation
|
10
|
+
# 4. TTY detection for clean file output
|
11
|
+
#
|
12
|
+
# Run: ruby examples/progress_demo.rb
|
13
|
+
# Try: ruby examples/progress_demo.rb > build.log 2>&1 && cat build.log
|
14
|
+
|
15
|
+
require_relative "../lib/taski"
|
16
|
+
|
17
|
+
puts "🎯 Taski Progress Display Demo"
|
18
|
+
puts "=" * 50
|
19
|
+
|
20
|
+
# SECTION 1: Basic Spinner Animation
|
21
|
+
puts "\n📍 SECTION 1: Basic Spinner & Success/Failure Indicators"
|
22
|
+
puts "-" * 50
|
23
|
+
|
24
|
+
class ConfigTask < Taski::Task
|
25
|
+
exports :database_url, :cache_url
|
26
|
+
|
27
|
+
def build
|
28
|
+
sleep 0.8
|
29
|
+
@database_url = "postgres://localhost/myapp"
|
30
|
+
@cache_url = "redis://localhost:6379"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class DatabaseTask < Taski::Task
|
35
|
+
exports :connection
|
36
|
+
|
37
|
+
def build
|
38
|
+
sleep 1.2
|
39
|
+
@connection = "Connected to #{ConfigTask.database_url}"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
class ApplicationTask < Taski::Task
|
44
|
+
exports :status
|
45
|
+
|
46
|
+
def build
|
47
|
+
sleep 1.0
|
48
|
+
db = DatabaseTask.connection
|
49
|
+
@status = "App ready! #{db}"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
ApplicationTask.build
|
54
|
+
puts "🎉 Application Status: #{ApplicationTask.status}"
|
55
|
+
|
56
|
+
# SECTION 2: Output Capture Demo
|
57
|
+
puts "\n📍 SECTION 2: Output Capture with 5-Line Tail"
|
58
|
+
puts "-" * 50
|
59
|
+
|
60
|
+
class VerboseTask < Taski::Task
|
61
|
+
exports :result
|
62
|
+
|
63
|
+
def build
|
64
|
+
puts "Starting task initialization..."
|
65
|
+
sleep 0.3
|
66
|
+
|
67
|
+
puts "Loading configuration files..."
|
68
|
+
puts "Connecting to database..."
|
69
|
+
puts "Connection established: localhost:5432"
|
70
|
+
sleep 0.3
|
71
|
+
|
72
|
+
puts "Running initial checks..."
|
73
|
+
puts "Checking schema version..."
|
74
|
+
puts "Schema is up to date"
|
75
|
+
puts "Performing data validation..."
|
76
|
+
puts "Validating user records..."
|
77
|
+
puts "Validating product records..."
|
78
|
+
puts "All validations passed"
|
79
|
+
sleep 0.4
|
80
|
+
|
81
|
+
puts "Task completed successfully!"
|
82
|
+
@result = "All operations completed"
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
VerboseTask.build
|
87
|
+
puts "📊 Verbose Task Result: #{VerboseTask.result}"
|
88
|
+
|
89
|
+
# SECTION 3: Production Build Scenario
|
90
|
+
puts "\n📍 SECTION 3: Production Build Scenario"
|
91
|
+
puts "-" * 50
|
92
|
+
|
93
|
+
class CompileTask < Taski::Task
|
94
|
+
exports :result
|
95
|
+
|
96
|
+
def build
|
97
|
+
puts "Starting compilation process..."
|
98
|
+
sleep 0.8
|
99
|
+
|
100
|
+
puts "Checking source files..."
|
101
|
+
puts "Found: main.c, utils.c, config.h"
|
102
|
+
sleep 0.6
|
103
|
+
|
104
|
+
puts "Running gcc compilation..."
|
105
|
+
puts "gcc -Wall -O2 -c main.c"
|
106
|
+
puts "gcc -Wall -O2 -c utils.c"
|
107
|
+
puts "main.c: In function 'main':"
|
108
|
+
puts "main.c:42: warning: unused variable 'temp'"
|
109
|
+
puts "utils.c: In function 'parse_config':"
|
110
|
+
puts "utils.c:15: warning: implicit declaration of function 'strcpy'"
|
111
|
+
sleep 0.8
|
112
|
+
|
113
|
+
puts "Linking objects..."
|
114
|
+
puts "gcc -o myapp main.o utils.o"
|
115
|
+
puts "Compilation successful!"
|
116
|
+
|
117
|
+
@result = "myapp binary created"
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
class TestTask < Taski::Task
|
122
|
+
exports :test_result
|
123
|
+
|
124
|
+
def build
|
125
|
+
puts "Running test suite..."
|
126
|
+
sleep 0.2
|
127
|
+
|
128
|
+
(1..8).each do |i|
|
129
|
+
puts "Test #{i}/8: #{["PASS", "PASS", "FAIL", "PASS", "PASS", "PASS", "PASS", "PASS"][i - 1]}"
|
130
|
+
sleep 0.4
|
131
|
+
end
|
132
|
+
|
133
|
+
puts "Test summary: 7/8 passed, 1 failed"
|
134
|
+
@test_result = "Tests completed with 1 failure"
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
CompileTask.build
|
139
|
+
puts "📦 Compilation: #{CompileTask.result}"
|
140
|
+
|
141
|
+
TestTask.build
|
142
|
+
puts "🧪 Test Result: #{TestTask.test_result}"
|
143
|
+
|
144
|
+
# SECTION 4: Error Handling Demo
|
145
|
+
puts "\n📍 SECTION 4: Error Handling Demo"
|
146
|
+
puts "-" * 50
|
147
|
+
|
148
|
+
class FailingTask < Taski::Task
|
149
|
+
def build
|
150
|
+
puts "Attempting network connection..."
|
151
|
+
sleep 1.0 # Watch it spin before failing
|
152
|
+
puts "Connection timeout after 30 seconds"
|
153
|
+
puts "Retrying connection..."
|
154
|
+
sleep 0.5
|
155
|
+
raise StandardError, "Network connection failed!"
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
begin
|
160
|
+
FailingTask.build
|
161
|
+
rescue Taski::TaskBuildError => e
|
162
|
+
puts "🛡️ Error handled gracefully: #{e.message}"
|
163
|
+
end
|
164
|
+
|
165
|
+
puts "\n✨ Demo Complete!"
|
166
|
+
puts "Note: Rich spinner display only appears in terminals, not when output is redirected."
|
@@ -1,8 +1,20 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
#
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
# Taski Quick Start Guide
|
5
|
+
#
|
6
|
+
# This example demonstrates the fundamentals of Taski:
|
7
|
+
# - Task definition with the Exports API
|
8
|
+
# - Automatic dependency resolution
|
9
|
+
# - Simple task execution
|
10
|
+
#
|
11
|
+
# Run: ruby examples/quick_start.rb
|
3
12
|
|
4
13
|
require_relative "../lib/taski"
|
5
14
|
|
15
|
+
puts "🚀 Taski Quick Start"
|
16
|
+
puts "=" * 30
|
17
|
+
|
6
18
|
# Simple static dependency using Exports API
|
7
19
|
class DatabaseSetup < Taski::Task
|
8
20
|
exports :connection_string
|
@@ -24,7 +36,6 @@ class APIServer < Taski::Task
|
|
24
36
|
end
|
25
37
|
|
26
38
|
# Execute - dependencies are resolved automatically
|
27
|
-
puts "=== Quick Start Example ==="
|
28
39
|
APIServer.build
|
29
40
|
|
30
|
-
puts "\
|
41
|
+
puts "\n✅ Result: APIServer running on port #{APIServer.port}"
|
@@ -0,0 +1,80 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
# Tree Display Demo
|
5
|
+
#
|
6
|
+
# This example demonstrates the tree display functionality that shows
|
7
|
+
# task dependency relationships in a visual tree format.
|
8
|
+
#
|
9
|
+
# Run: ruby examples/tree_demo.rb
|
10
|
+
|
11
|
+
require_relative "../lib/taski"
|
12
|
+
|
13
|
+
puts "🌲 Taski Tree Display Demo"
|
14
|
+
puts "=" * 40
|
15
|
+
|
16
|
+
# Create a dependency chain for demonstration
|
17
|
+
class Database < Taski::Task
|
18
|
+
exports :connection_string
|
19
|
+
|
20
|
+
def build
|
21
|
+
@connection_string = "postgres://localhost/myapp"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class Cache < Taski::Task
|
26
|
+
exports :redis_url
|
27
|
+
|
28
|
+
def build
|
29
|
+
@redis_url = "redis://localhost:6379"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
class Config < Taski::Task
|
34
|
+
exports :settings
|
35
|
+
|
36
|
+
def build
|
37
|
+
@settings = {
|
38
|
+
database: Database.connection_string,
|
39
|
+
cache: Cache.redis_url,
|
40
|
+
port: 3000
|
41
|
+
}
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
class Logger < Taski::Task
|
46
|
+
exports :log_level
|
47
|
+
|
48
|
+
def build
|
49
|
+
@log_level = "info"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
class WebServer < Taski::Task
|
54
|
+
exports :server_instance
|
55
|
+
|
56
|
+
def build
|
57
|
+
@server_instance = "WebServer configured with #{Config.settings[:database]} and #{Logger.log_level}"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
class Application < Taski::Task
|
62
|
+
def build
|
63
|
+
puts "Starting application..."
|
64
|
+
puts "Web server: #{WebServer.server_instance}"
|
65
|
+
puts "Config: #{Config.settings}"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
puts "\n📊 Application Dependency Tree:"
|
70
|
+
puts Application.tree
|
71
|
+
|
72
|
+
puts "\n🔍 Individual Component Trees:"
|
73
|
+
puts "\nWebServer dependencies:"
|
74
|
+
puts WebServer.tree
|
75
|
+
|
76
|
+
puts "\nConfig dependencies:"
|
77
|
+
puts Config.tree
|
78
|
+
|
79
|
+
puts "\n▶️ Building Application (to verify dependencies work):"
|
80
|
+
Application.build
|
@@ -38,7 +38,7 @@ module Taski
|
|
38
38
|
method_node = find_method_node(result.value, method_name, line_number)
|
39
39
|
|
40
40
|
if method_node
|
41
|
-
visitor = TaskDependencyVisitor.new
|
41
|
+
visitor = TaskDependencyVisitor.new(klass)
|
42
42
|
visitor.visit(method_node)
|
43
43
|
dependencies = visitor.dependencies
|
44
44
|
end
|
@@ -96,9 +96,10 @@ module Taski
|
|
96
96
|
class TaskDependencyVisitor < Prism::Visitor
|
97
97
|
attr_reader :dependencies
|
98
98
|
|
99
|
-
def initialize
|
99
|
+
def initialize(context_class = nil)
|
100
100
|
@dependencies = []
|
101
101
|
@constant_cache = {}
|
102
|
+
@context_class = context_class
|
102
103
|
end
|
103
104
|
|
104
105
|
def visit_constant_read_node(node)
|
@@ -135,14 +136,19 @@ module Taski
|
|
135
136
|
return @dependencies << cached_result if cached_result # Cached positive result
|
136
137
|
|
137
138
|
begin
|
139
|
+
resolved_class = nil
|
140
|
+
|
141
|
+
# 1. Try absolute reference first (existing logic)
|
138
142
|
if Object.const_defined?(const_name)
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
143
|
+
resolved_class = Object.const_get(const_name)
|
144
|
+
# 2. Try relative reference within namespace context
|
145
|
+
elsif @context_class
|
146
|
+
resolved_class = resolve_relative_constant(const_name)
|
147
|
+
end
|
148
|
+
|
149
|
+
if resolved_class&.is_a?(Class) && resolved_class < Taski::Task
|
150
|
+
@constant_cache[const_name] = resolved_class
|
151
|
+
@dependencies << resolved_class
|
146
152
|
else
|
147
153
|
@constant_cache[const_name] = false
|
148
154
|
end
|
@@ -151,6 +157,32 @@ module Taski
|
|
151
157
|
end
|
152
158
|
end
|
153
159
|
|
160
|
+
def resolve_relative_constant(const_name)
|
161
|
+
return nil unless @context_class
|
162
|
+
|
163
|
+
# Get the namespace from the context class
|
164
|
+
namespace = get_namespace_from_class(@context_class)
|
165
|
+
return nil unless namespace
|
166
|
+
|
167
|
+
# Try to resolve the constant within the namespace
|
168
|
+
full_const_name = "#{namespace}::#{const_name}"
|
169
|
+
Object.const_get(full_const_name) if Object.const_defined?(full_const_name)
|
170
|
+
rescue NameError, ArgumentError
|
171
|
+
nil
|
172
|
+
end
|
173
|
+
|
174
|
+
def get_namespace_from_class(klass)
|
175
|
+
# Extract namespace from class name (e.g., "A::AB" -> "A")
|
176
|
+
class_name = klass.name
|
177
|
+
return nil unless class_name&.include?("::")
|
178
|
+
|
179
|
+
# Split by "::" and take all but the last part
|
180
|
+
parts = class_name.split("::")
|
181
|
+
return nil if parts.length <= 1 # No namespace
|
182
|
+
|
183
|
+
parts[0..-2].join("::")
|
184
|
+
end
|
185
|
+
|
154
186
|
def extract_constant_path(node)
|
155
187
|
case node
|
156
188
|
when Prism::ConstantReadNode
|
data/lib/taski/logger.rb
CHANGED
@@ -48,11 +48,16 @@ module Taski
|
|
48
48
|
# Log task build start event
|
49
49
|
# @param task_name [String] Name of the task being built
|
50
50
|
# @param dependencies [Array] List of task dependencies
|
51
|
-
|
52
|
-
|
51
|
+
# @param args [Hash] Build arguments for parametrized builds
|
52
|
+
def task_build_start(task_name, dependencies: [], args: nil)
|
53
|
+
context = {
|
53
54
|
task: task_name,
|
54
55
|
dependencies: dependencies.size,
|
55
|
-
dependency_names: dependencies.map { |dep| dep.is_a?(Hash) ? dep[:klass].inspect : dep.inspect }
|
56
|
+
dependency_names: dependencies.map { |dep| dep.is_a?(Hash) ? dep[:klass].inspect : dep.inspect }
|
57
|
+
}
|
58
|
+
context[:args] = args if args && !args.empty?
|
59
|
+
|
60
|
+
info("Task build started", **context)
|
56
61
|
end
|
57
62
|
|
58
63
|
# Log task build completion event
|
@@ -181,6 +186,12 @@ module Taski
|
|
181
186
|
@logger ||= Logger.new
|
182
187
|
end
|
183
188
|
|
189
|
+
# Get the current progress display instance (always enabled)
|
190
|
+
# @return [ProgressDisplay] Current progress display instance
|
191
|
+
def progress_display
|
192
|
+
@progress_display ||= ProgressDisplay.new(force_enable: ENV["TASKI_FORCE_PROGRESS"] == "1")
|
193
|
+
end
|
194
|
+
|
184
195
|
# Configure the logger with new settings
|
185
196
|
# @param level [Symbol] Log level (:debug, :info, :warn, :error)
|
186
197
|
# @param output [IO] Output destination
|