Module: Columnize

Defined in:
lib/columnize.rb,
lib/version.rb

Overview

Adapted from the routine of the same name in cmd.py

Constant Summary collapse

VERSION =
'0.3.2'

Class Method Summary collapse

Class Method Details

.columnize(list, displaywidth = 80, colsep = ' ', arrange_vertical = true, ljust = true, lineprefix = '') ⇒ Object

or arranged horizontally:

['1', '2,', '3', '4'] => '1  2\n3  4\n'

Each column is only as wide possible, no larger than +displaywidth’. If list is not an array, the empty string, ”, is returned. By default, columns are separated by two spaces - one was not legible enough. Set colsep to adjust the string separate columns. If arrange_vertical is set false, consecutive items will go across, left to right, top to bottom.



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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
# File 'lib/columnize.rb', line 58

def columnize(list, displaywidth=80, colsep = '  ', 
              arrange_vertical=true, ljust=true, lineprefix='')

  # Some degenerate cases
  if not list.is_a?(Array)
    return ''
  end
  if list.size == 0
    return  "<empty>\n"
  end
  l = list.map{|li| li.to_s}
  if 1 == l.size
    return "#{l[0]}\n"
  end

  nrows = ncols = 0  # Make nrows, ncols have more global scope
  colwidths = []     # Same for colwidths
  displaywidth = [4, displaywidth - lineprefix.length].max
  if arrange_vertical
    array_index = lambda {|num_rows, row, col| num_rows*col + row }
    # Try every row count from 1 upwards
    1.upto(l.size-1) do |_nrows|
      nrows = _nrows
      ncols = (l.size + nrows-1) / nrows
      colwidths = []
      totwidth = -colsep.length

      0.upto(ncols-1) do |_col|
        col = _col
        # get max column width for this column
        colwidth = 0
        0.upto(nrows-1) do |_row|
          row = _row
          i = array_index.call(nrows, row, col)
          if i >= l.size
            break
          end
          colwidth = [colwidth, l[i].size].max
        end
        colwidths << colwidth
        totwidth += colwidth + colsep.length
        if totwidth > displaywidth
          ncols = col
          break
        end
      end
      if totwidth <= displaywidth
        break
      end
    end
    # The smallest number of rows computed and the
    # max widths for each column has been obtained.
    # Now we just have to format each of the
    # rows.
    s = ''
    0.upto(nrows-1) do |_row| 
      row = _row
      texts = []
      0.upto(ncols-1) do |_col|
        col = _col
        i = array_index.call(nrows, row, col)
        if i >= l.size
          x = ""
        else
          x = l[i]
        end
        texts << x
      end
      while texts and texts[-1] == ''
        texts = texts[0..-2]
      end
      if texts.size > 0
        0.upto(texts.size-1) do |_col|
          col = _col
          if ljust
              texts[col] = texts[col].ljust(colwidths[col])
          else
              texts[col] = texts[col].rjust(colwidths[col])
          end
        end
        s += "%s%s\n" % [lineprefix, texts.join(colsep)]
      end
    end
    return s
  else
    array_index = lambda {|num_rows, row, col| ncols*(row-1) + col }
    # Try every column count from size downwards
    # Assign to make enlarge scope of loop variables 
    totwidth = i = rounded_size = 0  
    l.size.downto(0) do |_ncols|
      ncols = _ncols
      # Try every row count from 1 upwards
      min_rows = (l.size+ncols-1) / ncols
      min_rows.upto(l.size) do |_nrows|
        nrows = _nrows
        rounded_size = nrows * ncols
        colwidths = []
        totwidth = -colsep.length
        colwidth = row = 0
        0.upto(ncols-1) do |_col|
          col = _col
          # get max column width for this column
          1.upto(nrows) do |_row|
            row = _row
            i = array_index.call(nrows, row, col)
            if i >= rounded_size 
              break
            elsif i < l.size
              colwidth = [colwidth, l[i].size].max
            end
          end
          colwidths << colwidth
          totwidth += colwidth + colsep.length
          if totwidth > displaywidth
            break
          end
        end
        if totwidth <= displaywidth
          # Found the right nrows and ncols
          nrows  = row
          break
        elsif totwidth >= displaywidth
          # Need to reduce ncols
          break
        end
      end
      if totwidth <= displaywidth and i >= rounded_size-1
          break
      end
    end
    # The smallest number of rows computed and the
    # max widths for each column has been obtained.
    # Now we just have to format each of the
    # rows.
    s = ''
    1.upto(nrows) do |row| 
      texts = []
      0.upto(ncols-1) do |col|
        i = array_index.call(nrows, row, col)
        if i >= l.size
          break
        else
          x = l[i]
        end
        texts << x
      end
      0.upto(texts.size-1) do |col|
        if ljust
          texts[col] = texts[col].ljust(colwidths[col])
        else
          texts[col] = texts[col].rjust(colwidths[col])
        end
      end
      s += "%s%s\n" % [lineprefix, texts.join(colsep)]
    end
    return s
  end
end