Class: TTY::ProgressBar

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Includes:
MonitorMixin
Defined in:
lib/tty/progressbar.rb,
lib/tty/progressbar/meter.rb,
lib/tty/progressbar/multi.rb,
lib/tty/progressbar/version.rb,
lib/tty/progressbar/pipeline.rb,
lib/tty/progressbar/converter.rb,
lib/tty/progressbar/formatter.rb,
lib/tty/progressbar/configuration.rb,
lib/tty/progressbar/formatter/bar.rb,
lib/tty/progressbar/formatter/rate.rb,
lib/tty/progressbar/formatter/total.rb,
lib/tty/progressbar/formatter/current.rb,
lib/tty/progressbar/formatter/elapsed.rb,
lib/tty/progressbar/formatter/percent.rb,
lib/tty/progressbar/formatter/byte_rate.rb,
lib/tty/progressbar/formatter/estimated.rb,
lib/tty/progressbar/formatter/mean_byte.rb,
lib/tty/progressbar/formatter/mean_rate.rb,
lib/tty/progressbar/formatter/total_byte.rb,
lib/tty/progressbar/formatter/current_byte.rb

Overview

Used for creating terminal progress bar

Defined Under Namespace

Modules: Converter Classes: BarFormatter, ByteFormatter, ByteRateFormatter, Configuration, CurrentFormatter, ElapsedFormatter, EstimatedFormatter, Formatter, MeanByteFormatter, MeanRateFormatter, Meter, Multi, PercentFormatter, Pipeline, RateFormatter, TotalByteFormatter, TotalFormatter

Constant Summary collapse

ECMA_CSI =
"\e[".freeze
CURSOR_LOCK =
Monitor.new
VERSION =
'0.14.0'.freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(format, options = {}) {|@configuration| ... } ⇒ ProgressBar

Create progress bar

Parameters:

  • format (String)

    the tokenized string that displays the output

  • options (Hash) (defaults to: {})

Options Hash (options):

  • :total (Numeric)

    the total number of steps to completion

  • :width (Numeric)

    the maximum width for the bars display including all formatting options

  • :no_width (Boolean)

    true when progression is unknown defaulting to false

  • :clear (Boolean)

    whether or not to clear the progress line

  • :hide_cursor (Boolean)

    display or hide cursor

  • :output (Object)

    the object that responds to print call defaulting to stderr

  • :frequency (Number)

    the frequency with which to display bars

  • :interval (Number)

    the period for sampling of speed measurement

Yields:

  • (@configuration)


67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/tty/progressbar.rb', line 67

def initialize(format, options = {})
  super()
  @format = format
  if format.is_a?(Hash)
    raise ArgumentError, "Expected bar formatting string, " \
                         "got `#{format}` instead."
  end
  @configuration = TTY::ProgressBar::Configuration.new(options)
  yield @configuration if block_given?

  @formatter = TTY::ProgressBar::Formatter.new
  @meter     = TTY::ProgressBar::Meter.new(interval)
  @callbacks = Hash.new { |h, k| h[k] = [] }

  @formatter.load
  reset
end

Instance Attribute Details

#currentObject



28
29
30
# File 'lib/tty/progressbar.rb', line 28

def current
  @current
end

#formatObject (readonly)



26
27
28
# File 'lib/tty/progressbar.rb', line 26

def format
  @format
end

#rowObject (readonly)



32
33
34
# File 'lib/tty/progressbar.rb', line 32

def row
  @row
end

#start_atObject (readonly)



30
31
32
# File 'lib/tty/progressbar.rb', line 30

def start_at
  @start_at
end

Instance Method Details

#advance(progress = 1, tokens = {}) ⇒ Object

Advance the progress bar

Parameters:

  • progress (Object|Number) (defaults to: 1)


134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
# File 'lib/tty/progressbar.rb', line 134

def advance(progress = 1, tokens = {})
  return if done?

  synchronize do
    emit(:progress)
    if progress.respond_to?(:to_hash)
      tokens, progress = progress, 1
    end
    @start_at  = Time.now if @current.zero? && !@started
    @current  += progress
    @tokens    = tokens
    @meter.sample(Time.now, progress)

    if !no_width && @current >= total
      finish && return
    end

    now = Time.now
    return if (now - @last_render_time) < @render_period
    render
  end
end

#attach_to(multibar) ⇒ 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.

Attach this bar to multi bar

Parameters:



