Skip to content

Instantly share code, notes, and snippets.

@mseymour
Created October 23, 2011 20:33
Show Gist options
  • Save mseymour/1307857 to your computer and use it in GitHub Desktop.
Save mseymour/1307857 to your computer and use it in GitHub Desktop.
ascii table generating class
# Should really make a note here:
# This class currently only accepts arrays of data that has separators, rather than being a two-dimensional array. This will be fixed at some point.
# It will also not take a single string, or other types of collections. This will also be fixed at some point (in that case, table headings would have to be revamped to allow key->value pairings.
# - Mark
# -*- coding: utf-8 -*-
require 'active_support/core_ext/object/blank'
module Helpers
# Formats a supplied array into a list or table.
# @author Mark Seymour ('Azure') (mark.seymour.ns@gmail.com)
#
# @param [Array] The source array.
# @param [Hash] params Options for generating the table.
# @option params [String] :splitchars ('\t') Characters to split each individual item on.
# @option params [Regexp] :regexp (nil) A Regexp to split each individual item on. If one is supplied, then :splitchars is ignored.
# @option params [Array] :justify ([:left]) Changes the justification of individual table items. If there are more headers set than column justifications, the default will be used. Valid options are :left or :right.
# @option params [Array] :headers ([]) Sets the names for the table column headers. If left unset, no headers will be generated.
# @option params [Integer] :gutter (4) Sets the gutter size between columns and optionally the left gutter.
# @option params [Boolean] :left_gutter (false) Generates a gutter on the left side of the generated table, equal to the same length as column gutters.
# @option params [Boolean] :display_indices (false) Shows the index #+1 of the row.
# @option params [Boolean] :display_noitems (true) Displays a notice if there are no items to show.
# @option params [String] :noitems_msg ("There is nothing to show.") Sets the message for display_noitems.
# @option params [Boolean] :display_eot (true) Displays a notice at the end of the table.
# @option params [String] :eot_msg ("End of results.") Sets the message for display_eot.
# @todo Have the ability to output either an array or string (params[:array]?)
# @return [String] The formatted string with line endings.
def Helpers.table_format array, params={}
params = {
splitchars: "\t",
regexp: nil,
justify: [:left], # :left, :right
headers: [], # ary (ex: ["a","b","c"])
gutter: 4,
left_gutter: false,
display_indices: false,
display_noitems: true,
noitems_msg: "There is nothing to show.",
display_eot: true,
eot_msg: "End of results."
}.merge!(params)
source = array.dup # We cannot be altering our original object now, can we?
# We use the str.tr method if our regexp param is nil.
# Otherwise, we just use regexp.
source.map! {|e| params[:regexp].nil? ? e.tr(params[:splitchars], "\t").split("\t") : e.match(params[:regexp])[1..-1].map {|e| e.nil? ? "" : e; } }
# calculating the maximum length of each column
column_lengths = []
# optional index
if params[:display_indices]
params[:justify].unshift(:right)
params[:headers].unshift("#")
source.each_with_index.map {|e,i| e.unshift(i.succ)}
end
source.dup.unshift(params[:headers]).each {|e|
e.each_with_index {|item,index|
column_lengths[index] = [] if column_lengths[index].blank?
column_lengths[index] << item.size
}
}
column_lengths.map! {|e| e.sort.last }
data = []
# Generating table headers
if !params[:headers].blank?
# Generating the headers, separators, etc.
s_header = []
s_separator = s_header.dup
params[:headers].each_with_index {|e,i|
s_header << "%#{"-" if params[:justify][i] == :left || params[:justify][i].nil?}#{column_lengths[i]}s" % e.to_s
s_separator << "-"*column_lengths[i]
}
data << s_header.join(" "*params[:gutter]) << s_separator.join(" "*params[:gutter])
end
# Generating formatted table rows
source.each {|e|
line = []
e.each_with_index {|item,index|
line << "%#{"-" if params[:justify][index] == :left || params[:justify][index].nil?}#{column_lengths[index]}s" % item.to_s
}
data << line.join(" "*params[:gutter])
}
# Adding noitems_msg if there are well... no items.
if source.empty? && params[:display_noitems] then data << params[:noitems_msg] end
# Adding EOT message
if params[:display_eot]
data << "-" * params[:eot_msg].length
data << params[:eot_msg]
end
# Adding a gutter to the left side
if params[:left_gutter] === true then data.map! {|e| " "*params[:gutter] + e } end
data.join("\n")
end
end
=begin
my_array = ["column 1 r1 aa\tcolumn 2 r1 aaa\tcolumn 3 r1 aaaa",
"column 1 r2 bbbb\tcolumn 2 r2 b\tcolumn 3 r2 bbbbbbbbb",
"column 1 r3\tcolumn 2 r3 ffffffffff\tcolumn 3 r3 fff"]
puts Helpers.table_format my_array, justify: [:right,:left,:right], gutter: 2, headers: ["column 1","column 2","column3"], display_indices: true
=end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment