Class: CAFrame::CSVReader

Inherits:
Object
  • Object
show all
Defined in:
lib/carray/frame/csv_parser.rb

Overview

The block reading-control DSL for CAFrame.from_csv. A file often has preamble lines, a units row, or no header at all; the block says, in order, how to consume the stream:

CAFrame.from_csv(path) do
skip 3          # drop 3 preamble lines
header          # next record supplies the column names
skip 1          # drop a units row
body            # the rest are data rows
end

CAFrame.from_csv(path) do   # headerless file
column_names "date", "temp", "rh"
body
end

The verbs are skip / header / column_names / body; each returns a value useful inline (header returns its fields) and the ordering is the script. Without a block, from_csv runs the default header then body.

Instance Method Summary collapse

Constructor Details

#initialize(io, sep: ",", quote: '"', strip: false) ⇒ CSVReader

Returns a new instance of CSVReader.



168
169
170
171
172
173
# File 'lib/carray/frame/csv_parser.rb', line 168

def initialize(io, sep: ",", quote: '"', strip: false)
  @io    = io
  @tok   = CSVParser::Tokenizer.new(sep, quote, strip)
  @names = nil
  @rows  = nil
end

Instance Method Details

#body ⇒ Object

Consume the remaining records as data rows.



202
203
204
205
206
207
208
209
210
# File 'lib/carray/frame/csv_parser.rb', line 202

def body
  rows = []
  blank_is_row = @names && @names.size == 1
  while (fields = @tok.read(@io, blank_is_row: blank_is_row))
    rows << fields
  end
  @rows = rows
  self
end

#column_names(*names) ⇒ Object

Set the column names explicitly (headerless files).



196
197
198
199
# File 'lib/carray/frame/csv_parser.rb', line 196

def column_names(*names)
  @names = names.flatten.map(&:to_s)
  self
end

#header(name = nil) ⇒ Object

Read one record. With no argument it becomes the column names; with a name it is a secondary header (e.g. units) -- read, returned, not used as names. Returns the record's fields either way.



184
185
186
187
188
189
190
191
192
193
# File 'lib/carray/frame/csv_parser.rb', line 184

def header(name = nil)
  fields = @tok.read(@io)
  raise CSVParser::MalformedCSV, "header expected but input ended" if fields.nil?
  if name.nil?
    @names = fields.map(&:to_s)
  else
    (@named_headers ||= {})[name.to_s] = fields
  end
  fields
end

#result ⇒ Object

[names_or_nil, rows] for CAFrame.from_csv to build from. names is nil when neither header nor column_names ran (positional names are generated).



214
215
216
# File 'lib/carray/frame/csv_parser.rb', line 214

def result
  [@names, @rows || []]
end

#skip(n = 1) ⇒ Object

Drop n raw lines (preamble, units, notes).



176
177
178
179
# File 'lib/carray/frame/csv_parser.rb', line 176

def skip(n = 1)
  n.times { @io.gets }
  self
end