Class Grid
In: lib/grid.rb
Parent: Object

Parse and render Array of Arrays of Strings. To be replaced by Tabular.

Methods

Included Modules

ActionView::Helpers::TextHelper

Attributes

column_count  [R] 
column_map  [R] 
columns  [RW] 
custom_columns  [RW] 
delimiter  [R] 
padding  [R] 
quoted  [R] 
rows  [RW] 

Public Class methods

The Grid class maps columns by default — it changes them to lowercase and replaces spaces with underscores.

Options ===

  • delimiter: Cell delimiter. Defaults to tab
  • quoted: Cells are surrounded by quotes — remove first and last character. Default to false
  • columns = Array of column names as Strings or Array of Columns
  • header_row: First row is a list of column name. Header rows are parsed are deleted, so rows.first will return the second row from the source text.
                Defaults to false
    
  • column_map: Hash of column names. Replace column names from the original file with another name if the default mapping isn‘t enough.
                Example: 'birth date' => 'date_of_birth'.
                All keys are forced to lowercase for case-insenstive comparions
    
  • row_class: Map each row to this Class. Example: :row_class => Person

If both columns and header_row options are provided, columns is used to create the columns, and the first row is deleted and ignored

TODO Consider using regex for column maps

[Source]

    # File lib/grid.rb, line 24
24:   def initialize(source = '', *options)
25:     raise ArgumentError("'source' cannot be nil") if source.nil?
26:     
27:     options.flatten! if options
28:     @truncated = false
29:     @calculated_padding = false
30:     @custom_columns = []
31: 
32:     if (options.nil? || options.empty?)
33:       options_hash = {}
34:     else
35:       options_hash = options.first
36:     end
37: 
38:     @delimiter  = options_hash[:delimiter]  || '\t'
39:     @header_row = options_hash[:header_row] || false
40:     @quoted     = options_hash[:quoted]     || false
41:     
42:     @column_map = {}
43:     if options_hash[:column_map]
44:       options_hash[:column_map].each do |key, value|
45:         @column_map[key.downcase] = value
46:       end
47:     end
48:     
49:     @row_class = options_hash[:row_class]
50:     if @row_class
51:       @row_class_instance = @row_class.new
52:     end
53: 
54:     if source.is_a?(String)
55:       source = source.split(/\n/)
56:     end
57: 
58:     if @header_row and source.is_a?(Array) and !source.empty?
59:       columns_array = source.delete_at(0)
60:     end
61:     
62:     if options_hash[:columns]
63:       columns_array = options_hash[:columns]
64:     end
65:     self.columns = create_columns(columns_array)
66:     self.rows = source
67:   end

Public Instance methods

[Source]

    # File lib/grid.rb, line 69
69:   def [](row)
70:     if row > rows.size
71:       raise(ArgumentError, "#{row} is greater then the number of rows: #{rows.size}")
72:     end
73:     rows[row]
74:   end

Callback for sub classes

[Source]

     # File lib/grid.rb, line 192
192:   def after_columns_created
193:   end

[Source]

     # File lib/grid.rb, line 297
297:   def calculate_padding
298:     @calculated_padding = true
299:     @padding = []
300:     rows.each_with_index do |row, row_index|
301:       row_padding = []
302:       for index in 0..(column_count - 1)
303:         cell = row[index] || ''
304:         if cell.size <= column_size(index)
305:           padding = column_size(index) - cell.size
306:           row_padding << padding
307:         else
308:           row_padding << 0
309:         end
310:       end
311:       @padding << row_padding
312:     end
313:   end

[Source]

     # File lib/grid.rb, line 319
319:   def calculated_padding?
320:     @calculated_padding
321:   end

[Source]

     # File lib/grid.rb, line 122
122:   def column_count
123:     columns.size
124:   end

[Source]

     # File lib/grid.rb, line 126
126:   def column_size(index)
127:     if columns[index]
128:       columns[index].size
129:     else
130:       0
131:     end
132:   end

[Source]

     # File lib/grid.rb, line 118
118:   def columns
119:     @columns ||= []
120:   end

[Source]

     # File lib/grid.rb, line 134
