Class: VFCSV::Table

Inherits:
Object
  • Object
show all
Includes:
Enumerable
Defined in:
lib/vfcsv/table.rb

Overview

A CSV::Table-compatible class representing a collection of CSV rows. Supports multiple access modes: :row, :col, and :col_or_row (default).

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(rows = [], headers: nil) ⇒ Table

Create a new Table

Parameters:

  • rows (Array<Row>) (defaults to: [])

    Array of Row objects

  • headers (Array) (defaults to: nil)

    Column headers (optional, derived from first row if not provided)



14
15
16
17
18
# File 'lib/vfcsv/table.rb', line 14

def initialize(rows = [], headers: nil)
  @table = rows
  @headers = headers || (rows.first&.headers || [])
  @mode = :col_or_row
end

Instance Attribute Details

#modeObject (readonly)

Returns the value of attribute mode.



9
10
11
# File 'lib/vfcsv/table.rb', line 9

def mode
  @mode
end

#tableObject (readonly)

Returns the value of attribute table.



9
10
11
# File 'lib/vfcsv/table.rb', line 9

def table
  @table
end

Instance Method Details

#<<(row) ⇒ self Also known as: push

Append a row

Parameters:

  • row (Row, Array)

    Row to append

Returns:

  • (self)


65
66
67
68
69
70
71
72
# File 'lib/vfcsv/table.rb', line 65

def <<(row)
  if row.is_a?(Row)
    @table << row
  else
    @table << Row.new(@headers, row)
  end
  self
end

#==(other) ⇒ Boolean

Compare with another table

Parameters:

  • other (Table)

    Other table

Returns:

  • (Boolean)


183
184
185
186
# File 'lib/vfcsv/table.rb', line 183

def ==(other)
  return false unless other.is_a?(Table)
  @table == other.table && @headers == other.headers
end

#[](index_or_header) ⇒ Row, Array

Access rows or columns depending on mode

Parameters:

  • index_or_header (Integer, String)

    Row index or column header

Returns:

  • (Row, Array)

    Row object or array of column values



29
30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/vfcsv/table.rb', line 29

def [](index_or_header)
  case @mode
  when :row
    @table[index_or_header]
  when :col
    column_values(index_or_header)
  when :col_or_row
    if index_or_header.is_a?(Integer)
      @table[index_or_header]
    else
      column_values(index_or_header)
    end
  end
end

#[]=(index_or_header, value) ⇒ Object

Set row or column value depending on mode

Parameters:

  • index_or_header (Integer, String)

    Row index or column header

  • value (Row, Array)

    New row or column values



47
48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/vfcsv/table.rb', line 47

def []=(index_or_header, value)
  case @mode
  when :row
    @table[index_or_header] = value
  when :col
    set_column(index_or_header, value)
  when :col_or_row
    if index_or_header.is_a?(Integer)
      @table[index_or_header] = value
    else
      set_column(index_or_header, value)
    end
  end
end

#by_colTable

Switch to column access mode (returns new table with mode set)

Returns:



156
157
158
# File 'lib/vfcsv/table.rb', line 156

def by_col
  dup_with_mode(:col)
end

#by_col!self

Switch to column access mode (mutates self)

Returns:

  • (self)


162
163
164
165
# File 'lib/vfcsv/table.rb', line 162

def by_col!
  @mode = :col
  self
end

#by_col_or_rowTable

Switch to column-or-row access mode (returns new table with mode set)

Returns:



169
170
171
# File 'lib/vfcsv/table.rb', line 169

def by_col_or_row
  dup_with_mode(:col_or_row)
end

#by_col_or_row!self

Switch to column-or-row access mode (mutates self)

Returns:

  • (self)


175
176
177
178
# File 'lib/vfcsv/table.rb', line 175

def by_col_or_row!
  @mode = :col_or_row
  self
end

#by_rowTable

Switch to row access mode (returns new table with mode set)

Returns:



143
144
145
# File 'lib/vfcsv/table.rb', line 143

