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
data/examples/README.md CHANGED
@@ -1,69 +1,122 @@
1
1
  # Taski Examples
2
2
 
3
- Learn Taski through practical examples, from basic concepts to advanced patterns.
3
+ Practical examples demonstrating Taski's parallel task execution and automatic dependency resolution.
4
4
 
5
- ## Getting Started
5
+ ## Examples
6
6
 
7
- Start with these examples in order:
7
+ ### 1. quick_start.rb - Getting Started
8
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
9
+ Basic Exports API usage and automatic dependency resolution.
13
10
 
14
11
  ```bash
15
12
  ruby examples/quick_start.rb
16
13
  ```
17
14
 
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
15
+ **Covers:**
16
+ - Task definition with `exports`
17
+ - Automatic dependency detection
18
+ - Accessing exported values
19
+
20
+ ---
21
+
22
+ ### 2. section_demo.rb - Runtime Implementation Selection
23
+
24
+ Switch implementations based on environment using the Section API.
23
25
 
24
26
  ```bash
25
- # Interactive mode with rich spinner
26
- ruby examples/progress_demo.rb
27
+ ruby examples/section_demo.rb
28
+ ```
29
+
30
+ **Covers:**
31
+ - `interfaces` for defining contracts
32
+ - Environment-specific implementations
33
+ - Dependency tree visualization with `.tree`
34
+
35
+ ---
36
+
37
+ ### 3. context_demo.rb - Runtime Context
38
+
39
+ Access execution context information from any task.
27
40
 
28
- # Clean output mode (no spinner)
29
- ruby examples/progress_demo.rb > build.log 2>&1
30
- cat build.log
41
+ ```bash
42
+ ruby examples/context_demo.rb
31
43
  ```
32
44
 
33
- ### 3. **[section_configuration.rb](section_configuration.rb)** - Section-based Configuration Management
34
- - Dynamic implementation selection with Taski::Section
35
- - Environment-specific configuration
36
- - Section dependency resolution
37
- - Complex configuration hierarchies
45
+ **Covers:**
46
+ - `Taski::Context.working_directory`
47
+ - `Taski::Context.started_at`
48
+ - `Taski::Context.root_task`
49
+
50
+ ---
51
+
52
+ ### 4. reexecution_demo.rb - Cache Control
53
+
54
+ Understand caching behavior and re-execution patterns.
38
55
 
39
56
  ```bash
40
- ruby examples/section_configuration.rb
57
+ ruby examples/reexecution_demo.rb
41
58
  ```
42
59
 
43
- ### 4. **[advanced_patterns.rb](advanced_patterns.rb)** - Complex Dependency Patterns
44
- - Mixed Exports API and Define API usage
45
- - Environment-specific dependencies
46
- - Feature flags and conditional logic
47
- - Task reset and rebuild scenarios
60
+ **Covers:**
61
+ - Default caching behavior
62
+ - `Task.new` for fresh instances
63
+ - `Task.reset!` for clearing caches
64
+
65
+ ---
66
+
67
+ ### 5. data_pipeline_demo.rb - Real-World Pipeline
68
+
69
+ A realistic ETL pipeline with parallel data fetching.
48
70
 
49
71
  ```bash
50
- ruby examples/advanced_patterns.rb
72
+ ruby examples/data_pipeline_demo.rb
51
73
  ```
52
74
 
53
- ## Key Concepts Demonstrated
75
+ **Covers:**
76
+ - Multiple data sources in parallel
77
+ - Data transformation stages
78
+ - Aggregation and reporting
54
79
 
