Class: TrueTable

Inherits:
Array
  • Object
show all
Defined in:
lib/true_table.rb,
lib/true_table/version.rb

Constant Summary collapse

VERSION =
'0.2.5'

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.from_csv(csv_string, options = {}) ⇒ TrueTable

Loads a CSV string

Examples:

csv = "id,name\n1,Harry\n2,Lloyd"
table = TrueTable.load_csv csv, converters: [:date, :numeric]

Parameters:

  • csv_string (String)

    CSV string.

  • options (Hash) (defaults to: {})

    options to forward to the CSV class.

Returns:



15
16
17
18
19
20
21
# File 'lib/true_table.rb', line 15

def from_csv(csv_string, options = {})
  default_options = { headers: true, converters: :numeric, header_converters: :symbol }
  csv = CSV.new csv_string, **default_options.merge(options)
  new.tap do |table|
    csv.each { |row| table << row.to_h }
  end
end

.load_csv(path, options = {}) ⇒ TrueTable

Loads a CSV file

Examples:

table = TrueTable.from_csv "sample.csv", converters: [:date, :numeric]

Parameters:

  • path (String)

    the path to the CSV file.

  • options (Hash) (defaults to: {})

    options to forward to the CSV class.

Returns:



32
33
34
# File 'lib/true_table.rb', line 32

def load_csv(path, options = {})
  from_csv File.read(path), options
end

Instance Method Details

#+(other) ⇒ Object

Combines table with other and returns a new one



38
39
40
41
42
# File 'lib/true_table.rb', line 38

def +(other)
  result = self.class.new
  each_row { |row, i| result << row.merge(other[i]) }
  result
end

#-(other) ⇒ Object

Returns a new table without the specified columns



45
46
47
48
49
50
# File 'lib/true_table.rb', line 45

def -(other)
  keep_keys = headers - other
  result = self.class.new
  each_row { |row, _i| result << row.slice(*keep_keys) }
  result
end

#[](key) ⇒ Object

Returns a row or a column



53
54
55
56
57
58
59
# File 'lib/true_table.rb', line 53

def [](key)
  case key
  when Symbol then col(key)
  when Hash   then row(key)
  else super
  end
end

#[]=(key, value) ⇒ Object

Adds or updates a row or a column



62
63
64
65
66
67
68
# File 'lib/true_table.rb', line 62

def []=(key, value)
  case key
  when Symbol then add_col(key.to_sym, value)
  when Hash   then add_row(key, value)
  else super
  end
end

#cloneObject

Returns a deep copy of self



71
72
73
# File 'lib/true_table.rb', line 71

def clone
  self.class.new map(&:clone)
end

#col(key) ⇒ Object

Returns a column as Array



76
77
78
# File 'lib/true_table.rb', line 76

def col(key)
  map { |row| row[key] }
end

#colsObject

Returns a hash of columns



81
82
83
84
85
# File 'lib/true_table.rb', line 81

def cols
  result = {}
  each_col { |col, header| result[header] = col }
  result
end

#compactObject

Returns a copy of self without rows that contain nil in any column



88
89
90
# File 'lib/true_table.rb', line 88

def compact
  dup.compact!
end

#compact!Object

Removes rows with nil in any column



93
94
95
# File 'lib/true_table.rb', line 93

def compact!
  delete_if { |row| row.has_value?(nil) }
end

#delete_at(index) ⇒ Object Also known as: delete_col, delete_row

Delete a row or a column in place and returns the deleted row/column



98
99
100
101
102
103
104
105
106
107
108
# File 'lib/true_table.rb', line 98

def delete_at(index)
  if index.is_a?(Symbol) || index.is_a?(String)
    result = self[index]
    return nil unless result

    each_row { |row, _i| row.delete index }
    result
  else
    super
  end
end

#difference(*others) ⇒ Object

Returns a table with different rows



113
114
115
# File 'lib/true_table.rb', line 113

def difference(*others)
  self.class.new super
end

#dig(*indexes) ⇒ Object

Extracts nested value. Accepts row, column or column, row



118
119
120
121
122
123
124
125
# File 'lib/true_table.rb', line 118

def dig(*indexes)
  key = indexes.shift
  if key.is_a?(Symbol)
    col(key.to_sym).dig(*indexes)
  else
    row(key).dig(*indexes)
  end
end

#drop(*args) ⇒ Object

Returns a new table without the first N rows



128
129
130
# File 'lib/true_table.rb', line 128

def drop(*args)
  self.class.new super
end

#drop_while(*args) ⇒ Object

Returns a new table with rows until the block returns false



133
134
135
# File 'lib/true_table.rb', line 133

def drop_while(*args)
  self.class.new super
end

#each_colObject

Iterates over columns



138
139
140
# File 'lib/true_table.rb', line 138

def each_col
  headers.each { |header| yield col(header), header }
end

#fetch(key, *default) ⇒ Object

Returns a row or a column



146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
# File 'lib/true_table.rb', line 146

