Class: ColumnFormatter

Inherits:
Object show all
Defined in:
lib/utilrb/column_formatter.rb

Overview

Displays a set of data into a column-formatted table

Constant Summary collapse

MARGIN =
1
SCREEN_WIDTH =
80

Class Method Summary collapse

Class Method Details

.from_hashes(data, io = STDOUT, options = Hash.new) ⇒ Object

Formats the given array of hash column-wise.

data is an array of hash. In this array, each element is a sample. The column names are defined from the hash keys. If one hash does not have a value for a column, “-” is displayed instead.

In the output, the columns are ordered alphabetically by default. Alternatively, they can be ordered by giving an :order option which is an array of string:

from_hashes(data, STDOUT, :order => %w{Col0 Col1 Col2})

Finally, the method can yield the set of available columns to a block (if given), and this block should return an ordered array of string.

In both cases, columns not listed in the ordering array are not displayed.

The formatting can be controlled by the following options:

header_delimiter

if true, displays a line of dashes between the header and the rest of the table

column_delimiter

a string that is inserted between columns

left_padding

a string that is inserted in front of each line

order

an array of column names, defining which columns should be displayed, and in which order they should be displayed. See above for more explanations.

screen_width

if the table is wider than this count of characters, it is split into multiple tables.

margin

defines how many spaces are inserted between two columns.



43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
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
# File 'lib/utilrb/column_formatter.rb', line 43

def self.from_hashes(data, io = STDOUT, options = Hash.new)
    options = validate_options options, :margin => MARGIN,
        :screen_width => SCREEN_WIDTH,
        :header_delimiter => false,
        :column_delimiter => "",
        :left_padding => "",
        :order => nil

    margin       = options[:margin]
    screen_width = options[:screen_width]

	width = Hash.new

	# First, determine the columns width and height, and
	# convert data into strings
	data = data.map do |line_data|
 line_data = line_data.inject({}) do |h, (label, value)|
		h[label.to_s] = value.to_s
		h
 end
		
 line_data.each do |label, value|
		unless width.has_key?(label)
  width[label] = label.length
		end

		if width[label] < value.length
  width[label] = value.length
		end
 end
	end

	# Then ask the user to sort the keys for us
	names = width.keys.dup
	names.delete('label')
	names = if options[:order] then options[:order]
            elsif block_given? then yield(names)
		else names.sort
		end

	# Finally, format and display
	while !names.empty?
 # we determine the set of columns to display
 if width.has_key?('label')
		line_n = ['label']
		line_w = width['label']
		format = ["%-#{line_w}s"]
 else
		line_n = []
		line_w = 0
		format = []
 end
 
 while !names.empty? && (line_w < screen_width)
		col_n = names.shift
		col_w = width[col_n] || 0
		line_n << col_n
		line_w += col_w
		format << "%-#{col_w}s"
 end

 format = format.join(" " * margin + options[:column_delimiter] + " " * margin)
        header_line = format % line_n
 io.puts options[:left_padding] + header_line
        if options[:header_delimiter]
            io.puts options[:left_padding] + "-" * header_line.length
        end

        format = options[:left_padding] + format

 data.each do |line_data|
		line_data = line_data.values_at(*line_n)
		line_data.map! { |v| v || '-' }
		io.puts format % line_data
 end
	end
end