class Columnize::Columnizer

Constants

ARRANGE_ARRAY_OPTS
ATTRS

TODO: change colfmt to cell_format; change colsep to something else

OLD_AND_NEW_KEYS

Attributes

list[R]
opts[R]

Public Class Methods

new(list=[], opts={}) click to toggle source
# File lib/columnize/columnize.rb, line 14
def initialize(list=[], opts={})
  self.list = list
  self.opts = DEFAULT_OPTS.merge(opts)
end

Public Instance Methods

arrange_by_column(list, nrows, ncols) click to toggle source

Given list, ncols, nrows, arrange the one-dimensional array into a 2-dimensional lists of lists organized by columns.

In either horizontal or vertical arrangement, we will need to access this for the list data or for the width information.

Here is an example: #arrange_by_column((1..5).to_a, 2, 3) =>

[[1,3,5], [2,4]]
# File lib/columnize/columnize.rb, line 133
def arrange_by_column(list, nrows, ncols)
  (0...ncols).map do |i|
    (0..nrows-1).inject([]) do |row, j|
      k = i + (j * ncols)
      k < list.length ? row << list[k] : row
    end
  end
end
arrange_by_row(list, nrows, ncols) click to toggle source

Given list, ncols, nrows, arrange the one-dimensional array into a 2-dimensional lists of lists organized by rows.

In either horizontal or vertical arrangement, we will need to access this for the list data or for the width information.

Here is an example: #arrange_by_row((1..5).to_a, 3, 2) =>

[[1,2], [3,4], [5]],
# File lib/columnize/columnize.rb, line 119
def arrange_by_row(list, nrows, ncols)
  (0...nrows).map {|r| list[r*ncols, ncols] }.compact
end
columnize() click to toggle source
# File lib/columnize/columnize.rb, line 41
def columnize
  return @short_circuit if @short_circuit

  rows, colwidths = min_rows_and_colwidths
  ncols = colwidths.length
  justify = lambda {|t, c|
      @ljust ? t.ljust(colwidths[c]) : t.rjust(colwidths[c])
  }
  textify = lambda do |row|
    row.map!.with_index(&justify) unless ncols == 1 && @ljust
    "#{@line_prefix}#{row.join(@colsep)}#{@line_suffix}"
  end

  text = rows.map(&textify)
  text.first.sub!(/^#{@line_prefix}/, @array_prefix) unless @array_prefix.empty?
  text.last.sub!(/#{@line_suffix}$/, @array_suffix) unless @array_suffix.empty?
  text.join("\n") # + "\n" # if we want extra separation
end
list=(list) click to toggle source
# File lib/columnize/columnize.rb, line 19
def list=(list)
  @list = list
  if @list.is_a? Array
    @short_circuit = @list.empty? ? "<empty>\n" : nil
  else
    @short_circuit = ''
    @list = []
  end
end
min_rows_and_colwidths() click to toggle source

TODO: make this a method, rather than a function (?) compute the smallest number of rows and the max widths for each column

# File lib/columnize/columnize.rb, line 62
def min_rows_and_colwidths
  list = @list.map(&@stringify)
  cell_widths = list.map(&@term_adjuster).map(&:size)

  # Set default arrangement: one atom per row
  cell_width_max = cell_widths.max
  result = [arrange_by_row(list, list.size, 1), [cell_width_max]]

  # If any atom > @displaywidth, stop and use one atom per row.
  return result if cell_width_max > @displaywidth

  # For horizontal arrangement, we want to *maximize* the number
  # of columns. Thus the candidate number of rows (+sizes+) starts
  # at the minumum number of rows, 1, and increases.

  # For vertical arrangement, we want to *minimize* the number of
  # rows. So here the candidate number of columns (+sizes+) starts
  # at the maximum number of columns, list.length, and
  # decreases. Also the roles of columns and rows are reversed
  # from horizontal arrangement.

  # Loop from most compact arrangement to least compact, stopping
  # at the first successful packing.  The below code is tricky,
  # but very cool.
  #
  # FIXME: In the below code could be DRY'd. (The duplication got
  # introduced when I revised the code - rocky)
  if @arrange_vertical
    (1..list.length).each do |size|
      other_size = (list.size + size - 1) / size
      colwidths = arrange_by_row(cell_widths, other_size, size).map(&:max)
      totwidth = colwidths.inject(&:+) + ((colwidths.length-1) * @colsep.length)
      return [arrange_by_column(list, other_size, size), colwidths] if
        totwidth <= @displaywidth
    end
  else
    list.length.downto(1).each do |size|
      other_size = (list.size + size - 1) / size
      colwidths = arrange_by_column(cell_widths, other_size, size).map(&:max)
      totwidth = colwidths.inject(&:+) + ((colwidths.length-1) * @colsep.length)
      return [arrange_by_row(list, other_size, size), colwidths] if
        totwidth <= @displaywidth
    end
  end
  result
end
opts=(opts) click to toggle source

TODO: freeze @opts

# File lib/columnize/columnize.rb, line 30
def opts=(opts)
  @opts = opts
  OLD_AND_NEW_KEYS.each {|old, new| @opts[new] = @opts.delete(old) if @opts.keys.include?(old) and !@opts.keys.include?(new) }
  @opts.merge!(ARRANGE_ARRAY_OPTS) if @opts[:arrange_array]
  set_attrs_from_opts
end
set_attrs_from_opts() click to toggle source
# File lib/columnize/columnize.rb, line 142
def set_attrs_from_opts
  ATTRS.each {|attr| self.instance_variable_set "@#{attr}", @opts[attr] }

  @ljust = !@list.all? {|datum| datum.kind_of?(Numeric)} if @ljust == :auto
  @displaywidth -= @line_prefix.length
  @displaywidth = @line_prefix.length + 4 if @displaywidth < 4
  @stringify = @colfmt ? lambda {|li| @colfmt % li } : lambda {|li| li.to_s }
  @term_adjuster = @opts[:term_adjust] ? lambda {|c| c.gsub(/\e\[.*?m/, '') } : lambda {|c| c }
end
update_opts(opts) click to toggle source
# File lib/columnize/columnize.rb, line 37
def update_opts(opts)
  self.opts = @opts.merge(opts)
end