taski 0.8.0 → 0.8.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f7677c0f3995a7c61b5850fb25c82c60626287584e5c7f918939ededc045e9ea
4
- data.tar.gz: d470969c88a4df51503487aacdf2c6261b65e6ed75ee3c7cc2ff744dfd750365
3
+ metadata.gz: 7c841d7a7a8e632045f42b090be2c6b10a9ef1510c9b9298bc50737f89486f28
4
+ data.tar.gz: 540f4595d667f191ac2a36464529e324fd56c5a5466dbcc2580b5227030501b5
5
5
  SHA512:
6
- metadata.gz: 5f93d9e7d10f7104851266f0252ec4365d445a90d3a25b885f289df5d8caafbe9f9250ff9236e4cca0791749100c83c46735a8e98e5c1b675662199ba7a0e547
7
- data.tar.gz: eb4fb9f806cdd5097e0d3321d4cda9e3df183d4850c4aa8161ba09b71666444166f05b5e795b330227076d85f7410adbe2fc4f1e2b19c66d007ff1632d354f97
6
+ metadata.gz: c4b2064e55edde2f504fd8c857efff572faf6de8466983c0081c2ca902c63784c75d121c482691cf24e1b8f80a863c97c2268e358271692967adc5612933da28
7
+ data.tar.gz: b56270d6324127635290a906bb6d7361a8c9609ad071ea307b26dcd3b16489c073be909e744680b52a202ab99019c611d9a0112cf2b18fc180f8113fb3fcef5a
data/CHANGELOG.md CHANGED
@@ -7,6 +7,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.8.1] - 2026-01-26
11
+
12
+ ### Added
13
+ - `Taski.message` API for user-facing output during task execution ([#129](https://github.com/ahogappa/taski/pull/129))
14
+
15
+ ### Fixed
16
+ - Count unselected section candidates as completed in SimpleProgressDisplay ([#128](https://github.com/ahogappa/taski/pull/128))
17
+ - Prioritize environment variable over code settings for progress_mode ([#127](https://github.com/ahogappa/taski/pull/127))
18
+
10
19
  ## [0.8.0] - 2026-01-23
11
20
 
12
21
  ### Added
@@ -0,0 +1,57 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # Demonstrates Taski.message API
5
+ #
6
+ # Taski.message outputs text to the user without being captured by TaskOutputRouter.
7
+ # Messages are queued during progress display and shown after task completion.
8
+ #
9
+ # Usage:
10
+ # ruby examples/message_demo.rb
11
+ # TASKI_FORCE_PROGRESS=1 ruby examples/message_demo.rb # Force progress display
12
+
13
+ require_relative "../lib/taski"
14
+
15
+ class ProcessDataTask < Taski::Task
16
+ exports :processed_count
17
+
18
+ def run
19
+ puts "Starting data processing..." # Captured by TaskOutputRouter
20
+
21
+ # Simulate processing
22
+ 5.times do |i|
23
+ puts "Processing batch #{i + 1}/5..." # Captured
24
+ sleep 0.3
25
+ end
26
+
27
+ @processed_count = 42
28
+
29
+ # These messages bypass TaskOutputRouter and appear after execution
30
+ Taski.message("Created: /tmp/output.txt")
31
+ Taski.message("Summary: #{@processed_count} items processed successfully")
32
+ end
33
+ end
34
+
35
+ class GenerateReportTask < Taski::Task
36
+ exports :report_path
37
+
38
+ def run
39
+ # Dependency: ProcessDataTask will be executed first
40
+ count = ProcessDataTask.processed_count
41
+ puts "Generating report for #{count} items..." # Captured
42
+
43
+ sleep 0.5
44
+
45
+ @report_path = "/tmp/report.pdf"
46
+
47
+ Taski.message("Report available at: #{@report_path}")
48
+ end
49
+ end
50
+
51
+ puts "=== Taski.message Demo ==="
52
+ puts
53
+
54
+ GenerateReportTask.run
55
+
56
+ puts
57
+ puts "=== Done ==="
@@ -81,6 +81,7 @@ module Taski
81
81
  @output_capture = nil
82
82
  @original_stdout = nil
83
83
  @runtime_dependencies = {}
84
+ @message_queue = []
84
85
  end
85
86
 
86
87
  # Check if output capture is already active.
@@ -89,6 +90,31 @@ module Taski
89
90
  @monitor.synchronize { !@output_capture.nil? }
90
91
  end
91
92
 
93
+ # Queue a message to be displayed after execution completes.
94
+ # Thread-safe for access from worker threads.
95
+ #
96
+ # @param text [String] The message text to queue
97
+ def queue_message(text)
98
+ @monitor.synchronize { @message_queue << text }
99
+ end
100
+
101
+ # Flush all queued messages to the given output.
102
+ # Clears the queue after flushing.
103
+ #
104
+ # @param output [IO] The output stream to write messages to
105
+ def flush_messages(output)
106
+ messages = @monitor.synchronize { @message_queue.dup.tap { @message_queue.clear } }
107
+ messages.each { |msg| output.puts(msg) }
108
+ end
109
+
110
+ # Get the original stdout before output capture was set up.
111
+ # Thread-safe accessor.
112
+ #
113
+ # @return [IO, nil] The original stdout or nil if not captured
114
+ def original_stdout
115
+ @monitor.synchronize { @original_stdout }
116
+ end
117
+
92
118
  # Set up output capture for inline progress display.
93
119
  # Creates TaskOutputRouter and replaces $stdout.
94
120
  # Should only be called when progress display is active and not already set up.
@@ -418,9 +418,17 @@ module Taski
418
418
  ensure
419
419
  stop_progress_display
420
420
  @saved_output_capture = @execution_context.output_capture
421
+ flush_queued_messages if should_teardown_capture
421
422
  teardown_output_capture if should_teardown_capture
422
423
  end
423
424
 
425
+ # Flush queued messages from ExecutionContext to original stdout.
426
+ # Called after progress display stops to show user messages.
427
+ def flush_queued_messages
428
+ output = @execution_context.original_stdout || $stdout
429
+ @execution_context.flush_messages(output)
430
+ end
431
+
424
432
  def create_default_execution_context
425
433
  context = ExecutionContext.new
426
434
  progress = Taski.progress_display
@@ -34,6 +34,7 @@ module Taski
34
34
  @spinner_index = 0
35
35
  @renderer_thread = nil
36
36
  @running = false
37
+ @section_candidates = {} # section_class => [candidate_classes]
37
38
  end
38
39
 
39
40
  protected
@@ -44,9 +45,18 @@ module Taski
44
45
  end
45
46
 
46
47
  # Template method: Called when a section impl is registered
47
- def on_section_impl_registered(_section_class, impl_class)
48
+ def on_section_impl_registered(section_class, impl_class)
48
49
  @tasks[impl_class] ||= TaskProgress.new
49
50
  @tasks[impl_class].is_impl_candidate = false
51
+
52
+ # Mark unselected candidates as completed (skipped)
53
+ candidates = @section_candidates[section_class] || []
54
+ candidates.each do |candidate|
55
+ next if candidate == impl_class
56
+ progress = @tasks[candidate]
57
+ next unless progress
58
+ progress.run_state = :completed
59
+ end
50
60
  end
51
61
 
52
62
  # Template method: Determine if display should activate
@@ -83,6 +93,23 @@ module Taski
83
93
  # Use TreeProgressDisplay's static method for tree building
84
94
  tree = TreeProgressDisplay.build_tree_node(@root_task_class)
85
95
  register_tasks_from_tree(tree)
96
+ collect_section_candidates(tree)
97
+ end
98
+
99
+ def collect_section_candidates(node)
100
+ return unless node
101
+
102
+ task_class = node[:task_class]
103
+
104
+ # If this is a section, collect its implementation candidates
105
+ if node[:is_section]
106
+ candidates = node[:children]
107
+ .select { |c| c[:is_impl_candidate] }
108
+ .map { |c| c[:task_class] }
109
+ @section_candidates[task_class] = candidates unless candidates.empty?
110
+ end
111
+
112
+ node[:children].each { |child| collect_section_candidates(child) }
86
113
  end
87
114
 
88
115
  def render_live
data/lib/taski/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Taski
4
- VERSION = "0.8.0"
4
+ VERSION = "0.8.1"
5
5
  end
data/lib/taski.rb CHANGED
@@ -140,6 +140,7 @@ module Taski
140
140
 
141
141
  @args_monitor = Monitor.new
142
142
  @env_monitor = Monitor.new
143
+ @message_monitor = Monitor.new
143
144
 
144
145
  # Get the current runtime arguments
145
146
  # @return [Args, nil] The current args or nil if no task is running
@@ -153,6 +154,23 @@ module Taski
153
154
  @env_monitor.synchronize { @env }
154
155
  end
155
156
 
157
+ # Output a message to the user without being captured by TaskOutputRouter.
158
+ # During task execution with progress display, messages are queued and
159
+ # displayed after execution completes. Without progress display or outside
160
+ # task execution, messages are output immediately.
161
+ #
162
+ # @param text [String] The message text to display
163
+ def self.message(text)
164
+ @message_monitor.synchronize do
165
+ context = Execution::ExecutionContext.current
166
+ if context&.output_capture_active?
167
+ context.queue_message(text)
168
+ else
169
+ $stdout.puts(text)
170
+ end
171
+ end
172
+ end
173
+
156
174
  # Start new execution environment (internal use only)
157
175
  # @api private
158
176
  # @return [Boolean] true if this call created the env, false if env already existed
@@ -229,9 +247,14 @@ module Taski
229
247
  end
230
248
 
231
249
  # Get the current progress mode (:tree or :simple)
250
+ # Environment variable TASKI_PROGRESS_MODE takes precedence over code settings.
232
251
  # @return [Symbol] The current progress mode
233
252
  def self.progress_mode
234
- @progress_mode || progress_mode_from_env
253
+ if ENV["TASKI_PROGRESS_MODE"]
254
+ progress_mode_from_env
255
+ else
256
+ @progress_mode || :tree
257
+ end
235
258
  end
236
259
 
237
260
  # Set the progress mode (:tree or :simple)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: taski
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.0
4
+ version: 0.8.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - ahogappa
@@ -62,6 +62,7 @@ files:
62
62
  - examples/data_pipeline_demo.rb
63
63
  - examples/group_demo.rb
64
64
  - examples/large_tree_demo.rb
65
+ - examples/message_demo.rb
65
66
  - examples/nested_section_demo.rb
66
67
  - examples/parallel_progress_demo.rb
67
68
  - examples/quick_start.rb
@@ -120,7 +121,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
120
121
  - !ruby/object:Gem::Version
121
122
  version: '0'
122
123
  requirements: []
123
- rubygems_version: 4.0.3
124
+ rubygems_version: 4.0.4
124
125
  specification_version: 4
125
126
  summary: A simple yet powerful Ruby task runner with static dependency resolution
126
127
  (in development).