Created
March 9, 2012 17:14
-
-
Save tlowrimore/2007605 to your computer and use it in GitHub Desktop.
Layout Plain-text with columns and shit. (Ruby 1.9)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Quickly thrown together, but it works, and maybe it'll get YOU started on | |
# a better solution to the problem. Enjoy! | |
class TextLayout | |
attr_reader :page_width, :tab_width | |
def initialize(tab_width=4, page_width=80) | |
@tab_width, @page_width = tab_width, page_width | |
end | |
# Takes a title and an optional character which will be used | |
# to surround the title with a rule that spans the width | |
# of the page. | |
def header(title, chr="-") | |
[ rule(chr), title, rule(chr), "" ] * "\n" | |
end | |
# Takes either a Hash or an Array of Arrays and an optional | |
# character used to create a rule between each record in | |
# the dataset. This method makes its best effort to layout | |
# the data in columns. | |
def columns(data, chr=nil) | |
unless data.empty? | |
data_array = data.to_a | |
ws = column_widths data_array | |
data_array.each_with_object([]) { |row, a| | |
a << apply_widths(row, ws) | |
a << rule(chr) if chr | |
} * "\n" | |
end | |
end | |
private | |
# Returns the column widths of the supplied data with @tab_width padding | |
# applied to all but the last column. | |
def column_widths(data) | |
# ws (widths) is an array of the lengths of the longest word in each column. | |
data.transpose.map { |col| col.map(&:to_s).max_by(&:length).length }.tap { |ws| | |
# total column padding width | |
pw = (ws.length - 1) * @tab_width | |
# Determine the overflow; that is to say, the difference between the sum of | |
# column widths and the page width. Also, find the index of the max (i.e. widest) | |
# column. | |
overflow, max = [0, ws.reduce(:+) + pw - @page_width].max, ws.each_with_index.max.last | |
# Subtract the overflow from the widest column width. | |
ws[max] = ws[max] - overflow | |
} | |
end | |
def apply_widths(row, widths) | |
rw_pairs = row.map{ |val| val.to_s.dup }.zip(widths) | |
# First we need to know the maximum number of lines in a row, after | |
# the line has been split on it column width. | |
line_count = rw_pairs.map { |str, w| | |
str.gsub! /\n/, " " | |
str.scan(line_upto(w)).length | |
}.max | |
# Now we format the row. | |
rw_pairs.map { |str, w| | |
line_count.times.map { str.slice!(line_upto(w)).to_s.strip.ljust(w + @tab_width) } | |
}.transpose.map(&:join) * "\n" | |
end | |
def line_upto(length) | |
/.{1,#{length}}(?:\s|$)/ | |
end | |
def rule(chars=nil) | |
if chars.to_s.length > 0 | |
ch_len = chars.length | |
chars * (@page_width / ch_len) + chars[0, (@page_width % ch_len)] | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment