Module: RubyProgress::Utils

Defined in:
lib/ruby-progress/utils.rb

Overview

Universal terminal utilities shared between progress indicators.

This module provides common functionality for terminal manipulation, cursor control, and output formatting used across all progress indicator types.

Class Method Summary collapse

Class Method Details

.clear_line(output_stream = :stderr) ⇒ void

This method returns an undefined value.

Clears the current terminal line.

Examples:

Clear to stderr (default)

RubyProgress::Utils.clear_line

Clear to stdout

RubyProgress::Utils.clear_line(:stdout)

Parameters:

  • output_stream (Symbol, IO) (defaults to: :stderr)

    Stream to clear (:stdout, :stderr, or IO object)



35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/ruby-progress/utils.rb', line 35

def self.clear_line(output_stream = :stderr)
  io = case output_stream
       when :stdout
         $stdout
       when :stderr
         $stderr
       else
         # allow passing an IO-like object (e.g. StringIO) directly
         output_stream.respond_to?(:print) ? output_stream : $stderr
       end

  io.print "\r\e[K"
end

.clear_line_aggressivevoid

This method returns an undefined value.

Enhanced line clearing for daemon mode that handles output interruption.

Clears the current line and the line above it, useful when daemon output has been interrupted by other command output.

Examples:

RubyProgress::Utils.clear_line_aggressive


57
58
59
60
61
# File 'lib/ruby-progress/utils.rb', line 57

def self.clear_line_aggressive
  $stderr.print "\r\e[2K"    # Clear entire current line
  $stderr.print "\e[1A\e[2K" # Move up one line and clear it too
  $stderr.print "\r"         # Return to start of line
end

.complete_with_clear(message, success: true, show_checkmark: false, output_stream: :warn, icons: {}) ⇒ void

This method returns an undefined value.

Clears the current line and displays a completion message.

Convenience method that combines line clearing with message display. Note: When output_stream is :warn, line clearing is already included in display_completion.

Examples:

RubyProgress::Utils.complete_with_clear("Task complete", success: true, show_checkmark: true)

Parameters:

  • message (String)

    The message to display

  • success (Boolean) (defaults to: true)

    Whether this represents success (true) or failure (false)

  • show_checkmark (Boolean) (defaults to: false)

    Whether to show checkmark/X symbols

  • output_stream (Symbol, IO) (defaults to: :warn)

    Where to output (:stdout, :stderr, :warn, or IO object)

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

    Custom icons hash with :success and :error keys

See Also:



147
148
149
150
# File 'lib/ruby-progress/utils.rb', line 147

def self.complete_with_clear(message, success: true, show_checkmark: false, output_stream: :warn, icons: {})
  clear_line(output_stream) if output_stream != :warn # warn already includes clear in display_completion
  display_completion(message, success: success, show_checkmark: show_checkmark, output_stream: output_stream, icons: icons)
end

.display_completion(message, success: true, show_checkmark: false, output_stream: :warn, icons: {}) ⇒ void

This method returns an undefined value.

Displays a completion message with optional icons and formatting.

Universal completion message display that handles success/error states, custom icons, and output stream selection.

Examples:

Basic success message

RubyProgress::Utils.display_completion("Done!", success: true, show_checkmark: true)

With custom icons

RubyProgress::Utils.display_completion("Build complete",
  success: true,
  show_checkmark: true,
  icons: { success: '🚀', error: '💥' })

Parameters:

  • message (String)

    The message to display

  • success (Boolean) (defaults to: true)

    Whether this represents success (true) or failure (false)

  • show_checkmark (Boolean) (defaults to: false)

    Whether to show checkmark/X symbols

  • output_stream (Symbol, IO) (defaults to: :warn)

    Where to output (:stdout, :stderr, :warn, or IO object)

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

    Custom icons hash with :success and :error keys

Options Hash (icons:):

  • :success (String)

    Custom success icon (overrides default ✅)

  • :error (String)

    Custom error icon (overrides default 🛑)



83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# File 'lib/ruby-progress/utils.rb', line 83