134:   def create_columns(columns_array)
135:     self.columns = []
136:     return if columns_array.nil?
137: 
138:     columns_array = columns_array.split(/#{@delimiter}/) unless columns_array.is_a?(Array)
139:     self.columns = columns_array.collect do |column_name|
140:       description = column_name
141:       if column_name.is_a?(Column)
142:         column_name
143:       else
144:         column_name = column_name || ""
145:         column_name.strip! if column_name.respond_to?(:strip!)
146:         if quoted && column_name.respond_to?(:gsub!)
147:           column_name.gsub!(/^"/, '')
148:           column_name.gsub!(/"$/, '')
149:           description = column_name
150:         end
151:         if !column_name.blank? && @column_map[column_name.downcase]
152:           column_name = @column_map[column_name.downcase]
153:         end
154:       
155:         if column_name.is_a?(Column)
156:           column = column_name
157:         else
158:           column = Column.new(:name => column_name.to_s, :description => description)
159:         end
160: 
161:         unless column.name.blank?
162:           field = column.name.downcase
163:           field = field.underscore
164:           field.gsub!(' ', '_')
165:           if @column_map[field]
166:             if @column_map[field].is_a?(Column)
167:               column = @column_map[field]
168:             else
169:               column.field = @column_map[field]
170:             end
171:           else
172:             column.field = field
173:           end
174:         end
175:         column
176:       end
177:     end
178: 
179:     after_columns_created
180:     validate_columns
181:     
182:     columns.each do |column|
183:       unless column.description.blank?
184:         if !column.fixed_size && (column.description.size > column.size)
185:           column.size = column.description.size 
186:         end
187:       end
188:     end
189:   end

[Source]

     # File lib/grid.rb, line 323
323:   def delete_blank_rows
324:     rows.delete_if {|row|
325:       row.blank?
326:     }
327:   end

[Source]

     # File lib/grid.rb, line 245
245:   def header_to_s(row)
246:     text = ''
247:     for index in 0..(column_count - 1)
248:       cell = row[index] || ''
249:       if cell.size <= column_size(index)
250:         if columns[index].justification == Column::LEFT
251:           cell = cell.ljust(column_size(index))
252:         else
253:           cell = cell.rjust(column_size(index))
254:         end
255:       else
256:         cell = truncate(cell, :length => column_size(index))
257:       end
258:       if index + 1 == row.size
259:         text = "#{text}#{cell}"
260:       else
261:         text = "#{text}#{cell}   "
262:       end
263:     end
264:     "#{text}\n"
265:   end

[Source]

     # File lib/grid.rb, line 206
206:   def index_for_column_name(name)
207:     columns.each_with_index do |column, index|
208:       if column.name == name
209:         return index
210:       end
211:     end
212:     ''
213:   end

[Source]

     # File lib/grid.rb, line 215
215:   def inspect
216:     text = ""
217:     text << "#{columns}\n" if columns
218:     for row in rows
219:       text << row.inspect
220:     end
221:     text
222:   end

[Source]

     # File lib/grid.rb, line 114
114:   def row_count
115:     rows.size
116:   end

[Source]

     # File lib/grid.rb, line 267
267:   def row_to_s(row, row_index)
268:     text = ''
269:     for index in 0..(column_count - 1)
270:       cell = row[index] || ''
271:       if columns[index].justification == Column::LEFT
272:         cell = cell.ljust(column_size(index))
273:       else
274:         cell = cell.rjust(column_size(index))
275:       end
276:       if index + 1 == row.size
277:         text = "#{text}#{cell}"
278:       else
279:         text = "#{text}#{cell}   "
280:       end
281:     end
282:     "#{text}\n"
283:   end

[Source]

    # File lib/grid.rb, line 76
76:   def rows
77:     if @rows.nil?
78:       @rows = []
79:     end
80:     @rows
81:   end

Delimited String or Array of Strings or Arrays

[Source]

     # File lib/grid.rb, line 84
 84:   def rows=(source)
 85:     source.each do |row|
 86:       row = row.split(/#{@delimiter}/) unless row.is_a?(Array)
 87:       index = 0
 88:       row = row.collect do |cell|
 89:         if cell
 90:           cell.strip!
 91:           if quoted
 92:             cell.gsub!(/^"/, '')
 93:             cell.gsub!(/"$/, '')
 94:           end
 95: 
 96:           if index >= column_count
 97:             self.columns << Column.new
 98:           end
 99:           
100:           column = columns[index]
101:           if !column.fixed_size && (cell.size > column.size)
102:             column.size = cell.size
103:           end
104:         end
105: 
106:         index = index + 1
107:         cell
108:       end
109:       
110:       rows << Row.new(row, self)
111:     end
112:   end

[Source]

     # File lib/grid.rb, line 224
224:   def to_s(include_columns = true)
225:     unless truncated?
226:           truncate_rows
227:           end
228:           unless calculated_padding?
229:             calculate_padding
230:     end
231:   
232:     text = ""
233:     if include_columns && columns && columns.any?(&:present?)
234:       descriptions = columns.collect do |column|
235:         column.description
236:       end
237:       text = text + header_to_s(descriptions)
238:     end
239:     rows.each_with_index do |row, row_index|
240:       text = text + row_to_s(row, row_index)
241:     end
242:     text
243:   end

[Source]

     # File lib/grid.rb, line 285
285:   def truncate_rows
286:     @truncated = true
287:     for row in rows
288:       for index in 0..(column_count - 1)
289:         cell = row[index]
290:         if cell && cell.size > column_size(index)
291:           row[index] = truncate(cell, :length => column_size(index))
292:         end
293:       end
294:     end
295:   end

[Source]

     # File lib/grid.rb, line 315
315:   def truncated?
316:     @truncated
317:   end

[Source]

     # File lib/grid.rb, line 195
195:   def validate_columns
196:     return unless @row_class_instance
197:     
198:     columns.each do |column|
199:       if column.field.nil? || !(@row_class_instance.respond_to?("#{column.field}="))
200:         column.field = nil
201:         @custom_columns << column.name unless column.name.blank?
202:       end
203:     end
204:   end

[Validate]