taski 0.3.0 → 0.3.1
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 +1 -3
- data/examples/section_configuration.rb +0 -6
- data/lib/taski/dependency_analyzer.rb +3 -2
- data/lib/taski/progress/display_manager.rb +4 -2
- data/lib/taski/progress/spinner_animation.rb +4 -1
- data/lib/taski/progress_display.rb +0 -2
- data/lib/taski/section.rb +8 -4
- data/lib/taski/task/base.rb +4 -3
- data/lib/taski/task/define_api.rb +5 -3
- data/lib/taski/task/exports_api.rb +0 -2
- data/lib/taski/task/instance_management.rb +3 -5
- data/lib/taski/utils/tree_display_helper.rb +0 -3
- data/lib/taski/version.rb +1 -1
- data/lib/taski.rb +7 -7
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 80c881415617aa09fb7ae24441c38c677af816c20f356cc06ea82bba50639820
|
4
|
+
data.tar.gz: cc0c6e07e3f53c312844dc237ebebe344a0201bb772f1c6c20ee8c6476b9db30
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5e40462d8b2b359c17f28f16ec03524ee649324eb4e21eaf365fd147ccedad6bb3d683ece9021975683b1b121c93ad1da2bdaa0fed82ec37797090fadc79129c
|
7
|
+
data.tar.gz: 441c9553cded529843af032347f4590f9b6a289bd00f3a8ccbbe996b6be43d2154bc6e2fc4f84a94c1f18c35eb4cfcf5408ff07f6b8878b4f50e41c32a407756
|
data/README.md
CHANGED
@@ -105,7 +105,7 @@ For environment-specific implementations with clean interfaces:
|
|
105
105
|
class DatabaseSection < Taski::Section
|
106
106
|
interface :host, :port
|
107
107
|
|
108
|
-
def impl
|
108
|
+
def impl
|
109
109
|
ENV['RAILS_ENV'] == 'production' ? Production : Development
|
110
110
|
end
|
111
111
|
|
@@ -122,8 +122,6 @@ class DatabaseSection < Taski::Section
|
|
122
122
|
@port = 5432
|
123
123
|
end
|
124
124
|
end
|
125
|
-
|
126
|
-
apply_auto_exports # DRY - auto-adds exports to nested tasks
|
127
125
|
end
|
128
126
|
|
129
127
|
# Usage is simple - Section works like any Task
|
@@ -58,9 +58,6 @@ class DatabaseSection < Taski::Section
|
|
58
58
|
@pool_size = 5
|
59
59
|
end
|
60
60
|
end
|
61
|
-
|
62
|
-
# Apply auto-exports after all nested Task classes are defined
|
63
|
-
apply_auto_exports
|
64
61
|
end
|
65
62
|
|
66
63
|
# Example 2: API Configuration Section
|
@@ -98,9 +95,6 @@ class ApiSection < Taski::Section
|
|
98
95
|
@retry_count = 1
|
99
96
|
end
|
100
97
|
end
|
101
|
-
|
102
|
-
# Apply auto-exports after all nested Task classes are defined
|
103
|
-
apply_auto_exports
|
104
98
|
end
|
105
99
|
|
106
100
|
# Example 3: Task that depends on multiple sections
|
@@ -165,10 +165,11 @@ module Taski
|
|
165
165
|
begin
|
166
166
|
resolved_class = nil
|
167
167
|
|
168
|
-
#
|
168
|
+
# Try absolute reference first for performance and clarity
|
169
169
|
if Object.const_defined?(const_name)
|
170
170
|
resolved_class = Object.const_get(const_name)
|
171
|
-
#
|
171
|
+
# Fall back to relative reference for nested module support
|
172
|
+
# This enables tasks defined inside modules to reference siblings
|
172
173
|
elsif @context_class
|
173
174
|
resolved_class = resolve_relative_constant(const_name)
|
174
175
|
end
|
@@ -63,7 +63,8 @@ module Taski
|
|
63
63
|
|
64
64
|
lines_count = 0
|
65
65
|
|
66
|
-
#
|
66
|
+
# Show only current task to maintain clean, focused UI
|
67
|
+
# Displaying all past completed tasks creates visual clutter and reduces readability
|
67
68
|
@terminal.puts @formatter.format_current_task(spinner_char, task_name)
|
68
69
|
lines_count += 1
|
69
70
|
|
@@ -85,7 +86,8 @@ module Taski
|
|
85
86
|
@output_capture.stop
|
86
87
|
clear_current_display
|
87
88
|
|
88
|
-
#
|
89
|
+
# Test environments need output for verification, production prefers concise display
|
90
|
+
# Conditional inclusion balances debugging needs with user experience
|
89
91
|
if @include_captured_output && captured_output.any?
|
90
92
|
captured_output.each do |line|
|
91
93
|
@terminal.puts line.chomp
|
@@ -28,12 +28,15 @@ module Taski
|
|
28
28
|
sleep FRAME_DELAY
|
29
29
|
end
|
30
30
|
rescue
|
31
|
-
#
|
31
|
+
# Prevent crashes during app shutdown or forced thread termination
|
32
|
+
# Progress display is auxiliary - errors shouldn't affect main processing
|
32
33
|
end
|
33
34
|
end
|
34
35
|
|
35
36
|
def stop
|
36
37
|
@running = false
|
38
|
+
# 0.2s timeout prevents hanging during rapid task execution
|
39
|
+
# UI responsiveness is more important than perfect cleanup
|
37
40
|
@thread&.join(0.2)
|
38
41
|
@thread = nil
|
39
42
|
end
|
@@ -20,8 +20,6 @@ module Taski
|
|
20
20
|
@spinner = Progress::SpinnerAnimation.new
|
21
21
|
@output_capture = Progress::OutputCapture.new(output)
|
22
22
|
|
23
|
-
# Default to including captured output in test environments (when output != $stdout)
|
24
|
-
# This ensures test output is visible in the test output stream
|
25
23
|
include_captured_output = include_captured_output.nil? ? (output != $stdout) : include_captured_output
|
26
24
|
@display_manager = Progress::DisplayManager.new(@terminal, @spinner, @output_capture, include_captured_output: include_captured_output)
|
27
25
|
|
data/lib/taski/section.rb
CHANGED
@@ -117,7 +117,7 @@ module Taski
|
|
117
117
|
colored_section_name = color ? TreeColors.section(section_name) : section_name
|
118
118
|
result = "#{prefix}#{colored_section_name}\n"
|
119
119
|
|
120
|
-
# Add possible implementations
|
120
|
+
# Add possible implementations - detect from nested Task classes
|
121
121
|
possible_implementations = find_possible_implementations
|
122
122
|
if possible_implementations.any?
|
123
123
|
impl_names = possible_implementations.map { |impl| extract_implementation_name(impl) }
|
@@ -174,6 +174,9 @@ module Taski
|
|
174
174
|
end
|
175
175
|
end
|
176
176
|
end
|
177
|
+
|
178
|
+
# Automatically apply exports to existing nested Task classes
|
179
|
+
auto_apply_exports_to_existing_tasks
|
177
180
|
end
|
178
181
|
|
179
182
|
# Get the interface exports for this section
|
@@ -214,9 +217,10 @@ module Taski
|
|
214
217
|
result
|
215
218
|
end
|
216
219
|
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
+
private
|
221
|
+
|
222
|
+
# Automatically apply exports to existing nested Task classes when interface is defined
|
223
|
+
def auto_apply_exports_to_existing_tasks
|
220
224
|
constants.each do |const_name|
|
221
225
|
const_value = const_get(const_name)
|
222
226
|
if const_value.is_a?(Class) && const_value < Taski::Task && !interface_exports.empty?
|
data/lib/taski/task/base.rb
CHANGED
@@ -20,7 +20,7 @@ module Taski
|
|
20
20
|
def method_added(method_name)
|
21
21
|
super
|
22
22
|
return unless ANALYZED_METHODS.include?(method_name)
|
23
|
-
#
|
23
|
+
# Avoid calling before dependency_resolver module is loaded
|
24
24
|
analyze_dependencies_at_definition if respond_to?(:analyze_dependencies_at_definition, true)
|
25
25
|
end
|
26
26
|
|
@@ -29,7 +29,8 @@ module Taski
|
|
29
29
|
# @return [Reference] A reference object
|
30
30
|
def ref(klass)
|
31
31
|
reference = Reference.new(klass)
|
32
|
-
#
|
32
|
+
# Use throw/catch mechanism for dependency collection during define API analysis
|
33
|
+
# This allows catching unresolved references without unwinding the entire call stack
|
33
34
|
if Thread.current[TASKI_ANALYZING_DEFINE_KEY]
|
34
35
|
reference.tap { |ref| throw :unresolved, ref }
|
35
36
|
else
|
@@ -84,7 +85,7 @@ module Taski
|
|
84
85
|
# Clean method with default empty implementation
|
85
86
|
# Subclasses can override this method to implement cleanup logic
|
86
87
|
def clean
|
87
|
-
# Default implementation does nothing
|
88
|
+
# Default implementation does nothing - allows optional cleanup in subclasses
|
88
89
|
end
|
89
90
|
end
|
90
91
|
end
|
@@ -16,7 +16,8 @@ module Taski
|
|
16
16
|
@dependencies ||= []
|
17
17
|
@definitions ||= {}
|
18
18
|
|
19
|
-
#
|
19
|
+
# Enable forward declarations by creating ref method on first define usage
|
20
|
+
# This allows tasks to reference other tasks before they're defined
|
20
21
|
create_ref_method_if_needed
|
21
22
|
|
22
23
|
# Create method that tracks dependencies on first call
|
@@ -61,7 +62,7 @@ module Taski
|
|
61
62
|
def self.#{name}
|
62
63
|
__resolve__[__callee__] ||= false
|
63
64
|
if __resolve__[__callee__]
|
64
|
-
# already resolved
|
65
|
+
# already resolved - prevents infinite recursion
|
65
66
|
else
|
66
67
|
__resolve__[__callee__] = true
|
67
68
|
throw :unresolved, [self, __callee__]
|
@@ -93,7 +94,8 @@ module Taski
|
|
93
94
|
# Reset resolution state
|
94
95
|
classes.each do |task_class|
|
95
96
|
klass = task_class[:klass]
|
96
|
-
#
|
97
|
+
# Reference objects are stateless but Task classes store analysis state
|
98
|
+
# Selective reset prevents errors while ensuring clean state for next analysis
|
97
99
|
if klass.respond_to?(:instance_variable_set) && !klass.is_a?(Taski::Reference)
|
98
100
|
klass.instance_variable_set(:@__resolve__, {})
|
99
101
|
end
|
@@ -15,12 +15,10 @@ module Taski
|
|
15
15
|
names.each do |name|
|
16
16
|
next if respond_to?(name)
|
17
17
|
|
18
|
-
# Define class method to access exported value
|
19
18
|
define_singleton_method(name) do
|
20
19
|
ensure_instance_built.send(name)
|
21
20
|
end
|
22
21
|
|
23
|
-
# Define instance method getter
|
24
22
|
define_method(name) do
|
25
23
|
instance_variable_get("@#{name}")
|
26
24
|
end
|
@@ -12,14 +12,12 @@ module Taski
|
|
12
12
|
# @return [Task] Returns task instance (singleton or temporary)
|
13
13
|
def build(**args)
|
14
14
|
if args.empty?
|
15
|
-
# Traditional build: singleton instance with caching
|
16
15
|
resolve_dependencies.reverse_each do |task_class|
|
17
16
|
task_class.ensure_instance_built
|
18
17
|
end
|
19
18
|
# Return the singleton instance for consistency
|
20
19
|
instance_variable_get(:@__task_instance)
|
21
20
|
else
|
22
|
-
# Parametrized build: temporary instance without caching
|
23
21
|
build_with_args(args)
|
24
22
|
end
|
25
23
|
end
|
@@ -45,7 +43,7 @@ module Taski
|
|
45
43
|
self
|
46
44
|
end
|
47
45
|
|
48
|
-
# Refresh task state
|
46
|
+
# Refresh task state
|
49
47
|
# @return [self] Returns self for method chaining
|
50
48
|
def refresh
|
51
49
|
reset!
|
@@ -82,11 +80,11 @@ module Taski
|
|
82
80
|
# Ensure task instance is built (public because called from build)
|
83
81
|
# @return [Task] The built task instance
|
84
82
|
def ensure_instance_built
|
85
|
-
#
|
83
|
+
# Double-checked locking prevents lock contention in multi-threaded builds
|
84
|
+
# First check avoids expensive synchronization when instance already exists
|
86
85
|
return @__task_instance if @__task_instance
|
87
86
|
|
88
87
|
build_monitor.synchronize do
|
89
|
-
# Check again after acquiring lock
|
90
88
|
return @__task_instance if @__task_instance
|
91
89
|
|
92
90
|
check_circular_dependency
|
@@ -26,15 +26,12 @@ module Taski
|
|
26
26
|
child_prefix_text = is_last ? " " : "│ "
|
27
27
|
child_prefix = prefix + (color ? TreeColors.connector(child_prefix_text) : child_prefix_text)
|
28
28
|
|
29
|
-
# For the dependency itself, we want to use the connector
|
30
|
-
# For its children, we want to use the child_prefix
|
31
29
|
dep_tree = if dep_class.respond_to?(:tree)
|
32
30
|
dep_class.tree(child_prefix, visited, color: color)
|
33
31
|
else
|
34
32
|
"#{child_prefix}#{dep_class.name}\n"
|
35
33
|
end
|
36
34
|
|
37
|
-
# Replace the first line (which has child_prefix) with the proper connector
|
38
35
|
dep_lines = dep_tree.lines
|
39
36
|
if dep_lines.any?
|
40
37
|
# Replace the first line prefix with connector
|
data/lib/taski/version.rb
CHANGED
data/lib/taski.rb
CHANGED
@@ -26,20 +26,20 @@ module Taski
|
|
26
26
|
# Main module for the Taski task framework
|
27
27
|
#
|
28
28
|
# Taski provides a framework for defining and managing task dependencies
|
29
|
-
# with
|
29
|
+
# with three complementary APIs:
|
30
30
|
# 1. Exports API - Export instance variables as class methods (static dependencies)
|
31
31
|
# 2. Define API - Define lazy-evaluated values with dynamic dependency resolution
|
32
|
+
# 3. Section API - Abstraction layers with runtime implementation selection
|
32
33
|
#
|
33
|
-
#
|
34
|
-
# -
|
35
|
-
# -
|
36
|
-
# -
|
37
|
-
# - Complex conditional logic determines dependencies
|
34
|
+
# API Selection Guide:
|
35
|
+
# - Use Exports API for simple static dependencies
|
36
|
+
# - Use Define API for conditional dependencies analyzed at class definition time
|
37
|
+
# - Use Section API for environment-specific implementations with static analysis
|
38
38
|
#
|
39
39
|
# Features:
|
40
40
|
# - Automatic dependency resolution (static and dynamic)
|
41
41
|
# - Static analysis of method dependencies
|
42
|
-
# - Runtime
|
42
|
+
# - Runtime implementation selection with Section API
|
43
43
|
# - Thread-safe task building
|
44
44
|
# - Circular dependency detection
|
45
45
|
# - Memory leak prevention
|