Class: Ruborg::Progress
- Inherits:
-
Object
- Object
- Ruborg::Progress
- Defined in:
- lib/ruborg/progress.rb
Overview
Terminal progress display: named stages, inline progress bar, and spinner. Writes to $stderr so stdout remains clean for –json or piped output. Degrades to plain text lines when output is not a TTY (piped / redirected).
Constant Summary collapse
- SPINNER_FRAMES =
%w[⠋ ⠙ ⠹ ⠸ ⠼ ⠴ ⠦ ⠧ ⠇ ⠏].freeze
- BAR_WIDTH =
28- LINE_WIDTH =
80
Instance Method Summary collapse
-
#bar(current, total, label = "") ⇒ Object
Redraw an inline progress bar.
-
#done(label = nil) ⇒ Object
Halt any in-progress display and print a completion line.
-
#initialize(output: $stderr) ⇒ Progress
constructor
A new instance of Progress.
-
#spin(label) ⇒ Object
Start a spinner on the current line for an indeterminate operation.
-
#stage(index, total, label) ⇒ Object
Print a numbered stage header: “[2/3] Label”.
-
#stop_spin ⇒ Object
Stop the spinner and erase its line.
-
#update_spin(label) ⇒ Object
Update the label on a running spinner without restarting it.
Constructor Details
#initialize(output: $stderr) ⇒ Progress
Returns a new instance of Progress.
12 13 14 15 16 17 18 |
# File 'lib/ruborg/progress.rb', line 12 def initialize(output: $stderr) @output = output @tty = output.respond_to?(:isatty) && output.isatty @spinner_thread = nil @spin_label = nil @spin_start = nil end |
Instance Method Details
#bar(current, total, label = "") ⇒ Object
Redraw an inline progress bar. Call once per item in a loop. label is truncated to fit the terminal line.
66 67 68 69 70 71 72 73 74 75 |
# File 'lib/ruborg/progress.rb', line 66 def (current, total, label = "") return unless @tty pct = total.positive? ? (current.to_f / total) : 0 filled = (BAR_WIDTH * pct).round = filled.positive? ? "#{"=" * (filled - 1)}>" : "" = .ljust(BAR_WIDTH) short_label = truncate_left(label.to_s, 28) @output.print "\r [#{}] #{current}/#{total} #{short_label.ljust(28)}" end |
#done(label = nil) ⇒ Object
Halt any in-progress display and print a completion line.
78 79 80 81 82 |
# File 'lib/ruborg/progress.rb', line 78 def done(label = nil) stop_spin clear_line if @tty @output.puts " ✓ #{label}" if label end |
#spin(label) ⇒ Object
Start a spinner on the current line for an indeterminate operation. Appends elapsed time after 3 seconds so long-running steps are visible. Call stop_spin (or done) to halt it.
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
# File 'lib/ruborg/progress.rb', line 30 def spin(label) stop_spin return unless @tty @spin_label = label @spin_start = Time.now frame = 0 @spinner_thread = Thread.new do loop do elapsed = (Time.now - @spin_start).to_i time_str = elapsed >= 3 ? " (#{elapsed}s)" : "" @output.print "\r #{SPINNER_FRAMES[frame % SPINNER_FRAMES.size]} #{@spin_label}#{time_str}" frame += 1 sleep 0.1 end end end |
#stage(index, total, label) ⇒ Object
Print a numbered stage header: “[2/3] Label”
21 22 23 24 25 |
# File 'lib/ruborg/progress.rb', line 21 def stage(index, total, label) stop_spin clear_line if @tty @output.puts "[#{index}/#{total}] #{label}" end |
#stop_spin ⇒ Object
Stop the spinner and erase its line.
55 56 57 58 59 60 61 62 |
# File 'lib/ruborg/progress.rb', line 55 def stop_spin return unless @spinner_thread @spinner_thread.kill @spinner_thread.join(0.2) @spinner_thread = nil clear_line if @tty end |
#update_spin(label) ⇒ Object
Update the label on a running spinner without restarting it. Safe to call from the main thread while the spinner runs in the background.
50 51 52 |
# File 'lib/ruborg/progress.rb', line 50 def update_spin(label) @spin_label = label end |