taski 0.3.0 → 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 +137 -248
  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 -66
  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 -250
  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 -231
  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 -115
  104. data/lib/taski/progress/output_capture.rb +0 -105
  105. data/lib/taski/progress/spinner_animation.rb +0 -46
  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 -59
  110. data/lib/taski/reference.rb +0 -40
  111. data/lib/taski/task/base.rb +0 -90
  112. data/lib/taski/task/define_api.rb +0 -154
  113. data/lib/taski/task/dependency_resolver.rb +0 -73
  114. data/lib/taski/task/exports_api.rb +0 -31
  115. data/lib/taski/task/instance_management.rb +0 -203
  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 -71
  119. data/lib/taski/utils.rb +0 -107
@@ -1,91 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Taski
4
- # Color utilities for tree display
5
- # Provides ANSI color codes for enhanced tree visualization
6
- class TreeColors
7
- # ANSI color codes
8
- COLORS = {
9
- red: "\e[31m",
10
- green: "\e[32m",
11
- yellow: "\e[33m",
12
- blue: "\e[34m",
13
- magenta: "\e[35m",
14
- cyan: "\e[36m",
15
- gray: "\e[90m",
16
- reset: "\e[0m",
17
- bold: "\e[1m"
18
- }.freeze
19
-
20
- class << self
21
- # Check if colors should be enabled
22
- # @return [Boolean] true if colors should be used
23
- def enabled?
24
- return @enabled unless @enabled.nil?
25
- @enabled = tty? && !no_color?
26
- end
27
-
28
- # Enable or disable colors
29
- # @param value [Boolean] whether to enable colors
30
- attr_writer :enabled
31
-
32
- # Colorize text for Section names (blue)
33
- # @param text [String] text to colorize
34
- # @return [String] colorized text
35
- def section(text)
36
- colorize(text, :blue, bold: true)
37
- end
38
-
39
- # Colorize text for Task names (green)
40
- # @param text [String] text to colorize
41
- # @return [String] colorized text
42
- def task(text)
43
- colorize(text, :green)
44
- end
45
-
46
- # Colorize text for implementation candidates (yellow)
47
- # @param text [String] text to colorize
48
- # @return [String] colorized text
49
- def implementations(text)
50
- colorize(text, :yellow)
51
- end
52
-
53
- # Colorize tree connectors (gray)
54
- # @param text [String] text to colorize
55
- # @return [String] colorized text
56
- def connector(text)
57
- colorize(text, :gray)
58
- end
59
-
60
- private
61
-
62
- # Apply color to text
63
- # @param text [String] text to colorize
64
- # @param color [Symbol] color name
65
- # @param bold [Boolean] whether to make text bold
66
- # @return [String] colorized text
67
- def colorize(text, color, bold: false)
68
- return text unless enabled?
69
-
70
- result = ""
71
- result += COLORS[:bold] if bold
72
- result += COLORS[color]
73
- result += text
74
- result += COLORS[:reset]
75
- result
76
- end
77
-
78
- # Check if output is a TTY
79
- # @return [Boolean] true if stdout is a TTY
80
- def tty?
81
- $stdout.tty?
82
- end
83
-
84
- # Check if NO_COLOR environment variable is set
85
- # @return [Boolean] true if colors should be disabled
86
- def no_color?
87
- ENV.key?("NO_COLOR")
88
- end
89
- end
90
- end
91
- end
@@ -1,85 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Taski
4
- module Utils
5
- # Helper module for dependency resolution functionality
6
- # Provides common logic for resolving dependencies and detecting circular dependencies
7
- module DependencyResolverHelper
8
- private
9
-
10
- # Resolve all dependencies in topological order with circular dependency detection
11
- # @return [Array<Class>] Array of tasks in dependency order
12
- def resolve_dependencies_common
13
- queue = [self]
14
- resolved = []
15
- visited = Set.new
16
- resolving = Set.new
17
- path_map = {self => []}
18
-
19
- while queue.any?
20
- task_class = queue.shift
21
- next if visited.include?(task_class)
22
-
23
- if resolving.include?(task_class)
24
- cycle_path = build_cycle_path(task_class, path_map)
25
- raise CircularDependencyError, build_circular_dependency_message(cycle_path)
26
- end
27
-
28
- resolving << task_class
29
- visited << task_class
30
-
31
- current_path = path_map[task_class] || []
32
- task_class.resolve(queue, resolved)
33
-
34
- task_class.instance_variable_get(:@dependencies)&.each do |dep|
35
- dep_class = extract_class(dep)
36
- path_map[dep_class] = current_path + [task_class] unless path_map.key?(dep_class)
37
- end
38
-
39
- resolving.delete(task_class)
40
- resolved << task_class unless resolved.include?(task_class)
41
- end
42
-
43
- resolved
44
- end
45
-
46
- # Resolve method for dependency graph (called by resolve_dependencies)
47
- # @param queue [Array] Queue of tasks to process
48
- # @param resolved [Array] Array of resolved tasks
49
- # @param options [Hash] Optional parameters for customization
50
- # @return [self] Returns self for method chaining
51
- def resolve_common(queue, resolved, options = {})
52
- @dependencies ||= []
53
-
54
- @dependencies.each do |task|
55
- task_class = extract_class(task)
56
-
57
- # Reorder in resolved list for correct priority
58
- resolved.delete(task_class) if resolved.include?(task_class)
59
- queue << task_class
60
- end
61
-
62
- # Call custom hook if provided
63
- options[:custom_hook]&.call
64
-
65
- self
66
- end
67
-
68
- # Build the cycle path from path tracking information
69
- # @param task_class [Class] Current task class
70
- # @param path_map [Hash] Map of paths to each task
71
- # @return [Array] Cycle path array
72
- def build_cycle_path(task_class, path_map)
73
- path = path_map[task_class] || []
74
- path + [task_class]
75
- end
76
-
77
- # Build detailed error message for circular dependencies
78
- # @param cycle_path [Array] Array representing the circular dependency path
79
- # @return [String] Formatted error message
80
- def build_circular_dependency_message(cycle_path)
81
- Utils::CircularDependencyHelpers.build_error_message(cycle_path, "dependency")
82
- end
83
- end
84
- end
85
- end
@@ -1,71 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Taski
4
- module Utils
5
- # Helper module for tree display functionality
6
- # Provides common logic for displaying dependency trees
7
- module TreeDisplayHelper
8
- private
9
-
10
- # Render dependencies as tree structure
11
- # @param dependencies [Array] Array of dependency objects
12
- # @param prefix [String] Current indentation prefix
13
- # @param visited [Set] Set of visited classes
14
- # @param color [Boolean] Whether to use color output
15
- # @return [String] Formatted dependency tree string
16
- def render_dependencies_tree(dependencies, prefix, visited, color)
17
- result = ""
18
-
19
- dependencies = dependencies.uniq { |dep| extract_class(dep) }
20
- dependencies.each_with_index do |dep, index|
21
- dep_class = extract_class(dep)
22
- is_last = index == dependencies.length - 1
23
-
24
- connector_text = is_last ? "└── " : "├── "
25
- connector = color ? TreeColors.connector(connector_text) : connector_text
26
- child_prefix_text = is_last ? " " : "│ "
27
- child_prefix = prefix + (color ? TreeColors.connector(child_prefix_text) : child_prefix_text)
28
-
29
- # For the dependency itself, we want to use the connector
30
- # For its children, we want to use the child_prefix
31
- dep_tree = if dep_class.respond_to?(:tree)
32
- dep_class.tree(child_prefix, visited, color: color)
33
- else
34
- "#{child_prefix}#{dep_class.name}\n"
35
- end
36
-
37
- # Replace the first line (which has child_prefix) with the proper connector
38
- dep_lines = dep_tree.lines
39
- if dep_lines.any?
40
- # Replace the first line prefix with connector
41
- first_line = dep_lines[0]
42
- fixed_first_line = first_line.sub(/^#{Regexp.escape(child_prefix)}/, prefix + connector)
43
- result += fixed_first_line
44
- # Add the rest of the lines as-is
45
- result += dep_lines[1..].join if dep_lines.length > 1
46
- else
47
- dep_name = color ? TreeColors.task(dep_class.name) : dep_class.name
48
- result += "#{prefix}#{connector}#{dep_name}\n"
49
- end
50
- end
51
-
52
- result
53
- end
54
-
55
- # Check for circular dependencies and handle visited set
56
- # @param visited [Set] Set of visited classes
57
- # @param current_class [Class] Current class being processed
58
- # @param prefix [String] Current indentation prefix
59
- # @return [Array] Returns [should_return_early, result_string, new_visited_set]
60
- def handle_circular_dependency_check(visited, current_class, prefix)
61
- if visited.include?(current_class)
62
- return [true, "#{prefix}#{current_class.name} (circular)\n", visited]
63
- end
64
-
65
- new_visited = visited.dup
66
- new_visited << current_class
67
- [false, nil, new_visited]
68
- end
69
- end
70
- end
71
- end
data/lib/taski/utils.rb DELETED
@@ -1,107 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Taski
4
- # Common utility functions for the Taski framework
5
- module Utils
6
- # Handle circular dependency error message generation
7
- module CircularDependencyHelpers
8
- # Build detailed error message for circular dependencies
9
- # @param cycle_path [Array<Class>] The circular dependency path
10
- # @param context [String] Context of the error (dependency, runtime)
11
- # @return [String] Formatted error message
12
- def self.build_error_message(cycle_path, context = "dependency")
13
- path_names = cycle_path.map { |klass| klass.name || klass.to_s }
14
-
15
- message = "Circular dependency detected!\n"
16
- message += "Cycle: #{path_names.join(" → ")}\n\n"
17
- message += "The #{context} chain is:\n"
18
-
19
- cycle_path.each_cons(2).with_index do |(from, to), index|
20
- action = (context == "dependency") ? "depends on" : "is trying to build"
21
- message += " #{index + 1}. #{from.name} #{action} → #{to.name}\n"
22
- end
23
-
24
- message += "\nThis creates an infinite loop that cannot be resolved." if context == "dependency"
25
- message
26
- end
27
- end
28
-
29
- # Common dependency utility functions
30
- module DependencyUtils
31
- # Extract class from dependency hash
32
- # @param dep [Hash] Dependency information
33
- # @return [Class] The dependency class
34
- def extract_class(dep)
35
- klass = dep[:klass]
36
- klass.is_a?(Reference) ? klass.deref : klass
37
- end
38
- end
39
-
40
- # Common task build utility functions
41
- module TaskBuildHelpers
42
- # Format arguments hash for display in error messages
43
- # @param args [Hash] Arguments hash
44
- # @return [String] Formatted arguments string
45
- def self.format_args(args)
46
- return "" if args.nil? || args.empty?
47
-
48
- formatted_pairs = args.map do |key, value|
49
- "#{key}: #{value.inspect}"
50
- end
51
- "{#{formatted_pairs.join(", ")}}"
52
- end
53
-
54
- # Execute block with comprehensive build logging and progress display
55
- # @param task_name [String] Name of the task being built
56
- # @param dependencies [Array] List of dependencies
57
- # @param args [Hash] Build arguments for parametrized builds
58
- # @yield Block to execute with logging
59
- # @return [Object] Result of the block execution
60
- def self.with_build_logging(task_name, dependencies: [], args: nil)
61
- build_start_time = Time.now
62
-
63
- begin
64
- # Traditional logging first (before any stdout redirection)
65
- Taski.logger.task_build_start(task_name, dependencies: dependencies, args: args)
66
-
67
- # Show progress display if enabled (this may redirect stdout)
68
- Taski.progress_display&.start_task(task_name, dependencies: dependencies)
69
-
70
- result = yield
71
- duration = Time.now - build_start_time
72
-
73
- # Complete progress display first (this restores stdout)
74
- Taski.progress_display&.complete_task(task_name, duration: duration)
75
-
76
- # Then do logging (on restored stdout)
77
- begin
78
- Taski.logger.task_build_complete(task_name, duration: duration)
79
- rescue IOError
80
- # If logger fails due to closed stream, write to STDERR instead
81
- warn "[#{Time.now.strftime("%Y-%m-%d %H:%M:%S.%3N")}] INFO Taski: Task build completed (task=#{task_name}, duration_ms=#{(duration * 1000).round(2)})"
82
- end
83
-
84
- result
85
- rescue => e
86
- duration = Time.now - build_start_time
87
-
88
- # Complete progress display first (with error)
89
- Taski.progress_display&.fail_task(task_name, error: e, duration: duration)
90
-
91
- # Then do error logging (on restored stdout)
92
- begin
93
- Taski.logger.task_build_failed(task_name, error: e, duration: duration)
94
- rescue IOError
95
- # If logger fails due to closed stream, write to STDERR instead
96
- warn "[#{Time.now.strftime("%Y-%m-%d %H:%M:%S.%3N")}] ERROR Taski: Task build failed (task=#{task_name}, error=#{e.message}, duration_ms=#{(duration * 1000).round(2)})"
97
- end
98
-
99
- error_message = "Failed to build task #{task_name}"
100
- error_message += " with args #{format_args(args)}" if args && !args.empty?
101
- error_message += ": #{e.message}"
102
- raise TaskBuildError, error_message
103
- end
104
- end
105
- end
106
- end
107
- end