55
- - **Exports API**: Static dependencies with `exports :property`
56
- - **Define API**: Dynamic dependencies with `define :property, -> { ... }`
57
- - **Section API**: Dynamic implementation selection with `Taski::Section`
58
- - **Dependency Resolution**: Automatic dependency detection for sections
59
- - **Progress Display**: Rich terminal output with spinners and colors
60
- - **Output Capture**: Tail-style display of task output
61
- - **Environment Configuration**: Different behavior based on runtime settings
62
- - **Error Handling**: Graceful failure with progress indicators
80
+ ---
81
+
82
+ ### 6. parallel_progress_demo.rb - Progress Display
83
+
84
+ Real-time progress visualization during parallel execution.
85
+
86
+ ```bash
87
+ TASKI_FORCE_PROGRESS=1 ruby examples/parallel_progress_demo.rb
88
+ ```
89
+
90
+ **Covers:**
91
+ - Parallel task execution
92
+ - Progress display with spinners
93
+ - Execution timing
94
+
95
+ ---
96
+
97
+ ## Quick Reference
98
+
99
+ | Example | Feature | Complexity |
100
+ |---------|---------|------------|
101
+ | quick_start | Exports API | Basic |
102
+ | section_demo | Section API | Intermediate |
103
+ | context_demo | Context API | Intermediate |
104
+ | reexecution_demo | Cache Control | Intermediate |
105
+ | data_pipeline_demo | ETL Pipeline | Advanced |
106
+ | parallel_progress_demo | Progress Display | Advanced |
107
+
108
+ ## Running All Examples
109
+
110
+ ```bash
111
+ # Run each example
112
+ for f in examples/*.rb; do echo "=== $f ===" && ruby "$f" && echo; done
113
+
114
+ # With progress display (for parallel_progress_demo)
115
+ TASKI_FORCE_PROGRESS=1 ruby examples/parallel_progress_demo.rb
116
+ ```
63
117
 
64
118
  ## Next Steps
65
119
 
