Class: Columnize::Columnizer

Inherits:
Object
  • Object
show all
Defined in:
lib/columnize/columnize.rb

Constant Summary collapse

ARRANGE_ARRAY_OPTS =
{:array_prefix => '[', :line_prefix => ' ', :line_suffix => ',', :array_suffix => ']', :colsep => ', ', :arrange_vertical => false}
OLD_AND_NEW_KEYS =
{:lineprefix => :line_prefix, :linesuffix => :line_suffix}
ATTRS =

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

[:arrange_vertical, :array_prefix, :array_suffix, :line_prefix, :line_suffix, :colfmt, :colsep, :displaywidth, :ljust]

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(list = [], opts = {}) ⇒ Columnizer

Returns a new instance of Columnizer.



14
15
16
17
# File 'lib/columnize/columnize.rb', line 14

def initialize(list=[], opts={})
  self.list = list
  self.opts = DEFAULT_OPTS.merge(opts)
end

Instance Attribute Details

#listObject

Returns the value of attribute list.



12
13
14
# File 'lib/columnize/columnize.rb', line 12

def list
  @list
end

#optsObject

Returns the value of attribute opts.



12
13
14
# File 'lib/columnize/columnize.rb', line 12

def opts
  @opts
end

Instance Method Details

#arrange_by_column(list, nrows, ncols) ⇒ Object

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]]


133
134
135
136
137
138
139
140
# 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) ⇒ Object

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]],


119
120
121
# File 'lib/columnize/columnize.rb', line 119

def arrange_by_row(list, nrows, ncols)
  (0...nrows).map {|r| list[r*ncols, ncols] }.compact
end

#columnizeObject



41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# 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

#min_rows_and_colwidthsObject

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



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
# 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

#set_attrs_from_optsObject



142
143
144
145
146
147
148
149
150
# 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) ⇒ Object



37
38
39
# File 'lib/columnize/columnize.rb', line 37

def update_opts(opts)
  self.opts = @opts.merge(opts)
end