Class: TTY::Spinner::Multi

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Includes:
Enumerable
Defined in:
lib/tty/spinner/multi.rb

Overview

Used for managing multiple terminal spinners

Constant Summary collapse

DEFAULT_INSET =
{
  top:    Gem.win_platform? ? '+ '   : "\u250c ",
  middle: Gem.win_platform? ? '|-- ' : "\u251c\u2500\u2500",
  bottom: Gem.win_platform? ? '|__ ' : "\u2514\u2500\u2500"
}.freeze

Instance Method Summary collapse

Constructor Details

#initialize(*args) ⇒ Multi

Initialize a multispinner

Examples:

spinner = TTY::Spinner::Multi.new

Parameters:

  • message (String)

    the optional message to print in front of the top level spinner

  • options (Hash)


48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/tty/spinner/multi.rb', line 48

def initialize(*args)
  @options = args.last.is_a?(::Hash) ? args.pop : {}
  message = args.empty? ? nil : args.pop
  @inset_opts = @options.delete(:style) { DEFAULT_INSET }
  @create_spinner_lock = Mutex.new
  @spinners    = []
  @top_spinner = nil
  @top_spinner = register(message) unless message.nil?

  @callbacks = {
    success: [],
    error:   [],
    done:    []
  }
end

Instance Method Details

#auto_spinObject

Auto spin the top level spinner & all child spinners that have scheduled jobs



113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/tty/spinner/multi.rb', line 113

def auto_spin
  raise "No top level spinner" if @top_spinner.nil?

  @top_spinner.auto_spin
  jobs = []
  @spinners.each do |spinner|
    if spinner.job?
      spinner.auto_spin
      jobs << Thread.new { spinner.instance_eval(&spinner.job) }
    end
  end
  jobs.each(&:join)
end

#count_line_offset(index) ⇒ Integer

Find relative offset position to which to move the current cursor

The position is found among the registered spinners given the current position the spinner is at provided its index

Parameters:

  • index (Integer)

    the position to search from

Returns:

  • (Integer)

    the current position



153
154
155
156
157
158
159
160
# File 'lib/tty/spinner/multi.rb', line 153

def count_line_offset(index)
  Array(@spinners[index..-1]).reduce(0) do |acc, spinner|
    if spinner.spinning? || spinner.done?
      acc += 1
    end
    acc
  end
end

#done?Boolean

Check if all spinners are done

Returns:

  • (Boolean)


190
191
192
# File 'lib/tty/spinner/multi.rb', line 190

def done?
  (@spinners - [@top_spinner]).all?(&:done?)
end

#errorObject

Stop all spinners with error status



232
233
234
235
236
# File 'lib/tty/spinner/multi.rb', line 232

def error
  @top_spinner.error if @top_spinner
  @spinners.dup.each(&:error)
  emit :error
end

#error?Boolean

Check if any spinner errored

Returns:

  • (Boolean)


208
209
210
# File 'lib/tty/spinner/multi.rb', line 208

def error?
  (@spinners - [@top_spinner]).any?(&:error?)
end

#line_inset(spinner) ⇒ String

Find the number of characters to move into the line before printing the spinner

Parameters:

  • spinner (TTY::Spinner)

    the spinner for which line inset is calculated

Returns:

  • (String)

    the inset



172
173
174
175
176
177
178
179
180
181
182
183
# File 'lib/tty/spinner/multi.rb', line 172

def line_inset(spinner)
  return '' if @top_spinner.nil?

  case spinner
  when @top_spinner
    @inset_opts[:top]
  when @spinners.last
    @inset_opts[:bottom]
  else
    @inset_opts[:middle]
  end
end

#observe_events(spinner) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Observe all child events to notify top spinner of current state

Parameters:

  • spinner (TTY::Spinner)

    the spinner to listen to for events



92
93
94
95
96
# File 'lib/tty/spinner/multi.rb', line 92

def observe_events(spinner)
  spinner.on(:success) { @top_spinner.success if success? }
         .on(:error)   { @top_spinner.error if error? }
         .on(:done)    { @top_spinner.stop if done? && !success? && !error? }
end

#on(key, &callback) ⇒ Object

Listen on event



241
242
243
244
245
246
247
248
# File 'lib/tty/spinner/multi.rb', line 241

def on(key, &callback)
  unless @callbacks.key?(key)
    raise ArgumentError, "The event #{key} does not exist. "\
                         " Use :success, :error, or :done instead"
  end
  @callbacks[key] << callback
  self
end

#pauseObject

Pause all spinners



130
131
132
# File 'lib/tty/spinner/multi.rb', line 130

def pause
  @spinners.dup.each(&:pause)
end

#register(pattern, options = {}, &job) ⇒ Object

Register a new spinner

Parameters:

  • pattern (String)

    the pattern used for creating spinner



70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/tty/spinner/multi.rb', line 70

def register(pattern, options = {}, &job)
  spinner = TTY::Spinner.new(pattern, @options.merge(options))

  @create_spinner_lock.synchronize do
    spinner.add_multispinner(self, @spinners.length)
    spinner.job(&job) if block_given?
    observe_events(spinner) if @top_spinner
    @spinners << spinner
    if @top_spinner
      @spinners.each { |sp| sp.redraw_indent if sp.spinning? || sp.done? }
    end
  end

  spinner
end

#resumeObject

Resume all spinners



137
138
139
# File 'lib/tty/spinner/multi.rb', line 137

def resume
  @spinners.dup.each(&:resume)
end

#stopObject

Stop all spinners



215
216
217
218
# File 'lib/tty/spinner/multi.rb', line 215

def stop
  @spinners.dup.each(&:stop)
  emit :done
end

#successObject

Stop all spinners with success status



223
224
225
226
227
# File 'lib/tty/spinner/multi.rb', line 223

def success
  @top_spinner.success if @top_spinner
  @spinners.dup.each(&:success)
  emit :success
end

#success?Boolean

Check if all spinners succeeded

Returns:

  • (Boolean)


199
200
201
# File 'lib/tty/spinner/multi.rb', line 199

def success?
  (@spinners - [@top_spinner]).all?(&:success?)
end

#top_spinnerTTY::Spinner

Get the top level spinner if it exists

Returns:



103
104
105
106
107
# File 'lib/tty/spinner/multi.rb', line 103

def top_spinner
  raise "No top level spinner" if @top_spinner.nil?

  @top_spinner
end