class

Athena::Console::Helper::ProgressBar

Inherits Reference / Object

When executing longer-running commands, it can be helpful to show progress information that updates as the command runs:

Progress Bar

TIP: Consider using ACON::Style::Athena to display a progress bar.

The ProgressBar helper can be used to progress information to any ACON::Output::Interface:

# Create a new progress bar with 50 required units for completion.
progress_bar = ACON::Helper::ProgressBar.new output, 50

# Start and display the progress bar.
progress_bar.start

50.times do
  # Do work

  # Advance the progress bar by 1 unit.
  progress_bar.advance

  # Or advance by more than a single unit.
  # progress_bar.advance 3
end

# Ensure progress bar is at 100%.
progress_bar.finish

A progress bar can also be created without a required number of units, in which case it will just act as a throbber. However, #max_steps= can be called at any point to either set, or increase the required number of units. E.g. if its only known after performing some calculations, or additional work is needed such that the original value is not invalid.

TIP: Consider using an ACON::Helper::ProgressIndicator instead of a progress bar for this use case.

Be sure to call #finish when the task completes to ensure the progress bar is refreshed with a 100% completion.

NOTE: By default the progress bar will write its output to STDERR, however this can be customized by using an ACON::Output::IO explicitly.

If the progress information is stored within an Enumerable type, the #iterate method can be used to start, advance, and finish the progress bar automatically, yielding each item in the collection:

bar = ACON::Helper::ProgressBar.new output
arr = [1, 2, 3]

bar.iterate(arr) do |item|
  # Do something
end

Which would output:

0/2 [>---------------------------]   0%
1/2 [==============>-------------]  50%
2/2 [============================] 100%

NOTE: Iterator types are also supported, but need the max value provided explicitly via the second argument to #iterate if known.

Progressing

While the #advance method can be used to move the progress bar ahead by a specific number of steps, the current step can be set explicitly via #progress=.

It is also possible to start the progress bar at a specific step, which is useful when resuming some long-standing task:

# Create a 100 unit progress bar.
progress_bar = ACON::Helper::ProgressBar.new output, 100

# Display the progress bar starting at already 25% complete.
progress_bar.start at: 25

TIP: The progress can also be regressed (stepped backwards) by providing #advance a negative value.

Controlling Rendering

If available, ANCI Escape Codes are used to handle the rendering of the progress bar, otherwise updates are added as new lines. #minimum_seconds_between_redraws= can be used to prevent the output being flooded. #redraw_frequency= can be used to to redraw every N iterations. By default, redraw frequency is 100ms or 10% of your #max_steps.

Customizing

Built-in Formats

The progress bar comes with a few built-in formats based on the ACON::Output::Verbosity the command was executed with:

# Verbosity::NORMAL (CLI with no verbosity flag)
 0/3 [>---------------------------]   0%
 1/3 [=========>------------------]  33%
 3/3 [============================] 100%

# Verbosity::VERBOSE (-v)
 0/3 [>---------------------------]   0%  1 sec
 1/3 [=========>------------------]  33%  1 sec
 3/3 [============================] 100%  1 sec

# Verbosity::VERY_VERBOSE (-vv)
 0/3 [>---------------------------]   0%  1 sec/1 sec
 1/3 [=========>------------------]  33%  1 sec/1 sec
 3/3 [============================] 100%  1 sec/1 sec

# Verbosity::DEBUG (-vvv)
 0/3 [>---------------------------]   0%  1 sec/1 sec  1kiB
 1/3 [=========>------------------]  33%  1 sec/1 sec  1kiB
 3/3 [============================] 100%  1 sec/1 sec  1kiB

NOTE: If a command called with ACON::Output::Verbosity::QUIET, the progress bar will not be displayed.

The format may also be set explicitly in code via:

# If the progress bar has a maximum number of steps.
bar.format = :very_verbose

# Without a maximum
bar.format = :very_verbose_nomax

Custom Formats

While the built-in formats are sufficient for most use cases, custom ones may also be defined:

bar.format = "%bar%"

Which would set the format to only display the progress bar itself:

>---------------------------
=========>------------------
============================

A progress bar format is a string that contains specific placeholders (a name enclosed with the % character); the placeholders are replaced based on the current progress of the bar. The built-in placeholders include:

  • %current% - The current step
  • %max% - The maximum number of steps (or zero if there is not one)
  • %bar% - The progress bar itself
  • %percent% - The percentage of completion (not available if no max is defined)
  • %elapsed% - The time elapsed since the start of the progress bar
  • %remaining% - The remaining time to complete the task (not available if no max is defined)
  • %estimated% - The estimated time to complete the task (not available if no max is defined)
  • %memory% - The current memory usage
  • %message% - Used to display arbitrary messages, more on this later

