class Formatador

Constants

INDENT_REGEX
PARSE_REGEX
STYLES
VERSION

Public Class Methods

new() click to toggle source
# File lib/formatador.rb, line 59
def initialize
  @indent = 1
end

Public Instance Methods

display(string = '') click to toggle source
# File lib/formatador.rb, line 63
def display(string = '')
  print(parse("[indent]#{string}"))
  $stdout.flush
  nil
end
display_compact_table(hashes, keys = nil, **options, &block) click to toggle source
# File lib/formatador/table.rb, line 10
def display_compact_table(hashes, keys = nil, **options, &block)
  headers = keys || []
  widths = {}

  # Calculate Widths
  if hashes.empty? && keys
    keys.each do |key|
      widths[key] = key.to_s.length
    end
  else
    hashes.each do |hash|
      next unless hash.respond_to?(:keys)

      (headers + hash.keys).each do |key|
        if !keys
          headers << key
        end
        widths[key] = [ length(key), widths[key] || 0, length(calculate_datum(key, hash)) || 0].max
      end
      headers = headers.uniq
    end
  end

  # Determine order of headers
  if block_given?
    headers = headers.sort(&block)
  elsif !keys
    headers = headers.sort {|x,y| x.to_s <=> y.to_s}
  end

  # Display separator row
  split = "+"
  if headers.empty?
    split << '--+'
  else
    headers.each do |header|
      widths[header] ||= length(header)
      split << ('-' * (widths[header] + 2)) << '+'
    end
  end
  display_line(split)

  # Display data row
  columns = []
  headers.each do |header|
    columns << "[bold]#{header}[/]#{' ' * (widths[header] - header.to_s.length)}"
  end
  display_line("| #{columns.join(' | ')} |")
  display_line(split)

  hashes.each do |hash|
    if hash.respond_to? :keys
      columns = headers.map do |header|
        datum = calculate_datum(header, hash)
        width = widths[header] - length(datum)
        width = width < 0 ? 0 : width

        datum.is_a?(Numeric) && options[:numeric_rjust] ? "#{' ' * width}#{datum}" : "#{datum}#{' ' * width}"
      end
      display_line("| #{columns.join(' | ')} |")
    else
      if hash == :split
        display_line(split)
      end 
    end
    nil
  end
  display_line(split)
end
display_line(string = '') click to toggle source
# File lib/formatador.rb, line 69
def display_line(string = '')
  display(string)
  new_line
  nil
end
display_lines(lines = []) click to toggle source
# File lib/formatador.rb, line 75
def display_lines(lines = [])
  for line in [*lines]
    display_line(line)
  end
  nil
end
display_table(hashes, keys = nil, **options, &block) click to toggle source
# File lib/formatador/table.rb, line 2
def display_table(hashes, keys = nil, **options, &block)
  new_hashes = hashes.inject([]) do |accum,item|
    accum << :split unless accum.empty?
    accum << item
  end
  display_compact_table(new_hashes, keys, **options, &block)
end
indent() { || ... } click to toggle source
# File lib/formatador.rb, line 90
def indent(&block)
  @indent += 1
  yield
ensure
  @indent -= 1
end
indentation() click to toggle source
# File lib/formatador.rb, line 97
def indentation
  '  ' * @indent
end
new_line() click to toggle source
# File lib/formatador.rb, line 113
def new_line
  print("\n")
  nil
end
parse(string) click to toggle source
# File lib/formatador.rb, line 82
def parse(string)
  if $stdout.tty?
    string.gsub(PARSE_REGEX) { "\e[#{STYLES[$1.to_sym]}m" }.gsub(INDENT_REGEX) { indentation }
  else
    strip(string)
  end
end
redisplay(string = '', width = 120) click to toggle source
# File lib/formatador.rb, line 101
def redisplay(string = '', width = 120)
  print("\r#{' ' * width}\r")
  display("#{string}")
  nil
end
redisplay_line(string = '', width = 120) click to toggle source
# File lib/formatador.rb, line 107
def redisplay_line(string = '', width = 120)
  redisplay(string, width)
  new_line
  nil
end
redisplay_progressbar(current, total, options = {}) click to toggle source
# File lib/formatador/progressbar.rb, line 34
def redisplay_progressbar(current, total, options = {})
  options = { :color => 'white', :width => 50, :new_line => true }.merge!(options)
  data = progressbar(current, total, options)
  if current < total
    redisplay(data, options[:width])
  else
    redisplay("#{data}", options[:width])
    if options[:new_line]
      new_line
    end
    @progressbar_started_at = nil
  end
end
strip(string) click to toggle source
# File lib/formatador.rb, line 118
def strip(string)
  string.gsub(PARSE_REGEX, '').gsub(INDENT_REGEX) { indentation }
end

Private Instance Methods

calculate_datum(header, hash) click to toggle source
# File lib/formatador/table.rb, line 93
def calculate_datum(header, hash)
  if !hash.keys.include?(header) && (splits = header.to_s.split('.')).length > 1
    datum = nil
    splits.each do |split|
      d = (datum||hash)
      datum = d[split] || d[split.to_sym] || ''
    end
  else
    datum = hash.fetch(header, '')
  end
  datum
end
length(value) click to toggle source
# File lib/formatador/table.rb, line 82
def length(value)
  if Module.const_defined?(:Unicode)
    Unicode.width(value.to_s.gsub(PARSE_REGEX, ''))
  else
    value.to_s.gsub(PARSE_REGEX, '').chars.reduce(0) { |sum, char| sum += char.bytesize > 1 ? 2 : 1 }
  end

rescue NotImplementedError
  value.to_s.gsub(PARSE_REGEX, '').chars.reduce(0) { |sum, char| sum += char.bytesize > 1 ? 2 : 1 }
end
progressbar(current, total, options) click to toggle source
# File lib/formatador/progressbar.rb, line 50
def progressbar(current, total, options)
  color = options[:color]
  started_at = options[:started_at]
  width = options[:width]

  output = []

  if options[:label]
    output << options[:label]
  end

  # width
  # we are going to write a string that looks like "   current/total"
  # It would be nice if it were left padded with spaces in such a way that
  # it puts the progress bar in a constant place on the page. This witdh
  # calculation allows for the "current" string to be up to two characters
  # longer than the "total" string without problems. eg- current =
  # 9.99, total = 10
  padding = total.to_s.size * 2 + 3

  output << "[#{color}]%#{padding}s[/]" % "#{current}/#{total}"

  percent = current.to_f / total.to_f
  percent = 0 if percent < 0
  percent = 1 if percent > 1

  done = '*' * (percent * width).ceil
  remaining = ' ' * (width - done.length)
  output << "[_white_]|[/][#{color}][_#{color}_]#{done}[/]#{remaining}[_white_]|[/]"

  if started_at
    elapsed = Time.now - started_at
    minutes = (elapsed / 60).truncate.to_s
    seconds = (elapsed % 60).truncate.to_s
    output << "#{minutes}:#{'0' if seconds.size < 2}#{seconds}"
  end

  output << ''
  output.join('  ')
end