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/examples/progress_demo.rb
DELETED
|
@@ -1,166 +0,0 @@
|
|
|
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."
|
data/examples/tree_demo.rb
DELETED
|
@@ -1,205 +0,0 @@
|
|
|
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🔧 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
|
-
|
|
204
|
-
puts "\n▶️ Building Application (to verify dependencies work):"
|
|
205
|
-
Application.build
|
|
@@ -1,232 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "prism"
|
|
4
|
-
|
|
5
|
-
module Taski
|
|
6
|
-
module DependencyAnalyzer
|
|
7
|
-
class << self
|
|
8
|
-
def analyze_method(klass, method_name)
|
|
9
|
-
return [] unless klass.instance_methods(false).include?(method_name)
|
|
10
|
-
|
|
11
|
-
method = klass.instance_method(method_name)
|
|
12
|
-
source_location = method.source_location
|
|
13
|
-
return [] unless source_location
|
|
14
|
-
|
|
15
|
-
file_path, line_number = source_location
|
|
16
|
-
return [] unless File.exist?(file_path)
|
|
17
|
-
|
|
18
|
-
parse_source_file(file_path, line_number, klass, method_name)
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
private
|
|
22
|
-
|
|
23
|
-
# Parse source file and extract dependencies with proper error handling
|
|
24
|
-
# @param file_path [String] Path to source file
|
|
25
|
-
# @param line_number [Integer] Line number of method definition
|
|
26
|
-
# @param klass [Class] Class containing the method
|
|
27
|
-
# @param method_name [Symbol] Method name being analyzed
|
|
28
|
-
# @return [Array<Class>] Array of dependency classes
|
|
29
|
-
def parse_source_file(file_path, line_number, klass, method_name)
|
|
30
|
-
result = Prism.parse_file(file_path)
|
|
31
|
-
handle_parse_errors(result, file_path, klass, method_name)
|
|
32
|
-
extract_dependencies_from_node(result.value, line_number, klass, method_name)
|
|
33
|
-
rescue IOError, SystemCallError => e
|
|
34
|
-
Taski.logger.error("Failed to read source file",
|
|
35
|
-
file: file_path,
|
|
36
|
-
error: e.message,
|
|
37
|
-
method: "#{klass}##{method_name}")
|
|
38
|
-
[]
|
|
39
|
-
rescue => e
|
|
40
|
-
Taski.logger.error("Failed to analyze method dependencies",
|
|
41
|
-
class: klass.name,
|
|
42
|
-
method: method_name,
|
|
43
|
-
error: e.message,
|
|
44
|
-
error_class: e.class.name)
|
|
45
|
-
[]
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
# Handle parse errors and warnings from Prism parsing
|
|
49
|
-
# @param result [Prism::ParseResult] Parse result from Prism
|
|
50
|
-
# @param file_path [String] Path to source file
|
|
51
|
-
# @param klass [Class] Class containing the method
|
|
52
|
-
# @param method_name [Symbol] Method name being analyzed
|
|
53
|
-
# @return [Array] Empty array if errors found
|
|
54
|
-
# @raise [RuntimeError] If parse fails
|
|
55
|
-
def handle_parse_errors(result, file_path, klass, method_name)
|
|
56
|
-
unless result.success?
|
|
57
|
-
Taski.logger.error("Parse errors in source file",
|
|
58
|
-
file: file_path,
|
|
59
|
-
errors: result.errors.map(&:message),
|
|
60
|
-
method: "#{klass}##{method_name}")
|
|
61
|
-
return []
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
# Handle warnings if present
|
|
65
|
-
if result.warnings.any?
|
|
66
|
-
Taski.logger.warn("Parse warnings in source file",
|
|
67
|
-
file: file_path,
|
|
68
|
-
warnings: result.warnings.map(&:message),
|
|
69
|
-
method: "#{klass}##{method_name}")
|
|
70
|
-
end
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
# Extract dependencies from parsed AST node
|
|
74
|
-
# @param root_node [Prism::Node] Root AST node
|
|
75
|
-
# @param line_number [Integer] Line number of method definition
|
|
76
|
-
# @param klass [Class] Class containing the method
|
|
77
|
-
# @param method_name [Symbol] Method name being analyzed
|
|
78
|
-
# @return [Array<Class>] Array of unique dependency classes
|
|
79
|
-
def extract_dependencies_from_node(root_node, line_number, klass, method_name)
|
|
80
|
-
dependencies = []
|
|
81
|
-
method_node = find_method_node(root_node, method_name, line_number)
|
|
82
|
-
|
|
83
|
-
if method_node
|
|
84
|
-
visitor = TaskDependencyVisitor.new(klass)
|
|
85
|
-
visitor.visit(method_node)
|
|
86
|
-
dependencies = visitor.dependencies
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
dependencies.uniq
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
def find_method_node(node, method_name, target_line)
|
|
93
|
-
return nil unless node
|
|
94
|
-
|
|
95
|
-
case node
|
|
96
|
-
when Prism::DefNode
|
|
97
|
-
if node.name == method_name && node.location.start_line <= target_line && node.location.end_line >= target_line
|
|
98
|
-
return node
|
|
99
|
-
end
|
|
100
|
-
when Prism::ClassNode, Prism::ModuleNode
|
|
101
|
-
if node.respond_to?(:body)
|
|
102
|
-
return find_method_node(node.body, method_name, target_line)
|
|
103
|
-
end
|
|
104
|
-
when Prism::StatementsNode
|
|
105
|
-
node.body.each do |child|
|
|
106
|
-
result = find_method_node(child, method_name, target_line)
|
|
107
|
-
return result if result
|
|
108
|
-
end
|
|
109
|
-
end
|
|
110
|
-
|
|
111
|
-
# Recursively search child nodes
|
|
112
|
-
if node.respond_to?(:child_nodes)
|
|
113
|
-
node.child_nodes.each do |child|
|
|
114
|
-
result = find_method_node(child, method_name, target_line)
|
|
115
|
-
return result if result
|
|
116
|
-
end
|
|
117
|
-
end
|
|
118
|
-
|
|
119
|
-
nil
|
|
120
|
-
end
|
|
121
|
-
|
|
122
|
-
# Task dependency visitor using Prism's visitor pattern
|
|
123
|
-
class TaskDependencyVisitor < Prism::Visitor
|
|
124
|
-
attr_reader :dependencies
|
|
125
|
-
|
|
126
|
-
def initialize(context_class = nil)
|
|
127
|
-
@dependencies = []
|
|
128
|
-
@constant_cache = {}
|
|
129
|
-
@context_class = context_class
|
|
130
|
-
end
|
|
131
|
-
|
|
132
|
-
def visit_constant_read_node(node)
|
|
133
|
-
check_task_constant(node.name.to_s)
|
|
134
|
-
super
|
|
135
|
-
end
|
|
136
|
-
|
|
137
|
-
def visit_constant_path_node(node)
|
|
138
|
-
const_path = extract_constant_path(node)
|
|
139
|
-
check_task_constant(const_path) if const_path
|
|
140
|
-
super
|
|
141
|
-
end
|
|
142
|
-
|
|
143
|
-
def visit_call_node(node)
|
|
144
|
-
# Check for method calls on constants (e.g., TaskA.result)
|
|
145
|
-
case node.receiver
|
|
146
|
-
when Prism::ConstantReadNode
|
|
147
|
-
check_task_constant(node.receiver.name.to_s)
|
|
148
|
-
when Prism::ConstantPathNode
|
|
149
|
-
const_path = extract_constant_path(node.receiver)
|
|
150
|
-
check_task_constant(const_path) if const_path
|
|
151
|
-
end
|
|
152
|
-
super
|
|
153
|
-
end
|
|
154
|
-
|
|
155
|
-
private
|
|
156
|
-
|
|
157
|
-
def check_task_constant(const_name)
|
|
158
|
-
return unless const_name
|
|
159
|
-
|
|
160
|
-
# Use caching to avoid repeated constant resolution
|
|
161
|
-
cached_result = @constant_cache[const_name]
|
|
162
|
-
return cached_result if cached_result == false # Cached negative result
|
|
163
|
-
return @dependencies << cached_result if cached_result # Cached positive result
|
|
164
|
-
|
|
165
|
-
begin
|
|
166
|
-
resolved_class = nil
|
|
167
|
-
|
|
168
|
-
# Try absolute reference first for performance and clarity
|
|
169
|
-
if Object.const_defined?(const_name)
|
|
170
|
-
resolved_class = Object.const_get(const_name)
|
|
171
|
-
# Fall back to relative reference for nested module support
|
|
172
|
-
# This enables tasks defined inside modules to reference siblings
|
|
173
|
-
elsif @context_class
|
|
174
|
-
resolved_class = resolve_relative_constant(const_name)
|
|
175
|
-
end
|
|
176
|
-
|
|
177
|
-
if resolved_class&.is_a?(Class) && (resolved_class < Taski::Task || resolved_class < Taski::Section)
|
|
178
|
-
@constant_cache[const_name] = resolved_class
|
|
179
|
-
@dependencies << resolved_class
|
|
180
|
-
else
|
|
181
|
-
@constant_cache[const_name] = false
|
|
182
|
-
end
|
|
183
|
-
rescue NameError, ArgumentError
|
|
184
|
-
@constant_cache[const_name] = false
|
|
185
|
-
end
|
|
186
|
-
end
|
|
187
|
-
|
|
188
|
-
def resolve_relative_constant(const_name)
|
|
189
|
-
return nil unless @context_class
|
|
190
|
-
|
|
191
|
-
# Get the namespace from the context class
|
|
192
|
-
namespace = get_namespace_from_class(@context_class)
|
|
193
|
-
return nil unless namespace
|
|
194
|
-
|
|
195
|
-
# Try to resolve the constant within the namespace
|
|
196
|
-
full_const_name = "#{namespace}::#{const_name}"
|
|
197
|
-
Object.const_get(full_const_name) if Object.const_defined?(full_const_name)
|
|
198
|
-
rescue NameError, ArgumentError
|
|
199
|
-
nil
|
|
200
|
-
end
|
|
201
|
-
|
|
202
|
-
def get_namespace_from_class(klass)
|
|
203
|
-
# Extract namespace from class name (e.g., "A::AB" -> "A")
|
|
204
|
-
class_name = klass.name
|
|
205
|
-
return nil unless class_name&.include?("::")
|
|
206
|
-
|
|
207
|
-
# Split by "::" and take all but the last part
|
|
208
|
-
parts = class_name.split("::")
|
|
209
|
-
return nil if parts.length <= 1 # No namespace
|
|
210
|
-
|
|
211
|
-
parts[0..-2].join("::")
|
|
212
|
-
end
|
|
213
|
-
|
|
214
|
-
def extract_constant_path(node)
|
|
215
|
-
case node
|
|
216
|
-
when Prism::ConstantReadNode
|
|
217
|
-
node.name.to_s
|
|
218
|
-
when Prism::ConstantPathNode
|
|
219
|
-
parent_path = extract_constant_path(node.parent) if node.parent
|
|
220
|
-
child_name = node.name.to_s
|
|
221
|
-
|
|
222
|
-
if parent_path && child_name
|
|
223
|
-
"#{parent_path}::#{child_name}"
|
|
224
|
-
else
|
|
225
|
-
child_name
|
|
226
|
-
end
|
|
227
|
-
end
|
|
228
|
-
end
|
|
229
|
-
end
|
|
230
|
-
end
|
|
231
|
-
end
|
|
232
|
-
end
|
data/lib/taski/exceptions.rb
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Taski
|
|
4
|
-
# Custom exceptions for Taski framework
|
|
5
|
-
|
|
6
|
-
# Raised when circular dependencies are detected between tasks
|
|
7
|
-
class CircularDependencyError < StandardError; end
|
|
8
|
-
|
|
9
|
-
# Raised when task analysis fails (e.g., constant resolution errors)
|
|
10
|
-
class TaskAnalysisError < StandardError; end
|
|
11
|
-
|
|
12
|
-
# Raised when task building fails during execution
|
|
13
|
-
class TaskBuildError < StandardError; end
|
|
14
|
-
|
|
15
|
-
# Raised when section implementation method is missing
|
|
16
|
-
class SectionImplementationError < StandardError; end
|
|
17
|
-
end
|