112
113
114
# File 'lib/tty/progressbar.rb', line 112

def attach_to(multibar)
  @multibar = multibar
end

#clear_lineObject

Clear current line



358
359
360
# File 'lib/tty/progressbar.rb', line 358

def clear_line
  output.print(ECMA_CSI + '0m' + TTY::Cursor.clear_line)
end

#complete?Boolean

Check if progress is finised

Returns:

  • (Boolean)

    true when progress finished, false otherwise



368
369
370
# File 'lib/tty/progressbar.rb', line 368

def complete?
  @done
end

#done?Boolean

Check if progress is finished or stopped

Returns:

  • (Boolean)


386
387
388
# File 'lib/tty/progressbar.rb', line 386

def done?
  @done || @stopped
end

#finishObject

End the progress



323
324
325
326
327
328
329
330
331
332
333
334
335
336
# File 'lib/tty/progressbar.rb', line 323

def finish
  # reenable cursor if it is turned off
  if hide_cursor && @last_render_width != 0
    write(TTY::Cursor.show, false)
  end
  return if done?
  @current = total unless no_width
  render
  clear ? clear_line : write("\n", false)
ensure
  @meter.clear
  @done = true
  emit(:done)
end

#inspectString

Inspect bar properties

Returns:

  • (String)


446
447
448
449
450
451
452
453
454
455
456
# File 'lib/tty/progressbar.rb', line 446

def inspect
  "#<#{self.class.name} " \
  "@format=\"#{format}\", " \
  "@current=\"#{@current}\", " \
  "@total=\"#{total}\", " \
  "@width=\"#{width}\", " \
  "@complete=\"#{complete}\", " \
  "@head=\"#{head}\", " \
  "@incomplete=\"#{incomplete}\", " \
  "@interval=\"#{interval}\">"
end

#iterate(collection, progress = 1, &block) ⇒ Enumerator

Note:

If ‘total` is set, iteration will NOT stop after this number of iterations, only when provided Enumerable is finished. It may be convenient in “unsure number of iterations” situations (like downloading in chunks, when server may eventually send more chunks than predicted), but be careful to not pass infinite enumerators without previosly doing `.take(some_finite_number)` on them.

Iterate over collection either yielding computation to block or provided Enumerator. If the bar’s ‘total` was not set, it would be taken from `collection.count`, otherwise previously set `total` would be used. This allows using the progressbar with infinite, lazy, or slowly-calculated enumerators.

Examples:

bar.iterate(30.times) { ... }

Parameters:

  • collection (Enumerable)

    the collection to iterate over

  • progress (Integer) (defaults to: 1)

    the amount to move progress bar by

Returns:

  • (Enumerator)


184
185
186
187
188
189
190
191
192
193
# File 'lib/tty/progressbar.rb', line 184

def iterate(collection, progress = 1, &block)
  update(total: collection.count * progress) unless total
  progress_enum = Enumerator.new do |iter|
    collection.each do |elem|
      advance(progress)
      iter.yield(elem)
    end
  end
  block_given? ? progress_enum.each(&block) : progress_enum
end

#log(message) ⇒ Object

Log message above the current progress bar

Parameters:

  • message (String)

    the message to log out



411
412
413
414
415
416
417
418
419
420
421
# File 'lib/tty/progressbar.rb', line 411

def log(message)
  sanitized_message = message.gsub(/\r|\n/, ' ')
  if done?
    write(sanitized_message + "\n", false)
    return
  end
  sanitized_message = padout(sanitized_message)

  write(sanitized_message + "\n", true)
  render
end

#max_columnsInteger

Determine terminal width

Returns:

  • (Integer)


428
429
430
# File 'lib/tty/progressbar.rb', line 428

def max_columns
  TTY::Screen.width
end

#move_to_rowObject

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.

Move cursor to a row of the current bar if the bar is rendered under a multibar. Otherwise, do not move and yield on current row.



267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
# File 'lib/tty/progressbar.rb', line 267

def move_to_row
  if @multibar
    CURSOR_LOCK.synchronize do
      if @first_render
        @row = @multibar.next_row
        yield if block_given?
        output.print "\n"
        @first_render = false
      else
        lines_up = (@multibar.rows + 1) - @row
        output.print TTY::Cursor.save
        output.print TTY::Cursor.up(lines_up)
        yield if block_given?
        output.print TTY::Cursor.restore
      end
    end
  else
    yield if block_given?
  end
