Class: Clack::Prompts::Spinner

Inherits:
Object
  • Object
show all
Defined in:
lib/clack/prompts/spinner.rb

Overview

Animated spinner for async operations.

Runs animation in a background thread. Call #start to begin, #stop/#error/#cancel to finish. Thread-safe message updates.

Indicator modes:

  • ‘:dots` - animating dots after message (default)

  • ‘:timer` - elapsed time display [Xs] or [Xm Ys]

Examples:

Basic usage

s = Clack.spinner
s.start("Installing...")
# ... do work ...
s.stop("Done!")

With timer

s = Clack.spinner(indicator: :timer)
s.start("Building")
build_project
s.stop("Build complete")  # => "Build complete [12s]"

Updating message mid-spin

s = Clack.spinner
s.start("Step 1...")
do_step_1
s.message("Step 2...")
do_step_2
s.stop("All done!")

Instance Method Summary collapse

Constructor Details

#initialize(indicator: :dots, frames: nil, delay: nil, style_frame: nil, output: $stdout) ⇒ Spinner

Returns a new instance of Spinner.

Parameters:

  • indicator (:dots, :timer) (defaults to: :dots)

    animation style (default: :dots)

  • frames (Array<String>, nil) (defaults to: nil)

    custom spinner frames

  • delay (Float, nil) (defaults to: nil)

    delay between frames in seconds

  • style_frame (Proc, nil) (defaults to: nil)

    proc to style each frame character

  • output (IO) (defaults to: $stdout)

    output stream (default: $stdout)



40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/clack/prompts/spinner.rb', line 40

def initialize(
  indicator: :dots,
  frames: nil,
  delay: nil,
  style_frame: nil,
  output: $stdout
)
  @output = output
  @indicator = indicator
  @frames = frames || Symbols::SPINNER_FRAMES
  @delay = delay || Symbols::SPINNER_DELAY
  @style_frame = style_frame || ->(frame) { Colors.magenta(frame) }
  @state = :idle
  @message = ""
  @thread = nil
  @frame_idx = 0
  @prev_frame = nil
  @start_time = nil
  @mutex = Mutex.new
end

Instance Method Details

#cancel(message = nil) ⇒ Object

Stop with cancelled state.

Parameters:

  • message (String, nil) (defaults to: nil)

    cancellation message



100
101
102
# File 'lib/clack/prompts/spinner.rb', line 100

def cancel(message = nil)
  finish(:cancelled, message)
end

#cancelled?Boolean

Returns:

  • (Boolean)


123
# File 'lib/clack/prompts/spinner.rb', line 123

def cancelled? = @mutex.synchronize { @state == :cancelled }

#clearObject

Clear the spinner without showing a final message.



113
114
115
116
117
118
119
120
121
# File 'lib/clack/prompts/spinner.rb', line 113

def clear
  @mutex.synchronize do
    @state = :idle
  end
  @thread&.join
  restore_cursor
  @output.print Core::Cursor.clear_down
  @output.print Core::Cursor.show
end

#error(message = nil) ⇒ Object

Stop with error state.

Parameters:

  • message (String, nil) (defaults to: nil)

    error message (uses current if nil)



93
94
95
# File 'lib/clack/prompts/spinner.rb', line 93

def error(message = nil)
  finish(:error, message)
end

#message(msg) ⇒ Object

Update the spinner message while running.

Parameters:

  • msg (String)

    new message to display



107
108
109
110
# File 'lib/clack/prompts/spinner.rb', line 107

def message(msg)
  @mutex.synchronize { @message = remove_trailing_dots(msg) }
  self
end

#start(message = nil) ⇒ self

Start the spinner animation.

Parameters:

  • message (String, nil) (defaults to: nil)

    initial message to display

Returns:

  • (self)

    for method chaining



65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/clack/prompts/spinner.rb', line 65

def start(message = nil)
  @mutex.synchronize do
    return unless @state == :idle

    @message = remove_trailing_dots(message || "")
    @state = :running
    @prev_frame = nil
    @frame_idx = 0
    @start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
  end

  @output.print Core::Cursor.hide
  @output.print "#{Colors.gray(Symbols::S_BAR)}\n"

  @thread = Thread.new { spin_loop }
  self
end

#stop(message = nil) ⇒ Object

Stop with success state.

Parameters:

  • message (String, nil) (defaults to: nil)

    final message (uses current if nil)



86
87
88
# File 'lib/clack/prompts/spinner.rb', line 86

def stop(message = nil)
  finish(:success, message)
end