ruby-progress 1.3.1 → 1.3.4

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.
@@ -13,12 +13,17 @@ module RubyProgress
13
13
  end
14
14
 
15
15
  def self.clear_line(output_stream = :stderr)
16
- case output_stream
17
- when :stdout
18
- $stdout.print "\r\e[K"
19
- else
20
- $stderr.print "\r\e[K"
21
- end
16
+ io = case output_stream
17
+ when :stdout
18
+ $stdout
19
+ when :stderr
20
+ $stderr
21
+ else
22
+ # allow passing an IO-like object (e.g. StringIO) directly
23
+ output_stream.respond_to?(:print) ? output_stream : $stderr
24
+ end
25
+
26
+ io.print "\r\e[K"
22
27
  end
23
28
 
24
29
  # Enhanced line clearing for daemon mode that handles output interruption
@@ -33,39 +38,55 @@ module RubyProgress
33
38
  # @param success [Boolean] Whether this represents success or failure
34
39
  # @param show_checkmark [Boolean] Whether to show checkmark/X symbols
35
40
  # @param output_stream [Symbol] Where to output (:stdout, :stderr, :warn)
36
- def self.display_completion(message, success: true, show_checkmark: false, output_stream: :warn)
41
+ def self.display_completion(message, success: true, show_checkmark: false, output_stream: :warn, icons: {})
37
42
  return unless message
38
43
 
39
- mark = ''
40
- if show_checkmark
41
- mark = success ? '✅ ' : '🛑 '
42
- end
44
+ mark = if show_checkmark
45
+ icon = success ? (icons[:success] || '✅') : (icons[:error] || '🛑')
46
+ "#{icon} "
47
+ else
48
+ ''
49
+ end
43
50
 
44
51
  formatted_message = "#{mark}#{message}"
45
52
 
46
- case output_stream
47
- when :stdout
48
- puts formatted_message
49
- when :stderr
50
- warn formatted_message
51
- when :warn
52
- # Ensure we're at the beginning of a fresh line, clear it, then display message
53
- $stderr.print "\r\e[2K"
54
- $stderr.flush
53
+ # Resolve destination IO: support symbols (:stdout/:stderr/:warn) or an IO-like object
54
+ dest_io = case output_stream
55
+ when :stdout
56
+ $stdout
57
+ when :stderr
58
+ $stderr
59
+ when :warn
60
+ $stderr
61
+ else
62
+ output_stream.respond_to?(:print) ? output_stream : $stderr
63
+ end
64
+
65
+ # Only treat explicit :stdout and :stderr as non-clearing requests.
66
+ # For :warn and any other/custom stream, clear the current line first.
67
+ unless %i[stdout stderr].include?(output_stream)
68
+ # Always include a leading carriage return when clearing to match
69
+ # terminal behavior expected by the test-suite.
70
+ dest_io.print "\r\e[2K"
71
+ dest_io.flush if dest_io.respond_to?(:flush)
72
+ end
73
+
74
+ # Emit the message to the resolved destination IO. Use warn/puts when targeting
75
+ # the standard streams to preserve familiar behavior (warn writes to $stderr).
76
+ if dest_io == $stdout
77
+ $stdout.puts formatted_message
78
+ elsif dest_io == $stderr
55
79
  warn formatted_message
56
80
  else
57
- # Ensure we're at the beginning of a fresh line, clear it, then display message
58
- $stderr.print "\r\e[2K"
59
- $stderr.flush
60
- warn formatted_message
81
+ dest_io.puts formatted_message
61
82
  end
62
83
  end
63
84
 
64
85
  # Clear current line and display completion message
65
86
  # Convenience method that combines line clearing with message display
66
- def self.complete_with_clear(message, success: true, show_checkmark: false, output_stream: :warn)
87
+ def self.complete_with_clear(message, success: true, show_checkmark: false, output_stream: :warn, icons: {})
67
88
  clear_line(output_stream) if output_stream != :warn # warn already includes clear in display_completion
68
- display_completion(message, success: success, show_checkmark: show_checkmark, output_stream: output_stream)
89
+ display_completion(message, success: success, show_checkmark: show_checkmark, output_stream: output_stream, icons: icons)
69
90
  end
70
91
 
71
92
  # Parse start/end characters for animation wrapping
@@ -2,11 +2,11 @@
2
2
 
3
3
  module RubyProgress
4
4
  # Main gem version