def fetch(key, *default)
  case key
  when Symbol
    if headers.include?(key) then col(key.to_sym)
    elsif default.any? then default.first
    elsif block_given? then yield key
    else
      raise IndexError, "col :#{key} does not exist"
    end

  when Hash
    result = row(key)
    if result then result
    elsif default.any? then default.first
    elsif block_given? then yield key
    else
      raise IndexError, "row #{key} does not exist"
    end

  else
    super

  end
end

#headersObject

Returns an array of column headers



172
173
174
# File 'lib/true_table.rb', line 172

def headers
  first.keys
end

#inspectObject

Returns a short inspection string



177
178
179
# File 'lib/true_table.rb', line 177

def inspect
  "<#{self.class}:#{object_id} size=#{size} headers=#{headers}>"
end

#intersection(*others) ⇒ Object

Returns a new table with intersecting rows



182
183
184
# File 'lib/true_table.rb', line 182

def intersection(*others)
  self.class.new super
end

#join(row_separator = $,, col_separator = nil, with_headers: false) ⇒ Object

Returns a string with joined rows and columns



187
188
189
190
191
192
193
194
# File 'lib/true_table.rb', line 187

def join(row_separator = $,, col_separator = nil, with_headers: false)
  if col_separator
    result = map { |row| row.values.join col_separator }.join(row_separator)
    with_headers ? headers.join(col_separator) + row_separator + result : result
  else
    super row_separator
  end
end

#last(*args) ⇒ Object

Returns the last row or a new table with the last N rows



197
198
199
# File 'lib/true_table.rb', line 197

def last(*args)
  args.empty? ? super : self.class.new(super)
end

#rejectObject

Returns a new table without rejected rows



202
203
204
# File 'lib/true_table.rb', line 202

def reject
  self.class.new super
end

#reverseObject

Returns a reversed copy



207
208
209
# File 'lib/true_table.rb', line 207

def reverse
  self.class.new super
end

#rotate(count = 1) ⇒ Object

Returns a new table with the element at ‘count` as the first element



212
213
214
# File 'lib/true_table.rb', line 212

def rotate(count = 1)
  self.class.new super
end

#row(key) ⇒ Object

Returns a row



217
218
219
# File 'lib/true_table.rb', line 217

def row(key)
  key.is_a?(Hash) ? find { |x| x[key.first.first] == key.first.last } : self[key]
end

#save_csv(path) ⇒ Object

Saves the table as a CSV file



225
226
227
# File 'lib/true_table.rb', line 225

def save_csv(path)
  File.write path, to_csv
end

#save_tsv(path) ⇒ Object

Saves the table as a TSV file



230
231
232
# File 'lib/true_table.rb', line 230

def save_tsv(path)
  File.write path, to_tsv
end

#selectObject Also known as: filter

Returns a new table with selected rows



235
236
237
# File 'lib/true_table.rb', line 235

def select
  self.class.new super
end

#shuffle(*args) ⇒ Object

Returns a new shuffled tables



241
242
243
# File 'lib/true_table.rb', line 241

def shuffle(*args)
  self.class.new super
end

#slice(*args) ⇒ Object

Returns a new table slice



246
247
248
249
250
251
252
# File 'lib/true_table.rb', line 246

def slice(*args)
  if (args.count == 1) && args.first.is_a?(Integer)
    super
  else
    self.class.new super
  end
end

#slice!(*args) ⇒ Object

Deletes and returns one more rows



255
256
257
258
259
260
261
# File 'lib/true_table.rb', line 255

def slice!(*args)
  if (args.count == 1) && args.first.is_a?(Integer)
    super
  else
    self.class.new super
  end
end

#sortObject

Returns a new sorted table



264
265
266
# File 'lib/true_table.rb', line 264

def sort
  self.class.new super
end

#sort_byObject

Returns a new sorted table



269
270
271
# File 'lib/true_table.rb', line 269

def sort_by
  self.class.new super
end

#take(*args) ⇒ Object

Returns a new table with the first N rows



274
275
276
# File 'lib/true_table.rb', line 274

def take(*args)
  self.class.new super
end

#take_while(*args) ⇒ Object

Returns a new table with rows until the block returns false



279
280
281
# File 'lib/true_table.rb', line 279

def take_while(*args)
  self.class.new super
end

#to_csv(row_separator = "\n", col_separator = ',') ⇒ Object

Returns a CSV string



284
285
286
# File 'lib/true_table.rb', line 284

def to_csv(row_separator = "\n", col_separator = ',')
  join(row_separator, col_separator, with_headers: true)
end

#to_hObject

Returns a hash representation of the table using the values of the first column as hash keys. If a block is given, the results of the block on each element of the array will be used as key => value pair.



296
297
298
299
300
301
302
# File 'lib/true_table.rb', line 296

def to_h
  if block_given?
    super
  else
    super { |row| [row.values.first, row] }
  end
end

#to_tsv(row_separator = "\n", col_separator = "\t") ⇒ Object

Returns a TSV string



289
290
291
# File 'lib/true_table.rb', line 289

def to_tsv(row_separator = "\n", col_separator = "\t")
  join(row_separator, col_separator, with_headers: true)
end

#valuesObject

Returns only values, without any headers (array of arrays)



305
306
307
# File 'lib/true_table.rb', line 305

def values
  map(&:values)
end