For example, the format string for ACON::Helper::ProgressBar::Format::NORMAL is " %current% [%bar%] %elapsed:6s%". Individual placeholders can have their formatting tweaked by anything that sprintf supports by separating the name of the placeholder with a :. The part after the colon will be passed to sprintf.

If a format should be used across an entire application, they can be registered globally via .set_format_definition:

ACON::Helper::ProgressBar.set_format_definition "minimal", "Progress: %percent%%"

bar = ACON::Helper::ProgressBar.new output, 3
bar.format = "minimal"

Which would output:

Progress: 0%
Progress: 33%
Progress: 100%

TIP: It is almost always better to override the built-in formats in order to automatically vary the display based on the verbosity the command is being ran with.

When creating a custom format, be sure to also define a _nomax variant if it is using a placeholder that is only available if #max_steps is defined.

ACON::Helper::ProgressBar.set_format_definition "minimal", "%current%/%remaining%"
ACON::Helper::ProgressBar.set_format_definition "minimal_nomax", "%current%"

bar = ACON::Helper::ProgressBar.new output, 3
bar.format = "minimal"

The format will automatically be set to minimal_nomax if the bar does not have a maximum number of steps.

TIP: A format can contain any valid ANSI codes, or any ACON::Formatter::OutputStyleInterface markup.

TIP: A format may also span multiple lines, which can be useful to also display contextual information (like the first example).

Bar Settings

The bar placeholder is a bit special in that all of the characters used to display it can be customized:

# The Finished part of the bar.
bar.bar_character = "<comment>=</comment>"

# The unfinished part of the bar.
bar.empty_bar_character = " "

# The progress character.
bar.progress_character = "|"

# The width of the bar.
bar.bar_width = 50

Custom Placeholders

Just like the format, custom placeholders may also be defined. This can be useful to have a common way of displaying some sort of application specific information between multiple progress bars:

ACON::Helper::ProgressBar.set_placeholder_formatter "remaining_steps" do |bar|
  "#{bar.max_steps - bar.progress}"
end

From here it could then be used in a format string as %remaining_steps% just like any other placeholder. .set_placeholder_formatter registers the format globally, while #set_placeholder_formatter would set it on a specific progress bar.

Custom Messages

While there is a built-in message placeholder that can be set via #set_message, none of the built-in formats include it. As such, before displaying these messages, a custom format needs to be defined:

bar = ACON::Helper::ProgressBar.new output, 100
bar.format = " %current%/%max% -- %message%"

bar.set_message "Start"
bar.start # 0/100 -- Start

bar.set_message "Task is in progress..."
bar.advance # 1/100 -- Task is in progress...

#set_message also allows or an optional second argument, which can be used to have multiple independent messages within the same format string:

files.each do |file_name|
  bar.set_message "Importing files..."
  bar.set_message file_name, "filename"
  bar.advance # => 2/100 -- Importing files... (foo/bar.txt)
end

Multiple Progress Bars

When using ACON::Output::Sections, multiple progress bars can be displayed at the same time and updated independently:

output = output.as ACON::Output::ConsoleOutputInterface

section1 = output.section
section2 = output.section

bar1 = ACON::Helper::ProgressBar.new section1
bar2 = ACON::Helper::ProgressBar.new section2

bar1.start 100
bar2.start 100

100.times do |idx|
  bar1.advance
  bar2.advance(4) if idx.divisible_by? 2

  sleep 0.05.seconds
end

Which would ultimately look something like:

34/100 [=========>------------------]  34%
68/100 [===================>--------]  68%

Constructors

new(output : ACON::Output::Interface, max : Int32 | Nil = nil, minimum_seconds_between_redraws : Float64 = 0.04, clock : ACLK::Interface = ACLK::Native.new)
Source

Class methods

format_definition(name : String) : String | Nil

Returns the global format string for the provided name if it exists, otherwise nil.

Source
placeholder_formatter(name : String) : ACON::Helper::ProgressBar::PlaceholderFormatter | Nil

Returns the global formatter for the provided name if it exists, otherwise nil.

Source
set_format_definition(name : String, format : String) : Nil

Registers the format globally with the provided name.

Source
set_placeholder_formatter(name : String, &block : self, ACON::Output::Interface -> String) : Nil

Registers a custom placeholder with the provided name with the block being the formatter.

Source
set_placeholder_formatter(name : String, callable : ACON::Helper::ProgressBar::PlaceholderFormatter) : Nil

Registers a custom placeholder with the provided name, using the provided callable as the formatter.

Source

Instance methods

advance(by step : Int32 = 1) : Nil

Advanced the progress bar by the provided number of steps.

Source
bar_character

Returns the character to use for the finished part of the bar.

Source
bar_character=(bar_character : String | Nil)

Explicitly sets the character to use for the finished part of the bar.

Source
bar_offset

Returns the amount of #bar_character representing the current #progress.

Source
bar_width