def by_row
  dup_with_mode(:row)
end

#by_row!self

Switch to row access mode (mutates self)

Returns:

  • (self)


149
150
151
152
# File 'lib/vfcsv/table.rb', line 149

def by_row!
  @mode = :row
  self
end

#delete(index_or_header) ⇒ Row, ...

Delete a row or column

Parameters:

  • index_or_header (Integer, String)

    Row index or column header

Returns:

  • (Row, Array, nil)

    Deleted row or column values



78
79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/vfcsv/table.rb', line 78

def delete(index_or_header)
  case @mode
  when :row
    @table.delete_at(index_or_header)
  when :col
    delete_column(index_or_header)
  when :col_or_row
    if index_or_header.is_a?(Integer)
      @table.delete_at(index_or_header)
    else
      delete_column(index_or_header)
    end
  end
end

#delete_if {|row_or_col| ... } ⇒ self

Delete rows/columns matching condition

Yields:

  • (row_or_col)

    Block that returns true for items to delete

Returns:

  • (self)


96
97
98
99
# File 'lib/vfcsv/table.rb', line 96

def delete_if(&block)
  @table.delete_if(&block)
  self
end

#dig(index, *args) ⇒ Object

Dig into nested data

Parameters:

  • index (Integer)

    Row index

  • args (Array)

    Additional keys

Returns:

  • (Object)


127
128
129
130
131
132
# File 'lib/vfcsv/table.rb', line 127

def dig(index, *args)
  row = @table[index]
  return nil if row.nil?
  return row if args.empty?
  row.dig(*args)
end

#each {|Row| ... } ⇒ Enumerator

Iterate over rows

Yields:

Returns:

  • (Enumerator)

    if no block given



104
105
106
107
108
# File 'lib/vfcsv/table.rb', line 104

def each(&block)
  return to_enum(__method__) unless block_given?
  @table.each(&block)
  self
end

#empty?Boolean

Check if table is empty

Returns:

  • (Boolean)


112
113
114
# File 'lib/vfcsv/table.rb', line 112

def empty?
  @table.empty?
end

#headersArray

Get column headers

Returns:

  • (Array)


22
23
24
# File 'lib/vfcsv/table.rb', line 22

def headers
  @headers.dup
end

#inspectString

Inspection string

Returns:

  • (String)


220
221
222
# File 'lib/vfcsv/table.rb', line 220

def inspect
  "#<#{self.class} mode:#{@mode} row_count:#{size}>"
end

#sizeInteger Also known as: length

Get number of rows

Returns:

  • (Integer)


118
119
120
# File 'lib/vfcsv/table.rb', line 118

def size
  @table.size
end

#to_aArray<Array>

Convert to array (includes headers as first row)

Returns:

  • (Array<Array>)


190
191
192
# File 'lib/vfcsv/table.rb', line 190

def to_a
  [@headers] + @table.map(&:fields)
end

#to_csv(**options) ⇒ String Also known as: to_s

Convert to CSV string

Parameters:

  • options (Hash)

    CSV options

Returns:

  • (String)


197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
# File 'lib/vfcsv/table.rb', line 197

def to_csv(**options)
  write_headers = options.fetch(:write_headers, true)
  col_sep = options[:col_sep] || ","
  quote_char = options[:quote_char] || '"'
  row_sep = options[:row_sep]
  row_sep = "\n" if row_sep.nil? || row_sep == :auto

  result = +""

  if write_headers
    result << generate_line(@headers, col_sep, quote_char, row_sep)
  end

  @table.each do |row|
    result << generate_line(row.fields, col_sep, quote_char, row_sep)
  end

  result
end

#values_at(*indices) ⇒ Array<Row>

Get rows at specified indices

Parameters:

  • indices (Array<Integer>)

    Row indices

Returns:



137
138
139
# File 'lib/vfcsv/table.rb', line 137

def values_at(*indices)
  indices.map { |i| @table[i] }
end