5
- VERSION = '1.3.1'
5
+ VERSION = '1.3.4'
6
6
 
7
7
  # Component-specific versions (patch bumps)
8
- WORM_VERSION = '1.1.3'
9
- TWIRL_VERSION = '1.1.3'
10
- RIPPLE_VERSION = '1.1.3'
11
- FILL_VERSION = '1.0.3'
8
+ WORM_VERSION = '1.1.4'
9
+ TWIRL_VERSION = '1.1.4'
10
+ RIPPLE_VERSION = '1.1.4'
11
+ FILL_VERSION = '1.0.4'
12
12
  end
@@ -65,6 +65,9 @@ module RubyProgress
65
65
  @error_text = options[:error]
66
66
  @show_checkmark = options[:checkmark] || false
67
67
  @output_stdout = options[:stdout] || false
68
+ @output_lines = options[:output_lines]
69
+ @output_position = options[:output_position]
70
+ @output_live = options[:stdout_live] || false
68
71
  @direction_mode = options[:direction] || :bidirectional
69
72
  @start_chars, @end_chars = RubyProgress::Utils.parse_ends(options[:ends])
70
73
  @running = false
@@ -76,13 +79,14 @@ module RubyProgress
76
79
  def display_completion_message(message, success)
77
80
  return unless message
78
81
 
79
- mark = ''
80
- if @show_checkmark
81
- mark = success ? '✅ ' : '🛑 '
82
- end
83
-
84
- # Clear animation line and output completion message on stderr
85
- $stderr.print "\r\e[2K#{mark}#{message}\n"
82
+ # Delegate to Utils.display_completion so carriage-return and clearing
83
+ # behavior is consistent across all indicators and respects TTY state.
84
+ RubyProgress::Utils.display_completion(
85
+ message,
86
+ success: success,
87
+ show_checkmark: @show_checkmark,
88
+ output_stream: :warn
89
+ )
86
90
  end
87
91
 
88
92
  def parse_speed(speed_input)
@@ -196,67 +200,11 @@ module RubyProgress
196
200
  }
197
201
  end
198
202
 
199
- def animation_loop
200
- position = 0
201
- direction = 1
202
-
203
- while @running
204
- message_part = @message && !@message.empty? ? "#{@message} " : ''
205
- # Enhanced line clearing for better daemon mode behavior
206
- $stderr.print "\r\e[2K#{@start_chars}#{message_part}#{generate_dots(position, direction)}#{@end_chars}"
207
- $stderr.flush
208
-
209
- sleep @speed
210
-
211
- position += direction
212
- if position >= @length - 1
213
- if @direction_mode == :forward_only
214
- position = 0
215
- else
216
- direction = -1
217
- end
218
- elsif position <= 0
219
- direction = 1
220
- end
221
- end
222
- end
223
-
224
- # Enhanced animation loop for daemon mode with aggressive line clearing
225
- def animation_loop_daemon_mode(stop_requested_proc: -> { false })
226
- position = 0
227
- direction = 1
228
- frame_count = 0
229
-
230
- while @running && !stop_requested_proc.call
231
- message_part = @message && !@message.empty? ? "#{@message} " : ''
232
-
233
- # Always clear current line
234
- $stderr.print "\r\e[2K"
235
-
236
- # Every few frames, use aggressive clearing to handle interruptions
237
- if (frame_count % 10).zero?
238
- $stderr.print "\e[1A\e[2K" # Move up and clear that line too (in case of interruption)
239
- $stderr.print "\r" # Return to start
240
- end
241
-
242
- $stderr.print "#{message_part}#{generate_dots(position, direction)}"
243
- $stderr.flush
244
-
245
- sleep @speed
246
- frame_count += 1
247
-
248
- position += direction
249
- if position >= @length - 1
250
- if @direction_mode == :forward_only
251
- position = 0
252
- else
253
- direction = -1
254
- end
255
- elsif position <= 0
256
- direction = 1
257
- end
258
- end
259
- end
203
+ # animation_loop and animation_loop_daemon_mode are implemented in
204
+ # the WormRunner module so they can share the redraw behavior that
205
+ # integrates with RubyProgress::OutputCapture. Do not redefine them
206
+ # here, otherwise the module implementations (which call
207
+ # @output_capture&.redraw) will be overridden.
260
208
 
261
209
  def generate_dots(ripple_position, direction)
262
210
  dots = Array.new(@length) { @style[:baseline] }