class ConsoleTable::ConsoleTableClass
Attributes
Public Class Methods
new(column_layout, options={})
click to toggle source
# File lib/console_table.rb, line 31 def initialize(column_layout, options={}) @original_column_layout = [] if column_layout.is_a? Integer column_layout = (1..column_layout).collect{|i| "Column #{i}"} end if column_layout.is_a? Array column_layout.each_with_index do |layout, i| if layout.is_a? String @original_column_layout << {:key => "col#{i+1}".to_sym, :title=>layout, :size=>"*"} elsif layout.is_a? Integer @original_column_layout << {:key => "col#{i+1}".to_sym, :title=>"Column #{i+1}", :size=>layout} elsif layout.is_a? Float @original_column_layout << {:key => "col#{i+1}".to_sym, :title=>"Column #{i+1}", :size=>layout} elsif layout[:key].nil? and layout[:title].nil? @original_column_layout << layout.merge({:key => "col#{i+1}".to_sym, :title=>"Column #{i+1}"}) elsif layout[:title].nil? @original_column_layout << layout.merge({:title => layout[:key].to_s.capitalize}) elsif layout[:key].nil? @original_column_layout << layout.merge({:key => "col#{i+1}".to_sym}) else @original_column_layout << layout end end else raise("Column layout invalid, must be a num of columns or an array of column definitions") end #Mostly used for mocking/testing @out = options[:output] || $stdout @set_width = options[:width] @title = options[:title] @borders = options[:borders] || false #Lines between every cell, implies outline @left_margin = options[:left_margin] || 0 @right_margin = options[:right_margin] || 0 @headings = options[:headings].nil? ? true : options[:headings] @ellipse = options[:ellipse] || "..." #Set outline, just the upper and lower lines if @borders @outline = true elsif not options[:outline].nil? @outline = options[:outline] else @outline = true end @footer = [] @headings_printed = false @count = 0 calc_column_widths Signal.trap('SIGWINCH', proc { calc_column_widths }) end
Public Instance Methods
<<(options)
click to toggle source
Add rows to the table. Prints immediately, consult documentation for examples
# File lib/console_table.rb, line 25 def <<(options) print(options) end
Protected Instance Methods
print_header()
click to toggle source
# File lib/console_table.rb, line 88 def print_header() #Kind of weird but basically if there's a title, there will be a space between the top border and the actual data, meaning we don't #want special characters printed for the "joining" of the lines. If there's no title, however, we do. if @title.nil? print_line("=", "*", false) else print_line("=", "*", true) end if @outline unless @title.nil? @out.print " "*@left_margin @out.print "|" if @borders @out.print format(@working_width, @title, false, :center) @out.print "|" if @borders @out.print "\n" print_line if @borders end end
Private Instance Methods
calc_column_widths()
click to toggle source
# File lib/console_table.rb, line 276 def calc_column_widths() @column_widths = [] total_width = @set_width begin total_width = TermInfo.screen_columns rescue => ex total_width = ENV["COLUMNS"].to_i unless ENV["COLUMNS"].nil? total_width = 79 if total_width.nil? end if total_width.nil? keys = @original_column_layout.collect { |d| d[:key] }.uniq if keys.length < @original_column_layout.length raise("ConsoleTable configuration invalid, same key defined more than once") end num_spacers = @original_column_layout.length - 1 num_spacers = num_spacers + 2 if @borders set_sizes = @original_column_layout.collect { |x| x[:size] }.find_all { |x| x.is_a? Integer } used_up = set_sizes.inject(:+) || 0 available = total_width - used_up - @left_margin - @right_margin - num_spacers if available < 0 raise("ConsoleTable configuration invalid, current window is too small to display required sizes") end percentages = @original_column_layout.collect { |x| x[:size] }.find_all { |x| x.is_a? Float } percent_used = percentages.inject(:+) || 0 if percent_used > 1.0 raise("ConsoleTable configuration invalid, percentages total value greater than 100%") end percent_available = 1 - percent_used stars = @original_column_layout.collect { |x| x[:size] or x[:size].nil? }.find_all { |x| x.is_a? String } num_stars = [stars.length, 1].max percent_for_stars = percent_available.to_f / num_stars @original_column_layout.each do |column_config| if column_config[:size].is_a? Integer @column_widths << column_config #As-is when integer elsif column_config[:size].is_a? Float @column_widths << column_config.merge({:size => (column_config[:size]*available).floor}) elsif column_config[:size].nil? or column_config[:size].is_a?(String) && column_config[:size] == "*" @column_widths << column_config.merge({:size => (percent_for_stars*available).floor}) else raise("ConsoleTable configuration invalid, '#{column_config[:size]}' is not a valid size") end end @working_width = (@column_widths.inject(0) { |res, c| res+c[:size] }) + @column_widths.length - 1 end
format(length, text, ellipsize=false, justify=:left)
click to toggle source
# File lib/console_table.rb, line 334 def format(length, text, ellipsize=false, justify=:left) uncolorized = uncolorize(text) if uncolorized.length > length ellipsize = false if uncolorize(@ellipse).length >= length if ellipsize goal_length = length-uncolorize(@ellipse).length else goal_length = length end parts = text.scan(/(\e\[\d.*?m)|(.)/) #The idea here is to break the string up into control codes and single characters #We're going to now count up until we hit goal length, but we're not going to ever count control codes against the count #We're also going to keep track of if a non-resetting control code is 'active', so we know to reset at the end if need-be #I can't think of a better way to do this, it's probably dumb current_length = 0 current_index = 0 final_string_parts = [] color_active = false while current_length < goal_length color_code, regular_text = parts[current_index] if not regular_text.nil? current_length = current_length + 1 final_string_parts << regular_text elsif not color_code.nil? if color_code == "\e[0m" color_active = false if color_active else color_active = true end final_string_parts << color_code end current_index = current_index + 1 end final_string_parts << @ellipse if ellipsize final_string_parts << "\e[0m" if color_active final_string_parts.join("") else space = length-uncolorized.length if justify == :right (" "*space) + text elsif justify == :center left_side = space/2 right_side = space - left_side (" " * left_side) + text + (" "*right_side) else #assume left text + (" "*space) end end end
infer_justify_from_string(to_print, justify)
click to toggle source
# File lib/console_table.rb, line 252 def infer_justify_from_string(to_print, justify) uncolorized = uncolorize(to_print) if uncolorized.start_with?("\t") and uncolorized.end_with?("\t") justify = :center elsif uncolorized.start_with?("\t") justify = :right elsif uncolorized.end_with?("\t") justify = :left end justify end
normalize(string)
click to toggle source
# File lib/console_table.rb, line 264 def normalize(string) if string.nil? nil else normalized = string.to_s normalized = normalized.sub(/^(\e\[\d[^m]*?m)(\s+)/, '\2\1') #Any leading spaces preceeded by a color code should be swapped with the color code itself, so the spaces themselves aren't colored normalized = normalized.sub(/(\s+)(\e\[\d[^m]*?m)$/, '\2\1') normalized = normalized.gsub(/\s+/, " ").strip #Primarily to remove any tabs or newlines normalized end end
print(options)
click to toggle source
# File lib/console_table.rb, line 189 def print(options) if options.is_a? String print_plain(options) return end print_headings unless @headings_printed or not @headings if options.is_a? Array #If an array or something is supplied, infer the order from the heading order munged_options = {} options.each_with_index do |element, i| munged_options[@original_column_layout[i][:key]] = element end options = munged_options end print_line if @borders unless not @headings and @count == 0 @out.print " "*@left_margin if @borders @out.print "|" end #column order is set, so go through each column and look up values in the incoming options @column_widths.each_with_index do |column, i| to_print = options[column[:key]] || "" justify = column[:justify] || :left ellipsize = column[:ellipsize] || false if to_print.is_a? String justify = infer_justify_from_string(to_print, justify) @out.print format(column[:size], normalize(to_print), ellipsize, justify) elsif to_print.is_a? Hash justify = infer_justify_from_string(to_print[:text], justify) text = normalize(to_print[:text]) || "" ellipsize = to_print[:ellipsize] unless to_print[:ellipsize].nil? justify = to_print[:justify] unless to_print[:justify].nil? formatted=format(column[:size], text, ellipsize, justify) @out.print formatted else text = to_print.to_s justify = infer_justify_from_string(text, justify) @out.print format(column[:size], normalize(text), ellipsize, justify) end if @borders @out.print "|" else @out.print " " if i < @column_widths.size-1 end end @out.print "\n" @count = @count + 1 end
print_headings()
click to toggle source
# File lib/console_table.rb, line 129 def print_headings() @headings_printed = true @out.print " "*@left_margin if @borders @out.print "|" end @column_widths.each_with_index do |column, i| justify = column[:justify] || :left ellipsize = column[:ellipsize] || false title = column[:title].strip @out.print format(column[:size], title, ellipsize, justify) if @borders @out.print "|" else @out.print " " if i < @column_widths.size-1 end end @out.print "\n" print_line unless @borders #this line will be printed when the NEXT LINE of actual data prints out if borders are on, because that call PRE-prints the separator line end
print_line(char="-", join_char="+", edge_join_only=false)
click to toggle source
# File lib/console_table.rb, line 154 def print_line(char="-", join_char="+", edge_join_only=false) if @borders #use +'s to join columns @out.print " " * @left_margin @out.print join_char @column_widths.each_with_index do |column, i| @out.print char*column[:size] if edge_join_only and i < @column_widths.length - 1 @out.print char else @out.print join_char end end @out.print "\n" else #just print long lines @out.print " " * @left_margin @out.print "#{char}" * (@working_width + (@borders ? 2 : 0)) @out.print "\n" end end
print_plain(to_print)
click to toggle source
# File lib/console_table.rb, line 390 def print_plain(to_print) print_line if @borders @out.print " "*@left_margin @out.print "|" if @borders if to_print.is_a? String justify = infer_justify_from_string(to_print, :left) @out.print format(@working_width, normalize(to_print), false, justify) end @out.print "|" if @borders @out.print "\n" end
uncolorize(string)
click to toggle source
# File lib/console_table.rb, line 330 def uncolorize(string) string.gsub(/\e\[\d[^m]*?m/m, "") end