66
- After exploring these examples:
67
- - Read the main documentation
68
- - Examine the test files for more usage patterns
69
- - Check out the source code in `lib/taski/`
120
+ - [Main README](../README.md) - Full documentation
121
+ - [Tests](../test/) - More usage patterns
122
+ - [Source](../lib/taski/) - Implementation details
@@ -0,0 +1,112 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # Taski Context API Example
5
+ #
6
+ # This example demonstrates the Context API for accessing runtime information:
7
+ # - working_directory: Where execution started
8
+ # - started_at: When execution began
9
+ # - root_task: The first task class that was called
10
+ #
11
+ # Run: ruby examples/context_demo.rb
12
+
13
+ require_relative "../lib/taski"
14
+
15
+ puts "Taski Context API Example"
16
+ puts "=" * 40
17
+
18
+ # Task that uses context information for logging
19
+ class SetupTask < Taski::Task
20
+ exports :setup_info
21
+
22
+ def run
23
+ puts "Setup running..."
24
+ puts " Working directory: #{Taski::Context.working_directory}"
25
+ puts " Started at: #{Taski::Context.started_at}"
26
+ puts " Root task: #{Taski::Context.root_task}"
27
+
28
+ @setup_info = {
29
+ directory: Taski::Context.working_directory,
30
+ timestamp: Taski::Context.started_at
31
+ }
32
+ end
33
+ end
34
+
35
+ # Task that creates files relative to working directory
36
+ class FileProcessor < Taski::Task
37
+ exports :output_path
38
+
39
+ def run
40
+ # Use context to determine output location
41
+ base_dir = Taski::Context.working_directory
42
+ @output_path = File.join(base_dir, "tmp", "output.txt")
43
+
44
+ puts "FileProcessor: Would write to #{@output_path}"
45
+ puts " (relative to working directory)"
46
+ end
47
+ end
48
+
49
+ # Task that logs execution timing
50
+ class TimingTask < Taski::Task
51
+ exports :duration_info
52
+
53
+ def run
54
+ start_time = Taski::Context.started_at
55
+ current_time = Time.now
56
+ elapsed = current_time - start_time
57
+
58
+ puts "TimingTask: #{elapsed.round(3)}s since execution started"
59
+
60
+ @duration_info = {
61
+ started: start_time,
62
+ current: current_time,
63
+ elapsed_seconds: elapsed
64
+ }
65
+ end
66
+ end
67
+
68
+ # Main task that depends on others
69
+ class MainTask < Taski::Task
70
+ exports :summary
71
+
72
+ def run
73
+ puts "\nMainTask executing..."
74
+ puts " Root task is: #{Taski::Context.root_task}"
75
+
76
+ # Access dependencies
77
+ setup = SetupTask.setup_info
78
+ output = FileProcessor.output_path
79
+ timing = TimingTask.duration_info
80
+
81
+ @summary = {
82
+ setup: setup,
83
+ output_path: output,
84
+ timing: timing,
85
+ root_task: Taski::Context.root_task.to_s
86
+ }
87
+
88
+ puts "\nExecution Summary:"
89
+ puts " Setup directory: #{setup[:directory]}"
90
+ puts " Output path: #{output}"
91
+ puts " Total elapsed: #{timing[:elapsed_seconds].round(3)}s"
92
+ end
93
+ end
94
+
95
+ puts "\n1. Running MainTask (context will show MainTask as root)"
96
+ puts "-" * 40
97
+ MainTask.run
98
+
99
+ puts "\n" + "=" * 40
100
+ puts "\n2. Running SetupTask directly (context will show SetupTask as root)"
101
+ puts "-" * 40
102
+ SetupTask.reset!
103
+ SetupTask.run
104
+
105
+ puts "\n" + "=" * 40
106
+ puts "\n3. Dependency Tree"
107
+ puts "-" * 40
108
+ puts MainTask.tree
109
+
110
+ puts "\n" + "=" * 40
111
+ puts "Context API demonstration complete!"
112
+ puts "Note: Context provides runtime information without affecting dependency analysis."
@@ -0,0 +1,231 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # Taski Data Pipeline Example
5
+ #
6
+ # This example demonstrates a realistic data processing pipeline:
7
+ # - Section API for switching data sources (production vs test)
8
+ # - Multiple data sources fetched in parallel
9
+ # - Data transformation and aggregation
10
+ #
11
+ # Run: ruby examples/data_pipeline_demo.rb
12
+ # With progress: TASKI_FORCE_PROGRESS=1 ruby examples/data_pipeline_demo.rb
13
+
14
+ require_relative "../lib/taski"
15
+
16
+ # Section: Data source abstraction
17
+ # Switch between production API and test fixtures
18
+ class DataSourceSection < Taski::Section
19
+ interfaces :users, :sales, :activities
20
+
21
+ def impl
22
+ (ENV["USE_TEST_DATA"] == "true") ? TestData : ProductionData
23
+ end
24
+
25
+ # Production: Fetch from APIs (simulated with delays)
26
+ class ProductionData < Taski::Task
27
+ def run
28
+ puts " [ProductionData] Fetching from APIs..."
29
+ sleep(0.3)
30
+
31
+ @users = [
32
+ {id: 1, name: "Alice", department: "Engineering"},
33
+ {id: 2, name: "Bob", department: "Sales"},
34
+ {id: 3, name: "Charlie", department: "Engineering"},
35
+ {id: 4, name: "Diana", department: "Marketing"}
36
+ ]
37
+
38
+ @sales = [
39
+ {user_id: 2, amount: 1000, date: "2024-01"},
40
+ {user_id: 2, amount: 1500, date: "2024-02"},
41
+ {user_id: 4, amount: 800, date: "2024-01"}
42
+ ]
43
+
44
+ @activities = [
45
+ {user_id: 1, action: :commit, count: 45},
46
+ {user_id: 3, action: :commit, count: 32},
47
+ {user_id: 1, action: :review, count: 12},
48
+ {user_id: 3, action: :review, count: 8}
49
+ ]
50
+
51
+ puts " [ProductionData] Loaded #{@users.size} users, #{@sales.size} sales, #{@activities.size} activities"
52
+ end
53
+ end
54
+
55
+ # Test: Minimal fixture data (no delays)
56
+ class TestData < Taski::Task
57
+ def run
58
+ puts " [TestData] Loading test fixtures..."
59
+
60
+ @users = [
61
+ {id: 1, name: "Test User", department: "Test Dept"}
62
+ ]
63
+
64
+ @sales = [
65
+ {user_id: 1, amount: 100, date: "2024-01"}
66
+ ]
67
+
68
+ @activities = [
69
+ {user_id: 1, action: :commit, count: 10}
70
+ ]
71
+
72
+ puts " [TestData] Loaded minimal test data"
73
+ end
74
+ end
75
+ end
76
+
77
+ # Section: Report format selection
78
+ class ReportFormatSection < Taski::Section
79
+ interfaces :format_report
80
+
81
+ def impl
82
+ (ENV["REPORT_FORMAT"] == "json") ? JsonFormat : TextFormat
83
+ end
84
+
85
+ class TextFormat < Taski::Task
86
+ def run
87
+ @format_report = ->(report) {
88
+ report.map do |dept, stats|
89
+ "#{dept}: #{stats[:user_count]} users, $#{stats[:total_sales]} sales"
90
+ end.join("\n")
91
+ }
92
+ end
93
+ end
94
+
95
+ class JsonFormat < Taski::Task
96
+ def run
97
+ require "json"
98
+ @format_report = ->(report) { JSON.pretty_generate(report) }
99
+ end
100
+ end
101
+ end
102
+
103
+ # Transform: Enrich users with sales data
104
+ class EnrichWithSales < Taski::Task
105
+ exports :users_with_sales
106
+
107
+ def run
108
+ users = DataSourceSection.users
109
+ sales = DataSourceSection.sales
110
+
111
+ sales_by_user = sales.group_by { |s| s[:user_id] }
112
+ .transform_values { |records| records.sum { |r| r[:amount] } }
113
+
114
+ @users_with_sales = users.map do |user|
115
+ user.merge(total_sales: sales_by_user[user[:id]] || 0)
116
+ end
117
+
118
+ puts " [EnrichWithSales] Enriched #{@users_with_sales.size} users"
119
+ end
120
+ end
121
+
122
+ # Transform: Enrich users with activity data
123
+ class EnrichWithActivities < Taski::Task
124
+ exports :users_with_activities
125
+
126
+ def run
127
+ users = DataSourceSection.users
128
+ activities = DataSourceSection.activities
129
+
130
+ activities_by_user = activities.group_by { |a| a[:user_id] }
131
+ .transform_values do |records|
132
+ records.to_h { |r| [r[:action], r[:count]] }
133
+ end
134
+
135
+ @users_with_activities = users.map do |user|
136
+ user.merge(activities: activities_by_user[user[:id]] || {})
137
+ end
138
+
139
+ puts " [EnrichWithActivities] Enriched #{@users_with_activities.size} users"
140
+ end
141
+ end
142
+
143
+ # Aggregate: Combine enrichments into profiles
144
+ class BuildProfiles < Taski::Task
145
+ exports :profiles
146
+
147
+ def run
148
+ users_sales = EnrichWithSales.users_with_sales
149
+ users_activities = EnrichWithActivities.users_with_activities
150
+
151
+ activities_map = users_activities.to_h { |u| [u[:id], u[:activities]] }
152
+
153
+ @profiles = users_sales.map do |user|
154
+ user.merge(activities: activities_map[user[:id]] || {})
155
+ end
156
+
157
+ puts " [BuildProfiles] Built #{@profiles.size} profiles"
158
+ end
159
+ end
160
+
161
+ # Output: Generate department report
162
+ class GenerateReport < Taski::Task
163
+ exports :report, :formatted_output
164
+
165
+ def run
166
+ profiles = BuildProfiles.profiles
167
+ formatter = ReportFormatSection.format_report
168
+
169
+ by_department = profiles.group_by { |p| p[:department] }
170
+
171
+ @report = by_department.transform_values do |dept_users|
172
+ {
173
+ user_count: dept_users.size,
174
+ total_sales: dept_users.sum { |u| u[:total_sales] },
175
+ total_commits: dept_users.sum { |u| u[:activities][:commit] || 0 },
176
+ total_reviews: dept_users.sum { |u| u[:activities][:review] || 0 }
177
+ }
178
+ end
179
+
180
+ @formatted_output = formatter.call(@report)
181
+ puts " [GenerateReport] Generated report for #{@report.size} departments"
182
+ end
183
+ end
184
+
185
+ # Demo execution
186
+ puts "Taski Data Pipeline Demo"
187
+ puts "=" * 50
188
+
189
+ puts "\n1. Dependency Tree"
190
+ puts "-" * 50
191
+ puts GenerateReport.tree
192
+
193
+ puts "\n2. Production Data (default)"
194
+ puts "-" * 50
195
+ ENV["USE_TEST_DATA"] = "false"
196
+ ENV["REPORT_FORMAT"] = "text"
197
+
198
+ start_time = Time.now
199
+ GenerateReport.run
200
+ elapsed = Time.now - start_time
201
+
202
+ puts "\nReport (text format):"
203
+ puts GenerateReport.formatted_output
204
+ puts "\nCompleted in #{elapsed.round(3)}s"
205
+
206
+ puts "\n" + "=" * 50
207
+ puts "\n3. Test Data with JSON Format"
208
+ puts "-" * 50
209
+ ENV["USE_TEST_DATA"] = "true"
210
+ ENV["REPORT_FORMAT"] = "json"
211
+
212
+ # Reset all tasks for fresh execution
213
+ [DataSourceSection, ReportFormatSection, EnrichWithSales,
214
+ EnrichWithActivities, BuildProfiles, GenerateReport].each(&:reset!)
215
+
216
+ start_time = Time.now
217
+ GenerateReport.run
218
+ elapsed = Time.now - start_time
219
+
220
+ puts "\nReport (JSON format):"
221
+ puts GenerateReport.formatted_output
222
+ puts "\nCompleted in #{elapsed.round(3)}s"
223
+
224
+ puts "\n" + "=" * 50
225
+ puts "Pipeline demonstration complete!"
226
+ puts "\nKey concepts demonstrated:"
227
+ puts " - DataSourceSection: Switch between production/test data"
228
+ puts " - ReportFormatSection: Switch output format (text/JSON)"
229
+ puts " - Parallel execution of independent transforms"
230
+ puts "\nTry with progress display:"
231
+ puts " TASKI_FORCE_PROGRESS=1 ruby examples/data_pipeline_demo.rb"
@@ -0,0 +1,72 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require_relative "../lib/taski"
5
+
6
+ # Demo tasks that simulate parallel execution with progress display
7
+ # Run with: TASKI_FORCE_PROGRESS=1 ruby examples/parallel_progress_demo.rb
8
+
9
+ class DownloadLayer1 < Taski::Task
10
+ exports :layer1_data
11
+
12
+ def run
13
+ sleep(2.3) # Simulate download
14
+ @layer1_data = "Layer 1 data (base image)"
15
+ end
16
+ end
17
+
18
+ class DownloadLayer2 < Taski::Task
19
+ exports :layer2_data
20
+
21
+ def run
22
+ sleep(5.5) # Simulate slower download
23
+ @layer2_data = "Layer 2 data (dependencies)"
24
+ end
25
+ end
26
+
27
+ class DownloadLayer3 < Taski::Task
28
+ exports :layer3_data
29
+
30
+ def run
31
+ sleep(0.2) # Simulate fast download
32
+ @layer3_data = "Layer 3 data (application)"
33
+ end
34
+ end
35
+
36
+ class ExtractLayers < Taski::Task
37
+ exports :extracted_data
38
+
39
+ def run
40
+ # This task depends on all download tasks (via static analysis)
41
+ layer1 = DownloadLayer1.layer1_data
42
+ layer2 = DownloadLayer2.layer2_data
43
+ layer3 = DownloadLayer3.layer3_data
44
+
45
+ sleep(0.3) # Simulate extraction
46
+ @extracted_data = "Extracted: #{layer1}, #{layer2}, #{layer3}"
47
+ end
48
+ end
49
+
50
+ class VerifyImage < Taski::Task
51
+ exports :verification_result
52
+
53
+ def run
54
+ # Depends on ExtractLayers
55
+ data = ExtractLayers.extracted_data
56
+
57
+ sleep(0.2) # Simulate verification
58
+ @verification_result = "Verified: #{data}"
59
+ end
60
+ end
61
+
62
+ # Start progress display
63
+ Taski.progress_display&.start
64
+
65
+ # Execute the final task (all dependencies will be resolved automatically)
66
+ result = VerifyImage.verification_result
67
+
68
+ # Stop progress display
69
+ Taski.progress_display&.stop
70
+
71
+ puts "\n\nFinal result:"
72
+ puts result
@@ -19,7 +19,7 @@ puts "=" * 30
19
19
  class DatabaseSetup < Taski::Task
20
20
  exports :connection_string
21
21
 
22
- def build
22
+ def run
23
23
  @connection_string = "postgresql://localhost/myapp"
24
24
  puts "Database configured"
25
25
  end
@@ -28,14 +28,14 @@ end
28
28
  class APIServer < Taski::Task
29
29
  exports :port
30
30
 
31
- def build
32
- # Automatic dependency: DatabaseSetup will be built first
31
+ def run
32
+ # Automatic dependency: DatabaseSetup will be executed first
33
33
  puts "Starting API with #{DatabaseSetup.connection_string}"
34
34
  @port = 3000
35
35
  end
36
36
  end
37
37
 
38
38
  # Execute - dependencies are resolved automatically
39
- APIServer.build
39
+ APIServer.run
40
40
 
41
41
  puts "\n✅ Result: APIServer running on port #{APIServer.port}"