end

#on(name, &callback) ⇒ self

Register callback with this bar

Parameters:

  • name (Symbol)

    the name for the event to listen for, e.i. :complete

Returns:

  • (self)


398
399
400
401
402
403
# File 'lib/tty/progressbar.rb', line 398

def on(name, &callback)
  synchronize do
    @callbacks[name] << callback
  end
  self
end

#ratioFloat

Ratio of completed over total steps

Returns:

  • (Float)


237
238
239
240
241
242
# File 'lib/tty/progressbar.rb', line 237

def ratio
  synchronize do
    proportion = total > 0 ? (@current.to_f / total) : 0
    [[proportion, 0].max, 1].min
  end
end

#ratio=(value) ⇒ Object

Advance the progress bar to an exact ratio. The target value is set to the closest available value.

Parameters:

  • value (Float)

    the ratio between 0 and 1 inclusive



227
228
229
230
# File 'lib/tty/progressbar.rb', line 227

def ratio=(value)
  target = (value * total).floor
  advance(target - @current)
end

#renderObject

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.

Render progress to the output



247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
# File 'lib/tty/progressbar.rb', line 247

def render
  return if done?
  if hide_cursor && @last_render_width == 0 && !(@current >= total)
    write(TTY::Cursor.hide)
  end

  formatted = @formatter.decorate(self, @format)
  @tokens.each do |token, val|
    formatted = formatted.gsub(":#{token}", val)
  end
  write(formatted, true)

  @last_render_time  = Time.now
  @last_render_width = formatted.length
end

#resetObject

Reset progress to default configuration



88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/tty/progressbar.rb', line 88

def reset
  @width             = 0 if no_width
  @render_period     = frequency == 0 ? 0 : 1.0 / frequency
  @current           = 0
  @last_render_time  = Time.now
  @last_render_width = 0
  @done              = false
  @stopped           = false
  @start_at          = Time.now
  @started           = false
  @tokens            = {}
  @multibar          = nil
  @row               = nil
  @first_render      = true

  @meter.clear
end

#resize(new_width = nil) ⇒ Object

Resize progress bar with new configuration

Parameters:

  • new_width (Integer) (defaults to: nil)

    the new width for the bar display



310
311
312
313
314
315
316
317
318
# File 'lib/tty/progressbar.rb', line 310

def resize(new_width = nil)
  return if done?
  synchronize do
    clear_line
    if new_width
      self.width = new_width
    end
  end
end

#startObject

Start progression by drawing bar and setting time



119
120
121
122
123
124
125
126
127
# File 'lib/tty/progressbar.rb', line 119

def start
  synchronize do
    @started  = true
    @start_at = Time.now
    @meter.start
  end

  advance(0)
end

#stopObject

Stop and cancel the progress at the current position



341
342
343
344
345
346
347
348
349
350
351
352
353
# File 'lib/tty/progressbar.rb', line 341

def stop
  # reenable cursor if it is turned off
  if hide_cursor && @last_render_width != 0
    write(TTY::Cursor.show, false)
  end
  return if done?
  render
  clear ? clear_line : write("\n", false)
ensure
  @meter.clear
  @stopped = true
  emit(:stopped)
end

#stopped?Boolean

Check if progress is stopped

Returns:

  • (Boolean)


377
378
379
# File 'lib/tty/progressbar.rb', line 377

def stopped?
  @stopped
end

#to_sString

Show bar format

Returns:

  • (String)


437
438
439
# File 'lib/tty/progressbar.rb', line 437

def to_s
  @format.to_s
end

#update(options = {}) ⇒ Object

Update configuration options for this bar

Parameters:

  • options (Hash[Symbol]) (defaults to: {})

    the configuration options to update



201
202
203
204
205
206
207
# File 'lib/tty/progressbar.rb', line 201

def update(options = {})
  synchronize do
    options.each do |name, val|
      @configuration.public_send("#{name}=", val)
    end
  end
end

#write(data, clear_first = false) ⇒ 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.

Write out to the output

Parameters:

  • data (String)


293
294
295
296
297
298
299
300
301
302
# File 'lib/tty/progressbar.rb', line 293

def write(data, clear_first = false)
  return unless tty? # write only to terminal

  move_to_row do
    output.print(TTY::Cursor.column(1)) if clear_first
    characters_in = @multibar.line_inset(self) if @multibar
    output.print("#{characters_in}#{data}")
    output.flush
  end
end