Returns the width of the progress bar in pixels.

bar1 = ...
bar1.bar_width = 50
bar1.start 10

bar2 = ...
bar2.bar_width = 10
bar2.start 20

bar1.finish
bar2.finish
10/10 [==================================================] 100%
20/20 [==========] 100%
Source
bar_width=(size : Int32) : Nil

Sets the width of the bar in pixels to the provided size. See #bar_width.

Source
clear

Clears the progress bar from the output. Can be used in conjunction with #display to allow outputting something while a progress bar is running. Call #clear, write the content, then call #display to show the progress bar again.

NOTE: Requires that #overwrite= be set to true.

Source
display

Displays the progress bar's current state.

Source
empty_bar_character

Represents the character used for the unfinished part of the bar.

Source
empty_bar_character=(empty_bar_character : String)

Represents the character used for the unfinished part of the bar.

Source
estimated

Returns an estimated amount of time in seconds until the progress bar is completed.

Source
finish

Finishes the progress output, making it 100% complete.

Source
format=(format : String)

Sets the format string used to determine how to display the progress bar. See [Custom Formats][Athena::Console::Helper::ProgressBar--custom-formats] for more information.

Source
format=(format : ACON::Helper::ProgressBar::Format)

Sets what built in format to use. See [Built-in Formats][Athena::Console::Helper::ProgressBar--built-in-formats] for more information.

Source
iterate(enumerable : Enumerable(T), max : Int32 | Nil = nil, & : T -> Nil) : Nil forall T

Start, advance, and finish the progress bar automatically, yielding each item in the provided enumerable.

bar = ACON::Helper::ProgressBar.new output
arr = [1, 2, 3]

bar.iterate(arr) do |item|
  # Do something
end

Which would output:

0/2 [>---------------------------]   0%
1/2 [==============>-------------]  50%
2/2 [============================] 100%

NOTE: Iterator types are also supported, but need the max value provided explicitly via the second argument to #iterate if known.

Source
max_steps

Returns the maximum number of possible steps, or 0 if it is unknown.

Source
max_steps=(max : Int32) : Nil

Sets the maximum possible steps to the provided max.

Source
maximum_seconds_between_redraws=(maximum_seconds_between_redraws : Float64)

Sets the maximum amount of time between redraws.

See [Controlling Rendering][Athena::Console::Helper::ProgressBar--controlling-rendering] for more information.

Source
message(name : String = "message") : String | Nil

Returns the message associated with the provided name if defined, otherwise nil.

Source
minimum_seconds_between_redraws=(minimum_seconds_between_redraws : Float64)

Sets the minimum amount of time between redraws.

See [Controlling Rendering][Athena::Console::Helper::ProgressBar--controlling-rendering] for more information.

Source
overwrite=(overwrite : Bool)

Sets if the progress bar should overwrite the progress bar. Set to false in order to print the progress bar on a new line for each update.

Source
placeholder_formatter(name : String) : ACON::Helper::ProgressBar::PlaceholderFormatter | Nil

Returns the amount of time in seconds until the progress bar is completed.

Source
progress

Returns the current step of the progress bar

Source
progress=(step : Int32) : Nil

Explicitly sets the current step number of the progress bar.

ameba:disable Metrics/CyclomaticComplexity

Source
progress_character

Represents the character used for the current progress of the bar.

Source
progress_character=(progress_character : String)

Represents the character used for the current progress of the bar.

Source
progress_percent

Returns the a percent of progress of #progress versus #max_steps. Returns zero if there is no max defined.

Source
redraw_frequency=(steps : Int32 | Nil) : Nil

Redraw the progress bar every after advancing the provided amount of steps.

See [Controlling Rendering][Athena::Console::Helper::ProgressBar--controlling-rendering] for more information.

Source
remaining

Returns an estimated total amount of time in seconds needed for the progress bar to complete.

Source
set_message(message : String, name : String = "message") : Nil

Sets the message with the provided name to that of the provided message.

Source
set_placeholder_formatter(name : String, &block : self, ACON::Output::Interface -> String) : Nil

Same as .set_placeholder_formatter, but scoped to this particular progress bar.

Source
set_placeholder_formatter(name : String, callable : ACON::Helper::ProgressBar::PlaceholderFormatter) : Nil

Same as .set_placeholder_formatter, but scoped to this particular progress bar.

Source
start(max : Int32 | Nil = nil, at start_at : Int32 = 0) : Nil

Starts the progress bar.

Optionally sets the maximum number of steps to max, or nil to leave unchanged. Optionally starts the progress bar at the provided step.

Source
start_time

Returns the time the progress bar was started as a Unix epoch.

Source
step_width

Returns the width in pixels that the current #progress takes up when displayed.

Source
step_width?

Returns the width in pixels that the current #progress takes up when displayed.

Source

Nested types