def self.display_completion(message, success: true, show_checkmark: false, output_stream: :warn, icons: {})
  return unless message

  # Determine the mark to show. If checkmarks are enabled, prefer the
  # default icons but allow overrides via icons hash. If checkmarks are not
  # enabled, still show a custom icon when provided via CLI options.
  mark = ''
  if show_checkmark
    icon = success ? (icons[:success] || '✅') : (icons[:error] || '🛑')
    mark = "#{icon} "
  else
    custom_icon = success ? icons[:success] : icons[:error]
    mark = custom_icon ? "#{custom_icon} " : ''
  end

  formatted_message = "#{mark}#{message}"

  # Resolve destination IO: support symbols (:stdout/:stderr/:warn) or an IO-like object
  dest_io = case output_stream
            when :stdout
              $stdout
            when :stderr
              $stderr
            when :warn
              $stderr
            else
              output_stream.respond_to?(:print) ? output_stream : $stderr
            end

  # Only treat explicit :stdout and :stderr as non-clearing requests.
  # For :warn and any other/custom stream, clear the current line first.
  unless i[stdout stderr].include?(output_stream)
    # Always include a leading carriage return when clearing to match
    # terminal behavior expected by the test-suite.
    dest_io.print "\r\e[2K"
    dest_io.flush if dest_io.respond_to?(:flush)
  end

  # Emit the message to the resolved destination IO. Use warn/puts when targeting
  # the standard streams to preserve familiar behavior (warn writes to $stderr).
  if dest_io == $stdout
    $stdout.puts formatted_message
  elsif dest_io == $stderr
    warn formatted_message
  else
    dest_io.puts formatted_message
  end
end

.ends_valid?(ends_string) ⇒ Boolean

Validates an ends string for proper format.

Checks that the string is non-empty and has an even number of characters (handles multi-byte characters correctly).

Examples:

Valid strings

RubyProgress::Utils.ends_valid?("[]")  # => true
RubyProgress::Utils.ends_valid?("🎯🎪")  # => true

Invalid strings

RubyProgress::Utils.ends_valid?("abc")  # => false (odd length)
RubyProgress::Utils.ends_valid?("")     # => false (empty)
RubyProgress::Utils.ends_valid?(nil)    # => false (nil)

Parameters:

  • ends_string (String, nil)

    String to validate

Returns:

  • (Boolean)

    true if valid, false otherwise



195
196
197
198
199
200
# File 'lib/ruby-progress/utils.rb', line 195

def self.ends_valid?(ends_string)
  return false unless ends_string && !ends_string.empty?

  chars = ends_string.each_char.to_a
  !chars.empty? && (chars.length % 2).zero?
end

.hide_cursorvoid

This method returns an undefined value.

Hides the terminal cursor.

Examples:

RubyProgress::Utils.hide_cursor


14
15
16
# File 'lib/ruby-progress/utils.rb', line 14

def self.hide_cursor
  $stderr.print "\e[?25l"
end

.parse_ends(ends_string) ⇒ Array<String>

Parses start/end characters for animation wrapping.

Takes an even-length string and splits it in half to create start and end decorative characters for progress indicators. Handles multi-byte characters correctly.

Examples:

Basic decoration

RubyProgress::Utils.parse_ends("[]")  # => ["[", "]"]

Multi-character decoration

RubyProgress::Utils.parse_ends("<<>>")  # => ["<<", ">>"]

Emoji decoration

RubyProgress::Utils.parse_ends("🎯🎪")  # => ["🎯", "🎪"]

Empty or nil input

RubyProgress::Utils.parse_ends(nil)  # => ["", ""]

Parameters:

  • ends_string (String, nil)

    Even-length string to split in half

Returns:

  • (Array<String>)

    Array with [start_chars, end_chars]



168
169
170
171
172
173
174
175
176
177
178
179
# File 'lib/ruby-progress/utils.rb', line 168

def self.parse_ends(ends_string)
  return ['', ''] unless ends_string && !ends_string.empty?

  chars = ends_string.each_char.to_a
  return ['', ''] if chars.length.odd? || chars.empty?

  mid_point = chars.length / 2
  start_chars = chars[0...mid_point].join
  end_chars = chars[mid_point..-1].join

  [start_chars, end_chars]
end

.show_cursorvoid

This method returns an undefined value.

Shows the terminal cursor.

Examples:

RubyProgress::Utils.show_cursor


23
24
25
# File 'lib/ruby-progress/utils.rb', line 23

def self.show_cursor
  $stderr.print "\e[?25h"
end