Class: CSV
Relationships & Source Files | |
Namespace Children | |
Modules:
| |
Classes:
| |
Exceptions:
| |
Super Chains via Extension / Inclusion / Inheritance | |
Class Chain:
self,
Forwardable
|
|
Instance Chain:
self,
Enumerable
|
|
Inherits: | Object |
Defined in: | lib/csv.rb, lib/csv/fields_converter.rb, lib/csv/input_record_separator.rb, lib/csv/parser.rb, lib/csv/row.rb, lib/csv/table.rb, lib/csv/version.rb, lib/csv/writer.rb |
Overview
CSV Data
CSV (comma-separated values) data is a text representation of a table:
-
A row separator delimits table rows. A common row separator is the newline character
"\n"
. -
A column separator delimits fields in a row. A common column separator is the comma character
","
.
This CSV String, with row separator "\n"
and column separator ","
, has three rows and two columns:
"foo,0\nbar,1\nbaz,2\n"
Despite the name CSV, a CSV representation can use different separators.
For more about tables, see the Wikipedia article “) {CSV::Table (information)}”, especially its section “Simple table”
Class CSV
Class CSV provides methods for:
-
Parsing CSV data from a String object, a File (via its file path), or an IO object.
-
Generating CSV data to a String object.
To make CSV available:
require 'csv'
All examples here assume that this has been done.
Keeping It Simple
A CSV object has dozens of instance methods that offer fine-grained control of parsing and generating CSV data. For many needs, though, simpler approaches will do.
This section summarizes the singleton methods in CSV that allow you to parse and generate without explicitly creating CSV objects. For details, follow the links.
Simple Parsing
Parsing methods commonly return either of:
-
An Array of Arrays of Strings:
-
The outer Array is the entire “table”.
-
Each inner Array is a row.
-
Each String is a field.
-
-
A
Table
object. For details, see \ with Headers.
Parsing a String
The input to be parsed can be a string:
string = "foo,0\nbar,1\nbaz,2\n"
Method .parse returns the entire CSV data:
CSV.parse(string) # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
Method .parse_line returns only the first row:
CSV.parse_line(string) # => ["foo", "0"]
CSV extends class String with instance method String#parse_csv, which also returns only the first row:
string.parse_csv # => ["foo", "0"]
Parsing Via a File Path
The input to be parsed can be in a file:
string = "foo,0\nbar,1\nbaz,2\n"
path = 't.csv'
File.write(path, string)
Method .read returns the entire CSV data:
CSV.read(path) # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
Method .foreach iterates, passing each row to the given block:
CSV.foreach(path) do |row|
p row
end
Output:
["foo", "0"]
["bar", "1"]
["baz", "2"]
Method .table returns the entire CSV data as a Table
object:
CSV.table(path) # => #<CSV::Table mode:col_or_row row_count:3>
Parsing from an Open IO Stream
The input to be parsed can be in an open IO stream:
Method .read returns the entire CSV data:
File.open(path) do |file|
CSV.read(file)
end # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
As does method .parse:
File.open(path) do |file|
CSV.parse(file)
end # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
Method .parse_line returns only the first row:
File.open(path) do |file|
CSV.parse_line(file)
end # => ["foo", "0"]
Method .foreach iterates, passing each row to the given block:
File.open(path) do |file|
CSV.foreach(file) do |row|
p row
end
end
Output:
["foo", "0"]
["bar", "1"]
["baz", "2"]
Method .table returns the entire CSV data as a Table
object:
File.open(path) do |file|
CSV.table(file)
end # => #<CSV::Table mode:col_or_row row_count:3>
Simple Generating
Method .generate returns a String; this example uses method #<< to append the rows that are to be generated:
output_string = CSV.generate do |csv|
csv << ['foo', 0]
csv << ['bar', 1]
csv << ['baz', 2]
end
output_string # => "foo,0\nbar,1\nbaz,2\n"
Method .generate_line returns a String containing the single row constructed from an Array:
CSV.generate_line(['foo', '0']) # => "foo,0\n"
CSV extends class Array with instance method Array#to_csv, which forms an Array into a String:
['foo', '0'].to_csv # => "foo,0\n"
“Filtering” CSV
Method .filter provides a Unix-style filter for CSV data. The input data is processed to form the output data:
in_string = "foo,0\nbar,1\nbaz,2\n"
out_string = ''
CSV.filter(in_string, out_string) do |row|
row[0] = row[0].upcase
row[1] *= 4
end
out_string # => "FOO,0000\nBAR,1111\nBAZ,2222\n"
CSV Objects
There are three ways to create a CSV object:
-
Method .new returns a new CSV object.
-
Method .instance returns a new or cached CSV object.
-
Method CSV() also returns a new or cached CSV object.
Instance Methods
CSV has three groups of instance methods:
-
Its own internally defined instance methods.
-
Methods included by module Enumerable.
-
Methods delegated to class IO. See below.
Delegated Methods
For convenience, a CSV
object will delegate to many methods in class IO. (A few have wrapper “guard code” in CSV.) You may call:
-
IO#binmode
-
IO#close
-
IO#close_read
-
IO#close_write
-
IO#closed?
-
IO#external_encoding
-
IO#fcntl
-
IO#fileno
-
IO#flush
-
IO#fsync
-
IO#internal_encoding
-
IO#isatty
-
IO#pid
-
IO#pos
-
IO#pos=
-
IO#reopen
-
IO#seek
-
IO#string
-
IO#sync
-
IO#sync=
-
IO#tell
-
IO#truncate
-
IO#tty?
Options
The default values for options are:
DEFAULT_OPTIONS = {
# For both parsing and generating.
col_sep: ",",
row_sep: :auto,
quote_char: '"',
# For parsing.
field_size_limit: nil,
converters: nil,
unconverted_fields: nil,
headers: false,
return_headers: false,
header_converters: nil,
skip_blanks: false,
skip_lines: nil,
liberal_parsing: false,
nil_value: nil,
empty_value: "",
strip: false,
# For generating.
write_headers: nil,
quote_empty: true,
force_quotes: false,
write_converters: nil,
write_nil_value: nil,
write_empty_value: "",
}
Options for Parsing
Options for parsing, described in detail below, include:
-
#row_sep: Specifies the row separator; used to delimit rows.
-
#col_sep: Specifies the column separator; used to delimit fields.
-
#quote_char: Specifies the quote character; used to quote fields.
-
#field_size_limit: Specifies the maximum field size + 1 allowed. Deprecated since 3.2.3. Use #max_field_size instead.
-
#max_field_size: Specifies the maximum field size allowed.
-
#converters: Specifies the field converters to be used.
-
unconverted_fields
: Specifies whether unconverted fields are to be available. -
#headers: Specifies whether data contains headers, or specifies the headers themselves.
-
return_headers
: Specifies whether headers are to be returned. -
#header_converters: Specifies the header converters to be used.
-
skip_blanks
: Specifies whether blanks lines are to be ignored. -
#skip_lines: Specifies how comments lines are to be recognized.
-
strip
: Specifies whether leading and trailing whitespace are to be stripped from fields. This must be compatible withcol_sep
; if it is not, then anArgumentError
exception will be raised. -
liberal_parsing
: Specifies whether CSV should attempt to parse non-compliant data. -
nil_value
: Specifies the object that is to be substituted for each null (no-text) field. -
empty_value
: Specifies the object that is to be substituted for each empty field.
Options for Generating
Options for generating, described in detail below, include:
-
#row_sep: Specifies the row separator; used to delimit rows.
-
#col_sep: Specifies the column separator; used to delimit fields.
-
#quote_char: Specifies the quote character; used to quote fields.
-
write_headers
: Specifies whether headers are to be written. -
force_quotes
: Specifies whether each output field is to be quoted. -
quote_empty
: Specifies whether each empty output field is to be quoted. -
write_converters
: Specifies the field converters to be used in writing. -
write_nil_value
: Specifies the object that is to be substituted for eachnil
-valued field. -
write_empty_value
: Specifies the object that is to be substituted for each empty field.
CSV with Headers
CSV
allows to specify column names of CSV
file, whether they are in data, or provided separately. If headers are specified, reading methods return an instance of Table
, consisting of Row
.
# Headers are part of data
data = CSV.parse(<<~ROWS, headers: true)
Name,Department,Salary
Bob,Engineering,1000
Jane,Sales,2000
John,Management,5000
ROWS
data.class #=> CSV::Table
data.first #=> #<CSV::Row "Name":"Bob" "Department":"Engineering" "Salary":"1000">
data.first.to_h #=> {"Name"=>"Bob", "Department"=>"Engineering", "Salary"=>"1000"}
# Headers provided by developer
data = CSV.parse('Bob,Engineering,1000', headers: %i[name department salary])
data.first #=> #<CSV::Row name:"Bob" department:"Engineering" salary:"1000">
Converters
By default, each value (field or header) parsed by CSV is formed into a String. You can use a field converter or header converter to intercept and modify the parsed values:
-
See Field Converters.
-
See Header Converters.
Also by default, each value to be written during generation is written ‘as-is’. You can use a write converter to modify values before writing.
-
See Write Converters.
Specifying Converters
You can specify converters for parsing or generating in the options
argument to various CSV methods:
-
Option #converters for converting parsed field values.
-
Option #header_converters for converting parsed header values.
-
Option
write_converters
for converting values to be written (generated).
There are three forms for specifying converters:
-
A converter proc: executable code to be used for conversion.
-
A converter name: the name of a stored converter.
-
A converter list: an array of converter procs, converter names, and converter lists.
Converter Procs
This converter proc, strip_converter
, accepts a value field
and returns field.strip
:
strip_converter = proc {|field| field.strip }
In this call to .parse, the keyword argument converters: string_converter
specifies that:
-
Proc
string_converter
is to be called for each parsed field. -
The converter’s return value is to replace the
field
value.
Example:
string = " foo , 0 \n bar , 1 \n baz , 2 \n"
array = CSV.parse(string, converters: strip_converter)
array # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
A converter proc can receive a second argument, field_info
, that contains details about the field. This modified strip_converter
displays its arguments:
strip_converter = proc do |field, field_info|
p [field, field_info]
field.strip
end
string = " foo , 0 \n bar , 1 \n baz , 2 \n"
array = CSV.parse(string, converters: strip_converter)
array # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
Output:
[" foo ", #<struct CSV::FieldInfo index=0, line=1, header=nil>]
[" 0 ", #<struct CSV::FieldInfo index=1, line=1, header=nil>]
[" bar ", #<struct CSV::FieldInfo index=0, line=2, header=nil>]
[" 1 ", #<struct CSV::FieldInfo index=1, line=2, header=nil>]
[" baz ", #<struct CSV::FieldInfo index=0, line=3, header=nil>]
[" 2 ", #<struct CSV::FieldInfo index=1, line=3, header=nil>]
Each FieldInfo
object shows:
-
The 0-based field index.
-
The 1-based line index.
-
The field header, if any.
Stored Converters
A converter may be given a name and stored in a structure where the parsing methods can find it by name.
The storage structure for field converters is the Hash Converters. It has several built-in converter procs:
-
:integer
: converts each String-embedded integer into a true Integer. -
:float
: converts each String-embedded float into a true Float. -
:date
: converts each String-embedded date into a true Date. -
:date_time
: converts each String-embedded date-time into a true DateTime
. This example creates a converter proc, then stores it:
strip_converter = proc {|field| field.strip }
CSV::Converters[:strip] = strip_converter
Then the parsing method call can refer to the converter by its name, :strip
:
string = " foo , 0 \n bar , 1 \n baz , 2 \n"
array = CSV.parse(string, converters: :strip)
array # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
The storage structure for header converters is the Hash HeaderConverters, which works in the same way. It also has built-in converter procs:
-
:downcase
: Downcases each header. -
:symbol
: Converts each header to a Symbol.
There is no such storage structure for write headers.
In order for the parsing methods to access stored converters in non-main-Ractors, the storage structure must be made shareable first. Therefore, Ractor.make_shareable(CSV::Converters)
and Ractor.make_shareable(CSV::HeaderConverters)
must be called before the creation of Ractors that use the converters stored in these structures. (Since making the storage structures shareable involves freezing them, any custom converters that are to be used must be added first.)
Converter Lists
A converter list is an Array that may include any assortment of:
-
Converter procs.
-
Names of stored converters.
-
Nested converter lists.
Examples:
numeric_converters = [:integer, :float]
date_converters = [:date, :date_time]
[numeric_converters, strip_converter]
[strip_converter, date_converters, :float]
Like a converter proc, a converter list may be named and stored in either CSV::Converters or HeaderConverters:
CSV::Converters[:custom] = [strip_converter, date_converters, :float]
CSV::HeaderConverters[:custom] = [:downcase, :symbol]
There are two built-in converter lists:
CSV::Converters[:numeric] # => [:integer, :float]
CSV::Converters[:all] # => [:date_time, :numeric]
Field Converters
With no conversion, all parsed fields in all rows become Strings:
string = "foo,0\nbar,1\nbaz,2\n"
ary = CSV.parse(string)
ary # => # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
When you specify a field converter, each parsed field is passed to the converter; its return value becomes the stored value for the field. A converter might, for example, convert an integer embedded in a String into a true Integer. (In fact, that’s what built-in field converter :integer
does.)
There are three ways to use field converters.
-
Using option converters with a parsing method:
ary = CSV.parse(string, converters: :integer) ary # => [0, 1, 2] # => [["foo", 0], ["bar", 1], ["baz", 2]]
-
Using option converters with a new CSV instance:
csv = CSV.new(string, converters: :integer) # Field converters in effect: csv.converters # => [:integer] csv.read # => [["foo", 0], ["bar", 1], ["baz", 2]]
-
Using method #convert to add a field converter to a CSV instance:
csv = CSV.new(string) # Add a converter. csv.convert(:integer) csv.converters # => [:integer] csv.read # => [["foo", 0], ["bar", 1], ["baz", 2]]
Installing a field converter does not affect already-read rows:
csv = CSV.new(string)
csv.shift # => ["foo", "0"]
# Add a converter.
csv.convert(:integer)
csv.converters # => [:integer]
csv.read # => [["bar", 1], ["baz", 2]]
There are additional built-in converters, and custom converters are also supported.
Built-In Field Converters
The built-in field converters are in Hash Converters:
-
Each key is a field converter name.
-
Each value is one of:
-
A Proc field converter.
-
An Array of field converter names.
-
Display:
CSV::Converters.each_pair do |name, value|
if value.kind_of?(Proc)
p [name, value.class]
else
p [name, value]
end
end
Output:
[:integer, Proc]
[:float, Proc]
[:numeric, [:integer, :float]]
[:date, Proc]
[:date_time, Proc]
[:all, [:date_time, :numeric]]
Each of these converters transcodes values to UTF-8 before attempting conversion. If a value cannot be transcoded to UTF-8 the conversion will fail and the value will remain unconverted.
Converter :integer
converts each field that Integer() accepts:
data = '0,1,2,x'
# Without the converter
csv = CSV.parse_line(data)
csv # => ["0", "1", "2", "x"]
# With the converter
csv = CSV.parse_line(data, converters: :integer)
csv # => [0, 1, 2, "x"]
Converter :float
converts each field that Float() accepts:
data = '1.0,3.14159,x'
# Without the converter
csv = CSV.parse_line(data)
csv # => ["1.0", "3.14159", "x"]
# With the converter
csv = CSV.parse_line(data, converters: :float)
csv # => [1.0, 3.14159, "x"]
Converter :numeric
converts with both :integer
and :float
..
Converter :date
converts each field that Date.parse
accepts:
data = '2001-02-03,x'
# Without the converter
csv = CSV.parse_line(data)
csv # => ["2001-02-03", "x"]
# With the converter
csv = CSV.parse_line(data, converters: :date)
csv # => [#<Date: 2001-02-03 ((2451944j,0s,0n),+0s,2299161j)>, "x"]
Converter :date_time
converts each field that DateTime.parse
accepts:
data = '2020-05-07T14:59:00-05:00,x'
# Without the converter
csv = CSV.parse_line(data)
csv # => ["2020-05-07T14:59:00-05:00", "x"]
# With the converter
csv = CSV.parse_line(data, converters: :date_time)
csv # => [#<DateTime: 2020-05-07T14:59:00-05:00 ((2458977j,71940s,0n),-18000s,2299161j)>, "x"]
Converter :numeric
converts with both :date_time
and :numeric
..
As seen above, method #convert adds converters to a CSV instance, and method #converters returns an Array of the converters in effect:
csv = CSV.new('0,1,2')
csv.converters # => []
csv.convert(:integer)
csv.converters # => [:integer]
csv.convert(:date)
csv.converters # => [:integer, :date]
Custom Field Converters
You can define a custom field converter:
strip_converter = proc {|field| field.strip }
string = " foo , 0 \n bar , 1 \n baz , 2 \n"
array = CSV.parse(string, converters: strip_converter)
array # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
You can register the converter in Converters Hash, which allows you to refer to it by name:
CSV::Converters[:strip] = strip_converter
string = " foo , 0 \n bar , 1 \n baz , 2 \n"
array = CSV.parse(string, converters: :strip)
array # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
Header Converters
Header converters operate only on headers (and not on other rows).
There are three ways to use header converters; these examples use built-in header converter :downcase
, which downcases each parsed header.
-
Option #header_converters with a singleton parsing method:
string = "Name,Count\nFoo,0\n,Bar,1\nBaz,2" tbl = CSV.parse(string, headers: true, header_converters: :downcase) tbl.class # => CSV::Table tbl.headers # => ["name", "count"]
-
Option #header_converters with a new CSV instance:
csv = CSV.new(string, header_converters: :downcase) # Header converters in effect: csv.header_converters # => [:downcase] tbl = CSV.parse(string, headers: true) tbl.headers # => ["Name", "Count"]
-
Method #header_convert adds a header converter to a CSV instance:
csv = CSV.new(string) # Add a header converter. csv.header_convert(:downcase) csv.header_converters # => [:downcase] tbl = CSV.parse(string, headers: true) tbl.headers # => ["Name", "Count"]
Built-In Header Converters
The built-in header converters are in Hash HeaderConverters. The keys there are the names of the converters:
CSV::HeaderConverters.keys # => [:downcase, :symbol]
Converter :downcase
converts each header by downcasing it:
string = "Name,Count\nFoo,0\n,Bar,1\nBaz,2"
tbl = CSV.parse(string, headers: true, header_converters: :downcase)
tbl.class # => CSV::Table
tbl.headers # => ["name", "count"]
Converter :symbol
converts each header by making it into a Symbol:
string = "Name,Count\nFoo,0\n,Bar,1\nBaz,2"
tbl = CSV.parse(string, headers: true, header_converters: :symbol)
tbl.headers # => [:name, :count]
Details:
-
Strips leading and trailing whitespace.
-
Downcases the header.
-
Replaces embedded spaces with underscores.
-
Removes non-word characters.
-
Makes the string into a Symbol.
Custom Header Converters
You can define a custom header converter:
upcase_converter = proc {|header| header.upcase }
string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
table = CSV.parse(string, headers: true, header_converters: upcase_converter)
table # => #<CSV::Table mode:col_or_row row_count:4>
table.headers # => ["NAME", "VALUE"]
You can register the converter in HeaderConverters Hash, which allows you to refer to it by name:
CSV::HeaderConverters[:upcase] = upcase_converter
table = CSV.parse(string, headers: true, header_converters: :upcase)
table # => #<CSV::Table mode:col_or_row row_count:4>
table.headers # => ["NAME", "VALUE"]
Write Converters
When you specify a write converter for generating CSV, each field to be written is passed to the converter; its return value becomes the new value for the field. A converter might, for example, strip whitespace from a field.
Using no write converter (all fields unmodified):
output_string = CSV.generate do |csv|
csv << [' foo ', 0]
csv << [' bar ', 1]
csv << [' baz ', 2]
end
output_string # => " foo ,0\n bar ,1\n baz ,2\n"
Using option write_converters
with two custom write converters:
strip_converter = proc {|field| field.respond_to?(:strip) ? field.strip : field }
upcase_converter = proc {|field| field.respond_to?(:upcase) ? field.upcase : field }
write_converters = [strip_converter, upcase_converter]
output_string = CSV.generate(write_converters: write_converters) do |csv|
csv << [' foo ', 0]
csv << [' bar ', 1]
csv << [' baz ', 2]
end
output_string # => "FOO,0\nBAR,1\nBAZ,2\n"
Character Encodings (M17n or Multilingualization)
This new CSV
parser is m17n savvy. The parser works in the Encoding of the IO or ::String
object being read from or written to. Your data is never transcoded (unless you ask Ruby to transcode it for you) and will literally be parsed in the Encoding it is in. Thus CSV will return Arrays or Rows of Strings in the Encoding of your data. This is accomplished by transcoding the parser itself into your Encoding.
Some transcoding must take place, of course, to accomplish this multiencoding support. For example, :col_sep
, :row_sep
, and :quote_char
must be transcoded to match your data. Hopefully this makes the entire process feel transparent, since CSV’s defaults should just magically work for your data. However, you can set these values manually in the target Encoding to avoid the translation.
It’s also important to note that while all of CSV’s core parser is now Encoding agnostic, some features are not. For example, the built-in converters will try to transcode data to UTF-8 before making conversions. Again, you can provide custom converters that are aware of your Encodings to avoid this translation. It’s just too hard for me to support native conversions in all of Ruby’s Encodings.
Anyway, the practical side of this is simple: make sure IO and ::String
objects passed into CSV
have the proper Encoding set and everything should just work. CSV
methods that allow you to open IO objects (CSV::foreach(), .open(), .read(), and .readlines()) do allow you to specify the Encoding.
One minor exception comes when generating CSV
into a ::String
with an Encoding that is not ASCII compatible. There’s no existing data for CSV
to use to prepare itself and thus you will probably need to manually specify the desired Encoding for most of those cases. It will try to guess using the fields in a row of output though, when using .generate_line() or Array#to_csv().
I try to point out any other Encoding issues in the documentation of methods as they come up.
This has been tested to the best of my ability with all non-“dummy” Encodings Ruby ships with. However, it is brave new code and may have some bugs. Please feel free to report any issues you find with it.
Constant Summary
-
ConverterEncoding =
The encoding used by all converters.
Encoding.find("UTF-8")
-
Converters =
A Hash containing the names and Procs for the built-in field converters. See Built-In Field Converters.
This Hash is intentionally left unfrozen, and may be extended with custom field converters. See Custom Field Converters.
{ integer: lambda { |f| Integer(f.encode(ConverterEncoding)) rescue f }, float: lambda { |f| Float(f.encode(ConverterEncoding)) rescue f }, numeric: [:integer, :float], date: lambda { |f| begin e = f.encode(ConverterEncoding) e.match?(DateMatcher) ? Date.parse(e) : f rescue # encoding conversion or date parse errors f end }, date_time: lambda { |f| begin e = f.encode(ConverterEncoding) e.match?(DateTimeMatcher) ? DateTime.parse(e) : f rescue # encoding conversion or date parse errors f end }, all: [:date_time, :numeric], }
-
DEFAULT_OPTIONS =
Default values for method options.
{ # For both parsing and generating. col_sep: ",", row_sep: :auto, quote_char: '"', # For parsing. field_size_limit: nil, max_field_size: nil, converters: nil, unconverted_fields: nil, headers: false, return_headers: false, header_converters: nil, skip_blanks: false, skip_lines: nil, liberal_parsing: false, nil_value: nil, empty_value: "", strip: false, # For generating. write_headers: nil, quote_empty: true, force_quotes: false, write_converters: nil, write_nil_value: nil, write_empty_value: "", }.freeze
-
DateMatcher =
A Regexp used to find and convert some common Date formats.
/ \A(?: (\w,?\s)?\w\s\d{1,2},?\s+\d{2,4} | \d{4}-\d{2}-\d{2} )\z /x
-
DateTimeMatcher =
A Regexp used to find and convert some common DateTime formats.
/ \A(?: (\w,?\s)?\w\s\d{1,2}\s\d{1,2}:\d{1,2}:\d{1,2},?\s\d{2,4} | # ISO-8601 and RFC-3339 (space instead of T) recognized by DateTime.parse \d{4}-\d{2}-\d{2} (?:[T\s]\d{2}:\d{2}(?::\d{2}(?:\.\d)?(?:[-]\d{2}(?::\d{2})|Z)?)?)? )\z /x
-
HeaderConverters =
A Hash containing the names and Procs for the built-in header converters. See Built-In Header Converters.
This Hash is intentionally left unfrozen, and may be extended with custom field converters. See Custom Header Converters.
{ downcase: lambda { |h| h.encode(ConverterEncoding).downcase }, symbol: lambda { |h| h.encode(ConverterEncoding).downcase.gsub(/[^\s\w]+/, "").strip. gsub(/\s+/, "_").to_sym }, symbol_raw: lambda { |h| h.encode(ConverterEncoding).to_sym } }
-
VERSION =
The version of the installed library.
"3.2.8"
Class Method Summary
-
.filter(in_string_or_io, **options) {|row| ... } ⇒ array_of_arrays, CSV
Parses CSV from a source (String, IO stream, or ARGF).
-
.foreach(path_or_io, mode='r', **options) {|row| ... )
Calls the block with each row read from source
path_or_io
. -
.generate(csv_string, **options) {|csv| ... }
Argument
csv_string
, if given, must be a String object;.
-
.generate_line(ary)
Returns the String created by generating CSV from
ary
using the specifiedoptions
. -
.generate_lines(rows)
Returns the String created by generating CSV from using the specified
options
. -
.instance(string, **options)
Creates or retrieves cached CSV objects.
-
.new(string) ⇒ CSV
constructor
Returns the new CSV object created using
string
orio
and the specifiedoptions
. -
.open(file_path, mode = "rb", **options) ⇒ CSV
possible options elements:
-
.parse(string) ⇒ array_of_arrays
Parses
string
orio
using the specifiedoptions
. -
.parse_line(string) ⇒ Array?
Returns the data created by parsing the first line of
string
orio
using the specifiedoptions
. - .read(source, **options) ⇒ array_of_arrays
-
.readlines(source, **options)
Alias for .read.
-
.table(source, **options)
Calls .read with
source
,options
, and certain default options: - #headers:true
- #converters::numeric
- #header_converters::symbol
Instance Attribute Summary
- #binmode? ⇒ Boolean readonly
-
#encoding ⇒ Encoding
readonly
Returns the encoding used for parsing and generating; see Character Encodings (M17n or Multilingualization):
-
#eof
readonly
Alias for #eof?.
-
#force_quotes? ⇒ Boolean
readonly
Returns the value that determines whether all output fields are to be quoted; used for generating; see Option
force_quotes
: -
#header_row? ⇒ Boolean
readonly
Returns
true
if the next row to be read is a header row;false
otherwise. -
#liberal_parsing? ⇒ Boolean
readonly
Returns the value that determines whether illegal input is to be handled; used for parsing; see Option
liberal_parsing
: -
#return_headers? ⇒ Boolean
readonly
Returns the value that determines whether headers are to be returned; used for parsing; see Option
return_headers
: -
#skip_blanks? ⇒ Boolean
readonly
Returns the value that determines whether blank lines are to be ignored; used for parsing; see Option
skip_blanks
: -
#unconverted_fields? ⇒ Boolean
readonly
Returns the value that determines whether unconverted fields are to be available; used for parsing; see Option
unconverted_fields
: -
#write_headers? ⇒ Boolean
readonly
Returns the value that determines whether headers are to be written; used for generating; see Option
write_headers
:
Instance Method Summary
-
#<<(row) ⇒ self
(also: #add_row, #puts)
Appends a row to
self
. -
#add_row(row)
Alias for #<<.
-
#col_sep ⇒ String
Returns the encoded column separator; used for parsing and writing; see Option
col_sep
: -
#convert(converter_name) ⇒ array_of_procs
With no block, installs a field converter (a Proc).
-
#converters ⇒ Array
Returns an Array containing field converters; see Field Converters:
-
#each ⇒ Enumerator
Calls the block with each successive row.
- #eof? ⇒ Boolean (also: #eof) readonly
-
#field_size_limit ⇒ Integer?
Returns the limit for field size; used for parsing; see Option
field_size_limit
: - #flock(*args)
-
#gets
Alias for #shift.
-
#header_convert(name = nil, &converter)
The block need not return a String object:
-
#header_converters ⇒ Array
Returns an Array containing header converters; used for parsing; see Header Converters:
-
#headers ⇒ Object
Returns the value that determines whether headers are used; used for parsing; see Option
headers
: -
#inspect ⇒ String
Returns a String showing certain properties of
self
: - #ioctl(*args)
-
#line ⇒ Array
Returns the line most recently read:
-
#line_no ⇒ Integer
Returns the count of the rows parsed or generated.
-
#max_field_size ⇒ Integer?
Returns the limit for field size; used for parsing; see Option
max_field_size
: - #path
-
#puts(row)
Alias for #<<.
-
#quote_char ⇒ character
Returns the encoded quote character; used for parsing and writing; see Option
quote_char
: -
#read ⇒ Array, CSV
(also: #readlines)
Forms the remaining rows from
self
into: - ATable
object, if headers are in use. -
#readline
Alias for #shift.
-
#readlines
Alias for #read.
-
#rewind
Rewinds the underlying IO object and resets CSV’s lineno() counter.
-
#row_sep ⇒ String
Returns the encoded row separator; used for parsing and writing; see Option
row_sep
: -
#shift ⇒ Array, ...
(also: #gets, #readline)
Returns the next row of data as: - An Array if no headers are used.
-
#skip_lines ⇒ Regexp?
Returns the Regexp used to identify comment lines; used for parsing; see Option
skip_lines
: - #stat(*args)
- #to_i
- #to_io
- #build_fields_converter(initial_converters, options) private
- #build_header_fields_converter private
- #build_parser_fields_converter private
- #build_writer_fields_converter private
-
#convert_fields(fields, headers = false)
private
Processes
fields
with@converters
, or@header_converters
if #headers is passed astrue
, returning the converted field set. - #determine_encoding(encoding, internal_encoding) private
- #header_fields_converter private
- #normalize_converters(converters) private
- #parser private
- #parser_enumerator private
- #parser_fields_converter private
- #parser_options private
-
#raw_encoding
private
Returns the encoding of the internal IO object.
- #writer private
- #writer_fields_converter private
- #writer_options private
Constructor Details
.new(string) ⇒ CSV
.new(io) ⇒ CSV
.new(string, **options) ⇒ CSV
.new(io, **options) ⇒ CSV
CSV
.new(io) ⇒ CSV
.new(string, **options) ⇒ CSV
.new(io, **options) ⇒ CSV
Returns the new CSV object created using string
or io
and the specified options
.
-
Argument
string
should be a String object; it will be put into a new StringIO object positioned at the beginning.
-
Argument
options
: See:For performance reasons, the options cannot be overridden in a CSV object, so those specified here will endure.
In addition to the CSV instance methods, several IO methods are delegated. See Delegated Methods.
Create a CSV object from a String object:
csv = CSV.new('foo,0')
csv # => #<CSV io_type:StringIO encoding:UTF-8 lineno:0 col_sep:"," row_sep:"\n" quote_char:"\"">
Create a CSV object from a File object:
File.write('t.csv', 'foo,0')
csv = CSV.new(File.open('t.csv'))
csv # => #<CSV io_type:File io_path:"t.csv" encoding:UTF-8 lineno:0 col_sep:"," row_sep:"\n" quote_char:"\"">
Raises an exception if the argument is nil
:
# Raises ArgumentError (Cannot parse nil as CSV):
CSV.new(nil)
# File 'lib/csv.rb', line 1905
def initialize(data, col_sep: ",", row_sep: :auto, quote_char: '"', field_size_limit: nil, max_field_size: nil, converters: nil, unconverted_fields: nil, headers: false, return_headers: false, write_headers: nil, header_converters: nil, skip_blanks: false, force_quotes: false, skip_lines: nil, liberal_parsing: false, internal_encoding: nil, external_encoding: nil, encoding: nil, nil_value: nil, empty_value: "", strip: false, quote_empty: true, write_converters: nil, write_nil_value: nil, write_empty_value: "") raise ArgumentError.new("Cannot parse nil as CSV") if data.nil? if data.is_a?(String) if encoding if encoding.is_a?(String) data_external_encoding, data_internal_encoding = encoding.split(":", 2) if data_internal_encoding data = data.encode(data_internal_encoding, data_external_encoding) else data = data.dup.force_encoding(data_external_encoding) end else data = data.dup.force_encoding(encoding) end end @io = StringIO.new(data) else @io = data end @encoding = determine_encoding(encoding, internal_encoding) @base_fields_converter_options = { nil_value: nil_value, empty_value: empty_value, } @write_fields_converter_options = { nil_value: write_nil_value, empty_value: write_empty_value, } @initial_converters = converters @initial_header_converters = header_converters @initial_write_converters = write_converters if max_field_size.nil? and field_size_limit max_field_size = field_size_limit - 1 end @parser_options = { column_separator: col_sep, row_separator: row_sep, quote_character: quote_char, max_field_size: max_field_size, unconverted_fields: unconverted_fields, headers: headers, return_headers: return_headers, skip_blanks: skip_blanks, skip_lines: skip_lines, liberal_parsing: liberal_parsing, encoding: @encoding, nil_value: nil_value, empty_value: empty_value, strip: strip, } @parser = nil @parser_enumerator = nil @eof_error = nil @writer_options = { encoding: @encoding, force_encoding: (not encoding.nil?), force_quotes: force_quotes, headers: headers, write_headers: write_headers, column_separator: col_sep, row_separator: row_sep, quote_character: quote_char, quote_empty: quote_empty, } @writer = nil writer if @writer_options[:write_headers] end
Class Method Details
.filter(in_string_or_io, **options) {|row| ... } ⇒ array_of_arrays
, CSV
.filter(in_string_or_io, out_string_or_io, **options) {|row| ... } ⇒ array_of_arrays
, CSV
.filter(**options) {|row| ... } ⇒ array_of_arrays
, CSV
array_of_arrays
, CSV
.filter(in_string_or_io, out_string_or_io, **options) {|row| ... } ⇒ array_of_arrays
, CSV
.filter(**options) {|row| ... } ⇒ array_of_arrays
, CSV
-
Parses CSV from a source (String, IO stream, or ARGF).
-
Calls the given block with each parsed row:
-
Without headers, each row is an Array.
-
With headers, each row is a CSV::Row.
-
-
Generates CSV to an output (String, IO stream, or STDOUT).
-
Returns the parsed source:
-
Without headers, an Array of Arrays.
-
With headers, a CSV::Table.
-
When in_string_or_io
is given, but not out_string_or_io
, parses from the given in_string_or_io
and generates to STDOUT.
String input without headers:
in_string = "foo,0\nbar,1\nbaz,2"
CSV.filter(in_string) do |row|
row[0].upcase!
row[1] = - row[1].to_i
end # => [["FOO", 0], ["BAR", -1], ["BAZ", -2]]
Output (to STDOUT):
FOO,0
BAR,-1
BAZ,-2
String input with headers:
in_string = "Name,Value\nfoo,0\nbar,1\nbaz,2"
CSV.filter(in_string, headers: true) do |row|
row[0].upcase!
row[1] = - row[1].to_i
end # => #<CSV::Table mode:col_or_row row_count:4>
Output (to STDOUT):
Name,Value
FOO,0
BAR,-1
BAZ,-2
IO stream input without headers:
File.write('t.csv', "foo,0\nbar,1\nbaz,2")
File.open('t.csv') do |in_io|
CSV.filter(in_io) do |row|
row[0].upcase!
row[1] = - row[1].to_i
end
end # => [["FOO", 0], ["BAR", -1], ["BAZ", -2]]
Output (to STDOUT):
FOO,0
BAR,-1
BAZ,-2
IO stream input with headers:
File.write('t.csv', "Name,Value\nfoo,0\nbar,1\nbaz,2")
File.open('t.csv') do |in_io|
CSV.filter(in_io, headers: true) do |row|
row[0].upcase!
row[1] = - row[1].to_i
end
end # => #<CSV::Table mode:col_or_row row_count:4>
Output (to STDOUT):
Name,Value
FOO,0
BAR,-1
BAZ,-2
When both in_string_or_io
and out_string_or_io
are given, parses from in_string_or_io
and generates to out_string_or_io
.
String output without headers:
in_string = "foo,0\nbar,1\nbaz,2"
out_string = ''
CSV.filter(in_string, out_string) do |row|
row[0].upcase!
row[1] = - row[1].to_i
end # => [["FOO", 0], ["BAR", -1], ["BAZ", -2]]
out_string # => "FOO,0\nBAR,-1\nBAZ,-2\n"
String output with headers:
in_string = "Name,Value\nfoo,0\nbar,1\nbaz,2"
out_string = ''
CSV.filter(in_string, out_string, headers: true) do |row|
row[0].upcase!
row[1] = - row[1].to_i
end # => #<CSV::Table mode:col_or_row row_count:4>
out_string # => "Name,Value\nFOO,0\nBAR,-1\nBAZ,-2\n"
IO stream output without headers:
in_string = "foo,0\nbar,1\nbaz,2"
File.open('t.csv', 'w') do |out_io|
CSV.filter(in_string, out_io) do |row|
row[0].upcase!
row[1] = - row[1].to_i
end
end # => [["FOO", 0], ["BAR", -1], ["BAZ", -2]]
File.read('t.csv') # => "FOO,0\nBAR,-1\nBAZ,-2\n"
IO stream output with headers:
in_string = "Name,Value\nfoo,0\nbar,1\nbaz,2"
File.open('t.csv', 'w') do |out_io|
CSV.filter(in_string, out_io, headers: true) do |row|
row[0].upcase!
row[1] = - row[1].to_i
end
end # => #<CSV::Table mode:col_or_row row_count:4>
File.read('t.csv') # => "Name,Value\nFOO,0\nBAR,-1\nBAZ,-2\n"
When neither in_string_or_io
nor out_string_or_io
given, parses from ARGF
and generates to STDOUT.
Without headers:
# Put Ruby code into a file.
ruby = <<-EOT
require 'csv'
CSV.filter do |row|
row[0].upcase!
row[1] = - row[1].to_i
end
EOT
File.write('t.rb', ruby)
# Put some CSV into a file.
File.write('t.csv', "foo,0\nbar,1\nbaz,2")
# Run the Ruby code with CSV filename as argument.
system(Gem.ruby, "t.rb", "t.csv")
Output (to STDOUT):
FOO,0
BAR,-1
BAZ,-2
With headers:
# Put Ruby code into a file.
ruby = <<-EOT
require 'csv'
CSV.filter(headers: true) do |row|
row[0].upcase!
row[1] = - row[1].to_i
end
EOT
File.write('t.rb', ruby)
# Put some CSV into a file.
File.write('t.csv', "Name,Value\nfoo,0\nbar,1\nbaz,2")
# Run the Ruby code with CSV filename as argument.
system(Gem.ruby, "t.rb", "t.csv")
Output (to STDOUT):
Name,Value
FOO,0
BAR,-1
BAZ,-2
Arguments:
-
Argument
in_string_or_io
must be a String or an IO stream. -
Argument
out_string_or_io
must be a String or an IO stream. -
Arguments
**options
must be keyword options. See Options for Parsing.
# File 'lib/csv.rb', line 1202
def filter(input=nil, output=nil, ** ) # parse options for input, output, or both , = Hash.new, {row_sep: InputRecordSeparator.value} .each do |key, value| case key when /\Ain(?:put)?_(.+)\Z/ [$1.to_sym] = value when /\Aout(?:put)?_(.+)\Z/ [$1.to_sym] = value else [key] = value [key] = value end end # build input and output wrappers input = new(input || ARGF, ** ) output = new(output || $stdout, ** ) # process headers need_manual_header_output = ( [:headers] and [:headers] == true and [:write_headers]) if need_manual_header_output first_row = input.shift if first_row if first_row.is_a?(Row) headers = first_row.headers yield headers output << headers end yield first_row output << first_row end end # read, yield, write input.each do |row| yield row output << row end end
.foreach(path_or_io, mode='r', **options) {|row| ... )
.foreach(path_or_io, mode = 'r', **options) ⇒ Enumerator
Enumerator
Calls the block with each row read from source path_or_io
.
Path input without headers:
string = "foo,0\nbar,1\nbaz,2\n"
in_path = 't.csv'
File.write(in_path, string)
CSV.foreach(in_path) {|row| p row }
Output:
["foo", "0"]
["bar", "1"]
["baz", "2"]
Path input with headers:
string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
in_path = 't.csv'
File.write(in_path, string)
CSV.foreach(in_path, headers: true) {|row| p row }
Output:
<CSV::Row "Name":"foo" "Value":"0">
<CSV::Row "Name":"bar" "Value":"1">
<CSV::Row "Name":"baz" "Value":"2">
IO stream input without headers:
string = "foo,0\nbar,1\nbaz,2\n"
path = 't.csv'
File.write(path, string)
File.open('t.csv') do |in_io|
CSV.foreach(in_io) {|row| p row }
end
Output:
["foo", "0"]
["bar", "1"]
["baz", "2"]
IO stream input with headers:
string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
path = 't.csv'
File.write(path, string)
File.open('t.csv') do |in_io|
CSV.foreach(in_io, headers: true) {|row| p row }
end
Output:
<CSV::Row "Name":"foo" "Value":"0">
<CSV::Row "Name":"bar" "Value":"1">
<CSV::Row "Name":"baz" "Value":"2">
With no block given, returns an Enumerator:
string = "foo,0\nbar,1\nbaz,2\n"
path = 't.csv'
File.write(path, string)
CSV.foreach(path) # => #<Enumerator: CSV:foreach("t.csv", "r")>
Arguments:
-
Argument
path_or_io
must be a file path or an IO stream. -
Argument
mode
, if given, must be a File mode. SeeAccess Modes
. -
Arguments
**options
must be keyword options. See Options for Parsing. -
This method optionally accepts an additional
:encoding
option that you can use to specify the Encoding of the data read from #path orio
. You must provide this unless your data is in the encoding given byEncoding.default_external
. Parsing will use this to determine how to parse the data. You may provide a second Encoding to have the data transcoded as it is read. For example,encoding: 'UTF-32BE:UTF-8'
would read
UTF-32BE
data from the file but transcode it toUTF-8
before parsing.
.generate(csv_string, **options) {|csv| ... }
.generate(**options) {|csv| ... }
-
Argument
csv_string
, if given, must be a String object; defaults to a new empty String. -
Arguments
options
, if given, should be generating options. See Options for Generating.
Creates a new CSV object via CSV.new(csv_string, **options)
; calls the block with the CSV object, which the block may modify; returns the String generated from the CSV object.
Note that a passed String is modified by this method. Pass csv_string
.dup if the String must be preserved.
This method has one additional option: :encoding
, which sets the base Encoding for the output if no no str
is specified. CSV
needs this hint if you plan to output non-ASCII compatible data.
Add lines:
input_string = "foo,0\nbar,1\nbaz,2\n"
output_string = CSV.generate(input_string) do |csv|
csv << ['bat', 3]
csv << ['bam', 4]
end
output_string # => "foo,0\nbar,1\nbaz,2\nbat,3\nbam,4\n"
input_string # => "foo,0\nbar,1\nbaz,2\nbat,3\nbam,4\n"
output_string.equal?(input_string) # => true # Same string, modified
Add lines into new string, preserving old string:
input_string = "foo,0\nbar,1\nbaz,2\n"
output_string = CSV.generate(input_string.dup) do |csv|
csv << ['bat', 3]
csv << ['bam', 4]
end
output_string # => "foo,0\nbar,1\nbaz,2\nbat,3\nbam,4\n"
input_string # => "foo,0\nbar,1\nbaz,2\n"
output_string.equal?(input_string) # => false # Different strings
Create lines from nothing:
output_string = CSV.generate do |csv|
csv << ['foo', 0]
csv << ['bar', 1]
csv << ['baz', 2]
end
output_string # => "foo,0\nbar,1\nbaz,2\n"
Raises an exception if csv_string
is not a String object:
# Raises TypeError (no implicit conversion of Integer into String)
CSV.generate(0)
# File 'lib/csv.rb', line 1398
def generate(str=nil, ** ) encoding = [:encoding] # add a default empty String, if none was given if str str = StringIO.new(str) str.seek(0, IO::SEEK_END) str.set_encoding(encoding) if encoding else str = +"" str.force_encoding(encoding) if encoding end csv = new(str, ** ) # wrap yield csv # yield for appending csv.string # return final String end
.generate_line(ary)
.generate_line(ary, **options)
Returns the String created by generating CSV from ary
using the specified options
.
Argument ary
must be an Array.
Special options:
-
Option
:row_sep
defaults to"\n"> on Ruby 3.0 or later and <tt>$INPUT_RECORD_SEPARATOR
($/
) otherwise.:$INPUT_RECORD_SEPARATOR # => "\n"
-
This method accepts an additional option,
:encoding
, which sets the base Encoding for the output. This method will try to guess your Encoding from the first non-nil
field inrow
, if possible, but you may need to use this parameter as a backup plan.
For other options
, see Options for Generating.
Returns the String generated from an Array:
CSV.generate_line(['foo', '0']) # => "foo,0\n"
Raises an exception if ary
is not an Array:
# Raises NoMethodError (undefined method `find' for :foo:Symbol)
CSV.generate_line(:foo)
# File 'lib/csv.rb', line 1446
def generate_line(row, ** ) = {row_sep: InputRecordSeparator.value}.merge( ) str = +"" if [:encoding] str.force_encoding( [:encoding]) else fallback_encoding = nil output_encoding = nil row.each do |field| next unless field.is_a?(String) fallback_encoding ||= field.encoding next if field.ascii_only? output_encoding = field.encoding break end output_encoding ||= fallback_encoding if output_encoding str.force_encoding(output_encoding) end end (new(str, ** ) << row).string end
.generate_lines(rows)
.generate_lines(rows, **options)
Returns the String created by generating CSV from using the specified options
.
Argument rows
must be an Array of row. ::CSV::Row
is Array of String or CSV::Row.
Special options:
-
Option
:row_sep
defaults to"\n"
on Ruby 3.0 or later and$INPUT_RECORD_SEPARATOR
($/
) otherwise.:$INPUT_RECORD_SEPARATOR # => "\n"
-
This method accepts an additional option,
:encoding
, which sets the base Encoding for the output. This method will try to guess your Encoding from the first non-nil
field inrow
, if possible, but you may need to use this parameter as a backup plan.
For other options
, see Options for Generating.
Returns the String generated from an
CSV.generate_lines([['foo', '0'], ['bar', '1'], ['baz', '2']]) # => "foo,0\nbar,1\nbaz,2\n"
Raises an exception
# Raises NoMethodError (undefined method `each' for :foo:Symbol)
CSV.generate_lines(:foo)
.instance(string, **options)
.instance(io = $stdout, **options)
.instance(string, **options) {|csv| ... }
.instance(io = $stdout, **options) {|csv| ... }
Creates or retrieves cached CSV objects. For arguments and options, see .new.
This API is not Ractor-safe.
With no block given, returns a CSV object.
The first call to instance
creates and caches a CSV object:
s0 = 's0'
csv0 = CSV.instance(s0)
csv0.class # => CSV
Subsequent calls to instance
with that same string
or io
retrieve that same cached object:
csv1 = CSV.instance(s0)
csv1.class # => CSV
csv1.equal?(csv0) # => true # Same CSV object
A subsequent call to instance
with a different string
or io
creates and caches a different CSV object.
s1 = 's1'
csv2 = CSV.instance(s1)
csv2.equal?(csv0) # => false # Different CSV object
All the cached objects remains available:
csv3 = CSV.instance(s0)
csv3.equal?(csv0) # true # Same CSV object
csv4 = CSV.instance(s1)
csv4.equal?(csv2) # true # Same CSV object
When a block is given, calls the block with the created or retrieved CSV object; returns the block’s return value:
CSV.instance(s0) {|csv| :foo } # => :foo
# File 'lib/csv.rb', line 1006
def instance(data = $stdout, ** ) # create a _signature_ for this method call, data object and options sig = [data.object_id] + .values_at(*DEFAULT_OPTIONS.keys) # fetch or create the instance for this signature @@instances ||= Hash.new instance = (@@instances[sig] ||= new(data, ** )) if block_given? yield instance # run block, if given, returning result else instance # or return the instance end end
.open(file_path, mode = "rb", **options) ⇒ CSV
.open(io, mode = "rb", **options) ⇒ CSV
.open(file_path, mode = "rb", **options) {|csv| ... } ⇒ Object
.open(io, mode = "rb", **options) {|csv| ... } ⇒ Object
CSV
.open(io, mode = "rb", **options) ⇒ CSV
.open(file_path, mode = "rb", **options) {|csv| ... } ⇒ Object
.open(io, mode = "rb", **options) {|csv| ... } ⇒ Object
possible options elements:
keyword form:
:invalid => nil # raise error on invalid byte sequence (default)
:invalid => :replace # replace invalid byte sequence
:undef => :replace # replace undefined conversion
:replace => string # replacement string ("?" or "\uFFFD" if not specified)
-
Argument #path, if given, must be the path to a file.
-
Argument
mode
, if given, must be a File mode. SeeAccess Modes
. -
Arguments
**options
must be keyword options. See Options for Generating. -
This method optionally accepts an additional
:encoding
option that you can use to specify the Encoding of the data read from #path orio
. You must provide this unless your data is in the encoding given byEncoding.default_external
. Parsing will use this to determine how to parse the data. You may provide a second Encoding to have the data transcoded as it is read. For example,encoding: 'UTF-32BE:UTF-8'
would read
UTF-32BE
data from the file but transcode it toUTF-8
before parsing.
These examples assume prior execution of:
string = "foo,0\nbar,1\nbaz,2\n"
path = 't.csv'
File.write(path, string)
With no block given, returns a new CSV object.
Create a CSV object using a file path:
csv = CSV.open(path)
csv # => #<CSV io_type:File io_path:"t.csv" encoding:UTF-8 lineno:0 col_sep:"," row_sep:"\n" quote_char:"\"">
Create a CSV object using an open File:
csv = CSV.open(File.open(path))
csv # => #<CSV io_type:File io_path:"t.csv" encoding:UTF-8 lineno:0 col_sep:"," row_sep:"\n" quote_char:"\"">
With a block given, calls the block with the created CSV object; returns the block’s return value:
Using a file path:
csv = CSV.open(path) {|csv| p csv}
csv # => #<CSV io_type:File io_path:"t.csv" encoding:UTF-8 lineno:0 col_sep:"," row_sep:"\n" quote_char:"\"">
Output:
#<CSV io_type:File io_path:"t.csv" encoding:UTF-8 lineno:0 col_sep:"," row_sep:"\n" quote_char:"\"">
Using an open File:
csv = CSV.open(File.open(path)) {|csv| p csv}
csv # => #<CSV io_type:File io_path:"t.csv" encoding:UTF-8 lineno:0 col_sep:"," row_sep:"\n" quote_char:"\"">
Output:
#<CSV io_type:File io_path:"t.csv" encoding:UTF-8 lineno:0 col_sep:"," row_sep:"\n" quote_char:"\"">
Raises an exception if the argument is not a String object or IO object:
# Raises TypeError (no implicit conversion of Symbol into String)
CSV.open(:foo)
# File 'lib/csv.rb', line 1581
def open(filename, mode="r", ** ) # wrap a File opened with the remaining args with no newline # decorator file_opts = .dup unless file_opts.key?(:newline) file_opts[:universal_newline] ||= false end .delete(:invalid) .delete(:undef) .delete(:replace) .delete_if {|k, _| /newline\z/.match?(k)} begin f = File.open(filename, mode, **file_opts) rescue ArgumentError => e raise unless /needs binmode/.match?(e. ) and mode == "r" mode = "rb" file_opts = {encoding: Encoding.default_external}.merge(file_opts) retry end begin csv = new(f, ** ) rescue Exception f.close raise end # handle blocks like Ruby's open(), not like the CSV library if block_given? begin yield csv ensure csv.close end else csv end end
.parse(string) ⇒ array_of_arrays
.parse(io) ⇒ array_of_arrays
.parse(string, headers: ..., **options) ⇒ CSV
.parse(io, headers: ..., **options) ⇒ CSV
.parse(string, **options) {|row| ... }
.parse(io, **options) {|row| ... }
array_of_arrays
.parse(io) ⇒ array_of_arrays
.parse(string, headers: ..., **options) ⇒ CSV
.parse(io, headers: ..., **options) ⇒ CSV
.parse(string, **options) {|row| ... }
.parse(io, **options) {|row| ... }
Parses string
or io
using the specified options
.
-
Argument
string
should be a String object; it will be put into a new StringIO object positioned at the beginning.
-
Argument
options
: see Options for Parsing
Without Option #headers
These examples assume prior execution of:
string = "foo,0\nbar,1\nbaz,2\n"
path = 't.csv'
File.write(path, string)
With no block given, returns an Array of Arrays formed from the source.
Parse a String:
a_of_a = CSV.parse(string)
a_of_a # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
Parse an open File:
a_of_a = File.open(path) do |file|
CSV.parse(file)
end
a_of_a # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
With a block given, calls the block with each parsed row:
Parse a String:
CSV.parse(string) {|row| p row }
Output:
["foo", "0"]
["bar", "1"]
["baz", "2"]
Parse an open File:
File.open(path) do |file|
CSV.parse(file) {|row| p row }
end
Output:
["foo", "0"]
["bar", "1"]
["baz", "2"]
With Option #headers
These examples assume prior execution of:
string = "Name,Count\nfoo,0\nbar,1\nbaz,2\n"
path = 't.csv'
File.write(path, string)
With no block given, returns a ::CSV::Table
object formed from the source.
Parse a String:
csv_table = CSV.parse(string, headers: ['Name', 'Count'])
csv_table # => #<CSV::Table mode:col_or_row row_count:5>
Parse an open File:
csv_table = File.open(path) do |file|
CSV.parse(file, headers: ['Name', 'Count'])
end
csv_table # => #<CSV::Table mode:col_or_row row_count:4>
With a block given, calls the block with each parsed row, which has been formed into a ::CSV::Row
object:
Parse a String:
CSV.parse(string, headers: ['Name', 'Count']) {|row| p row }
Output:
# <CSV::Row "Name":"foo" "Count":"0">
# <CSV::Row "Name":"bar" "Count":"1">
# <CSV::Row "Name":"baz" "Count":"2">
Parse an open File:
File.open(path) do |file|
CSV.parse(file, headers: ['Name', 'Count']) {|row| p row }
end
Output:
# <CSV::Row "Name":"foo" "Count":"0">
# <CSV::Row "Name":"bar" "Count":"1">
# <CSV::Row "Name":"baz" "Count":"2">
Raises an exception if the argument is not a String object or IO object:
# Raises NoMethodError (undefined method `close' for :foo:Symbol)
CSV.parse(:foo)
Returns the data created by parsing the first line of string
or io
using the specified options
.
-
Argument
string
should be a String object; it will be put into a new StringIO object positioned at the beginning.
-
Argument
options
: see Options for Parsing
Without Option #headers
Without option #headers, returns the first row as a new Array.
These examples assume prior execution of:
string = "foo,0\nbar,1\nbaz,2\n"
path = 't.csv'
File.write(path, string)
Parse the first line from a String object:
CSV.parse_line(string) # => ["foo", "0"]
Parse the first line from a File object:
File.open(path) do |file|
CSV.parse_line(file) # => ["foo", "0"]
end # => ["foo", "0"]
Returns nil
if the argument is an empty String:
CSV.parse_line('') # => nil
With Option #headers
With option #headers, returns the first row as a ::CSV::Row
object.
These examples assume prior execution of:
string = "Name,Count\nfoo,0\nbar,1\nbaz,2\n"
path = 't.csv'
File.write(path, string)
Parse the first line from a String object:
CSV.parse_line(string, headers: true) # => #<CSV::Row "Name":"foo" "Count":"0">
Parse the first line from a File object:
File.open(path) do |file|
CSV.parse_line(file, headers: true)
end # => #<CSV::Row "Name":"foo" "Count":"0">
Raises an exception if the argument is nil
:
# Raises ArgumentError (Cannot parse nil as CSV):
CSV.parse_line(nil)
.read(source, **options) ⇒ array_of_arrays
.read(source, headers: true, **options) ⇒ CSV
array_of_arrays
.read(source, headers: true, **options) ⇒ CSV
Opens the given source
with the given options
(see .open), reads the source (see #read), and returns the result, which will be either an Array of Arrays or a ::CSV::Table
.
Without headers:
string = "foo,0\nbar,1\nbaz,2\n"
path = 't.csv'
File.write(path, string)
CSV.read(path) # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
With headers:
string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
path = 't.csv'
File.write(path, string)
CSV.read(path, headers: true) # => #<CSV::Table mode:col_or_row row_count:4>
.readlines(source, **options)
Alias for .read.
.table(source, **options)
Calls .read with source
, options
, and certain default options:
-
#headers:
true
-
#converters:
:numeric
-
#header_converters:
:symbol
Returns a ::CSV::Table
object.
Example:
string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
path = 't.csv'
File.write(path, string)
CSV.table(path) # => #<CSV::Table mode:col_or_row row_count:4>
Instance Attribute Details
#binmode? ⇒ Boolean
(readonly)
[ GitHub ]
# File 'lib/csv.rb', line 2261
def binmode? if @io.respond_to?(:binmode?) @io.binmode? else false end end
#encoding ⇒ Encoding
(readonly)
Returns the encoding used for parsing and generating; see Character Encodings (M17n or Multilingualization):
CSV.new('').encoding # => #<Encoding:UTF-8>
# File 'lib/csv.rb', line 2192
attr_reader :encoding
#eof (readonly)
Alias for #eof?.
# File 'lib/csv.rb', line 2309
alias_method :eof, :eof?
#force_quotes? ⇒ Boolean
(readonly)
Returns the value that determines whether all output fields are to be quoted; used for generating; see Option force_quotes
:
CSV.new('').force_quotes? # => false
# File 'lib/csv.rb', line 2172
def force_quotes? @writer_options[:force_quotes] end
#header_row? ⇒ Boolean
(readonly)
Returns true
if the next row to be read is a header row; false
otherwise.
Without headers:
string = "foo,0\nbar,1\nbaz,2\n"
csv = CSV.new(string)
csv.header_row? # => false
With headers:
string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
csv = CSV.new(string, headers: true)
csv.header_row? # => true
csv.shift # => #<CSV::Row "Name":"foo" "Value":"0">
csv.header_row? # => false
Raises an exception if the source is not opened for reading:
string = "foo,0\nbar,1\nbaz,2\n"
csv = CSV.new(string)
csv.close
# Raises IOError (not opened for reading)
csv.header_row?
# File 'lib/csv.rb', line 2631
def header_row? parser.header_row? end
#liberal_parsing? ⇒ Boolean
(readonly)
Returns the value that determines whether illegal input is to be handled; used for parsing; see Option liberal_parsing
:
CSV.new('').liberal_parsing? # => false
# File 'lib/csv.rb', line 2182
def liberal_parsing? parser.liberal_parsing? end
#return_headers? ⇒ Boolean
(readonly)
Returns the value that determines whether headers are to be returned; used for parsing; see Option return_headers
:
CSV.new('').return_headers? # => false
# File 'lib/csv.rb', line 2124
def return_headers? parser.return_headers? end
#skip_blanks? ⇒ Boolean
(readonly)
Returns the value that determines whether blank lines are to be ignored; used for parsing; see Option skip_blanks
:
CSV.new('').skip_blanks? # => false
# File 'lib/csv.rb', line 2161
def skip_blanks? parser.skip_blanks? end
#unconverted_fields? ⇒ Boolean
(readonly)
Returns the value that determines whether unconverted fields are to be available; used for parsing; see Option unconverted_fields
:
CSV.new('').unconverted_fields? # => nil
# File 'lib/csv.rb', line 2096
def unconverted_fields? parser.unconverted_fields? end
#write_headers? ⇒ Boolean
(readonly)
Returns the value that determines whether headers are to be written; used for generating; see Option write_headers
:
CSV.new('').write_headers? # => nil
# File 'lib/csv.rb', line 2134
def write_headers? @writer_options[:write_headers] end
Instance Method Details
#<<(row) ⇒ self
Also known as: #add_row, #puts
Appends a row to self
.
-
Argument
row
must be an Array object or a::CSV::Row
object. -
The output stream must be open for writing.
Append Arrays:
CSV.generate do |csv|
csv << ['foo', 0]
csv << ['bar', 1]
csv << ['baz', 2]
end # => "foo,0\nbar,1\nbaz,2\n"
Append CSV::Rows
:
headers = []
CSV.generate do |csv|
csv << CSV::Row.new(headers, ['foo', 0])
csv << CSV::Row.new(headers, ['bar', 1])
csv << CSV::Row.new(headers, ['baz', 2])
end # => "foo,0\nbar,1\nbaz,2\n"
Headers in ::CSV::Row
objects are not appended:
headers = ['Name', 'Count']
CSV.generate do |csv|
csv << CSV::Row.new(headers, ['foo', 0])
csv << CSV::Row.new(headers, ['bar', 1])
csv << CSV::Row.new(headers, ['baz', 2])
end # => "foo,0\nbar,1\nbaz,2\n"
Raises an exception if row
is not an Array or CSV::Row:
CSV.generate do |csv|
# Raises NoMethodError (undefined method `collect' for :foo:Symbol)
csv << :foo
end
Raises an exception if the output stream is not opened for writing:
path = 't.csv'
File.write(path, '')
File.open(path) do |file|
CSV.open(file) do |csv|
# Raises IOError (not opened for writing)
csv << ['foo', 0]
end
end
# File 'lib/csv.rb', line 2372
def <<(row) writer << row self end
#add_row(row)
Alias for #<<.
# File 'lib/csv.rb', line 2376
alias_method :add_row, :<<
#build_fields_converter(initial_converters, options) (private)
[ GitHub ]# File 'lib/csv.rb', line 2822
def build_fields_converter(initial_converters, ) fields_converter = FieldsConverter.new( ) normalize_converters(initial_converters).each do |name, converter| fields_converter.add_converter(name, &converter) end fields_converter end
#build_header_fields_converter (private)
[ GitHub ]# File 'lib/csv.rb', line 2804
def build_header_fields_converter = { builtin_converters_name: :HeaderConverters, accept_nil: true, } = @base_fields_converter_options.merge( ) build_fields_converter(@initial_header_converters, ) end
#build_parser_fields_converter (private)
[ GitHub ]# File 'lib/csv.rb', line 2792
def build_parser_fields_converter = { builtin_converters_name: :Converters, } = @base_fields_converter_options.merge( ) build_fields_converter(@initial_converters, ) end
#build_writer_fields_converter (private)
[ GitHub ]# File 'lib/csv.rb', line 2817
def build_writer_fields_converter build_fields_converter(@initial_write_converters, @write_fields_converter_options) end
#col_sep ⇒ String
Returns the encoded column separator; used for parsing and writing; see Option col_sep
:
CSV.new('').col_sep # => ","
# File 'lib/csv.rb', line 2009
def col_sep parser.column_separator end
#convert(converter_name) ⇒ array_of_procs
#convert {|field, field_info| ... } ⇒ array_of_procs
array_of_procs
#convert {|field, field_info| ... } ⇒ array_of_procs
-
With no block, installs a field converter (a Proc).
-
With a block, defines and installs a custom field converter.
-
Returns the Array of installed field converters.
-
Argument
converter_name
, if given, should be the name of an existing field converter.
See Field Converters.
With no block, installs a field converter:
csv = CSV.new('')
csv.convert(:integer)
csv.convert(:float)
csv.convert(:date)
csv.converters # => [:integer, :float, :date]
The block, if given, is called for each field:
-
Argument
field
is the field value. -
Argument
field_info
is a::CSV::FieldInfo
object containing details about the field.
The examples here assume the prior execution of:
string = "foo,0\nbar,1\nbaz,2\n"
path = 't.csv'
File.write(path, string)
Example giving a block:
csv = CSV.open(path)
csv.convert {|field, field_info| p [field, field_info]; field.upcase }
csv.read # => [["FOO", "0"], ["BAR", "1"], ["BAZ", "2"]]
Output:
["foo", #<struct CSV::FieldInfo index=0, line=1, header=nil>]
["0", #<struct CSV::FieldInfo index=1, line=1, header=nil>]
["bar", #<struct CSV::FieldInfo index=0, line=2, header=nil>]
["1", #<struct CSV::FieldInfo index=1, line=2, header=nil>]
["baz", #<struct CSV::FieldInfo index=0, line=3, header=nil>]
["2", #<struct CSV::FieldInfo index=1, line=3, header=nil>]
The block need not return a String object:
csv = CSV.open(path)
csv.convert {|field, field_info| field.to_sym }
csv.read # => [[:foo, :"0"], [:bar, :"1"], [:baz, :"2"]]
If converter_name
is given, the block is not called:
csv = CSV.open(path)
csv.convert(:integer) {|field, field_info| fail 'Cannot happen' }
csv.read # => [["foo", 0], ["bar", 1], ["baz", 2]]
Raises a parse-time exception if converter_name
is not the name of a built-in field converter:
csv = CSV.open(path)
csv.convert(:nosuch) => [nil]
# Raises NoMethodError (undefined method `arity' for nil:NilClass)
csv.read
# File 'lib/csv.rb', line 2443
def convert(name = nil, &converter) parser_fields_converter.add_converter(name, &converter) end
#convert_fields(fields, headers = false) (private)
# File 'lib/csv.rb', line 2767
def convert_fields(fields, headers = false) if headers header_fields_converter.convert(fields, nil, 0) else parser_fields_converter.convert(fields, @headers, lineno) end end
#converters ⇒ Array
Returns an Array containing field converters; see Field Converters:
csv = CSV.new('')
csv.converters # => []
csv.convert(:integer)
csv.converters # => [:integer]
csv.convert(proc {|x| x.to_s })
csv.converters
Notes that you need to call Ractor.make_shareable(CSV::Converters) on the main Ractor to use this method.
# File 'lib/csv.rb', line 2082
def converters parser_fields_converter.map do |converter| name = Converters.rassoc(converter) name ? name.first : converter end end
#determine_encoding(encoding, internal_encoding) (private)
[ GitHub ]# File 'lib/csv.rb', line 2730
def determine_encoding(encoding, internal_encoding) # honor the IO encoding if we can, otherwise default to ASCII-8BIT io_encoding = raw_encoding return io_encoding if io_encoding return Encoding.find(internal_encoding) if internal_encoding if encoding encoding, = encoding.split(":", 2) if encoding.is_a?(String) return Encoding.find(encoding) end Encoding.default_internal || Encoding.default_external end
#each ⇒ Enumerator
#each {|row| ... }
Enumerator
#each {|row| ... }
Calls the block with each successive row. The data source must be opened for reading.
Without headers:
string = "foo,0\nbar,1\nbaz,2\n"
csv = CSV.new(string)
csv.each do |row|
p row
end
Output:
["foo", "0"]
["bar", "1"]
["baz", "2"]
With headers:
string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
csv = CSV.new(string, headers: true)
csv.each do |row|
p row
end
Output:
<CSV::Row "Name":"foo" "Value":"0">
<CSV::Row "Name":"bar" "Value":"1">
<CSV::Row "Name":"baz" "Value":"2">
Raises an exception if the source is not opened for reading:
string = "foo,0\nbar,1\nbaz,2\n"
csv = CSV.new(string)
csv.close
# Raises IOError (not opened for reading)
csv.each do |row|
p row
end
# File 'lib/csv.rb', line 2554
def each(&block) return to_enum(__method__) unless block_given? begin while true yield(parser_enumerator.next) end rescue StopIteration end end
#eof? ⇒ Boolean
(readonly)
Also known as: #eof
# File 'lib/csv.rb', line 2297
def eof? return false if @eof_error begin parser_enumerator.peek false rescue MalformedCSVError => error @eof_error = error false rescue StopIteration true end end
#field_size_limit ⇒ Integer
?
Returns the limit for field size; used for parsing; see Option field_size_limit
:
CSV.new('').field_size_limit # => nil
Deprecated since 3.2.3. Use #max_field_size instead.
# File 'lib/csv.rb', line 2041
def field_size_limit parser.field_size_limit end
#flock(*args)
# File 'lib/csv.rb', line 2269
def flock(*args) raise NotImplementedError unless @io.respond_to?(:flock) @io.flock(*args) end
#gets
Alias for #shift.
# File 'lib/csv.rb', line 2679
alias_method :gets, :shift
#header_convert(name = nil, &converter)
The block need not return a String object:
csv = CSV.open(path, headers: true)
csv.header_convert {|header, field_info| header.to_sym }
table = csv.read
table.headers # => [:Name, :Value]
If converter_name
is given, the block is not called:
csv = CSV.open(path, headers: true)
csv.header_convert(:downcase) {|header, field_info| fail 'Cannot happen' }
table = csv.read
table.headers # => ["name", "value"]
Raises a parse-time exception if converter_name
is not the name of a built-in field converter:
csv = CSV.open(path, headers: true)
csv.header_convert(:nosuch)
# Raises NoMethodError (undefined method `arity' for nil:NilClass)
csv.read
# File 'lib/csv.rb', line 2509
def header_convert(name = nil, &converter) header_fields_converter.add_converter(name, &converter) end
#header_converters ⇒ Array
Returns an Array containing header converters; used for parsing; see Header Converters:
CSV.new('').header_converters # => []
Notes that you need to call Ractor.make_shareable(CSV::HeaderConverters) on the main Ractor to use this method.
# File 'lib/csv.rb', line 2148
def header_converters header_fields_converter.map do |converter| name = HeaderConverters.rassoc(converter) name ? name.first : converter end end
#header_fields_converter (private)
[ GitHub ]# File 'lib/csv.rb', line 2800
def header_fields_converter @header_fields_converter ||= build_header_fields_converter end
#headers ⇒ Object
Returns the value that determines whether headers are used; used for parsing; see Option headers
:
CSV.new('').headers # => nil
# File 'lib/csv.rb', line 2106
def headers if @writer @writer.headers else parsed_headers = parser.headers return parsed_headers if parsed_headers raw_headers = @parser_options[:headers] raw_headers = nil if raw_headers == false raw_headers end end
#inspect ⇒ String
Returns a String showing certain properties of self
:
string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
csv = CSV.new(string, headers: true)
s = csv.inspect
s # => "#<CSV io_type:StringIO encoding:UTF-8 lineno:0 col_sep:\",\" row_sep:\"\\n\" quote_char:\"\\\"\" headers:true>"
# File 'lib/csv.rb', line 2690
def inspect str = ["#<", self.class.to_s, " io_type:"] # show type of wrapped IO if @io == $stdout then str << "$stdout" elsif @io == $stdin then str << "$stdin" elsif @io == $stderr then str << "$stderr" else str << @io.class.to_s end # show IO.path(), if available if @io.respond_to?(:path) and (p = @io.path) str << " io_path:" << p.inspect end # show encoding str << " encoding:" << @encoding.name # show other attributes ["lineno", "col_sep", "row_sep", "quote_char"].each do |attr_name| if a = __send__(attr_name) str << " " << attr_name << ":" << a.inspect end end ["skip_blanks", "liberal_parsing"].each do |attr_name| if a = __send__("#{attr_name}?") str << " " << attr_name << ":" << a.inspect end end _headers = headers str << " headers:" << _headers.inspect if _headers str << ">" begin str.join('') rescue # any encoding error str.map do |s| e = Encoding::Converter.asciicompat_encoding(s.encoding) e ? s.encode(e) : s.force_encoding("ASCII-8BIT") end.join('') end end
#ioctl(*args)
# File 'lib/csv.rb', line 2274
def ioctl(*args) raise NotImplementedError unless @io.respond_to?(:ioctl) @io.ioctl(*args) end
#line ⇒ Array
# File 'lib/csv.rb', line 2247
def line parser.line end
#line_no ⇒ Integer
Returns the count of the rows parsed or generated.
Parsing:
string = "foo,0\nbar,1\nbaz,2\n"
path = 't.csv'
File.write(path, string)
CSV.open(path) do |csv|
csv.each do |row|
p [csv.lineno, row]
end
end
Output:
[1, ["foo", "0"]]
[2, ["bar", "1"]]
[3, ["baz", "2"]]
Generating:
CSV.generate do |csv|
p csv.lineno; csv << ['foo', 0]
p csv.lineno; csv << ['bar', 1]
p csv.lineno; csv << ['baz', 2]
end
Output:
0
1
2
# File 'lib/csv.rb', line 2223
def lineno if @writer @writer.lineno else parser.lineno end end
#max_field_size ⇒ Integer
?
Returns the limit for field size; used for parsing; see Option max_field_size
:
CSV.new('').max_field_size # => nil
Since 3.2.3.
# File 'lib/csv.rb', line 2053
def max_field_size parser.max_field_size end
#normalize_converters(converters) (private)
[ GitHub ]# File 'lib/csv.rb', line 2745
def normalize_converters(converters) converters ||= [] unless converters.is_a?(Array) converters = [converters] end converters.collect do |converter| case converter when Proc # custom code block [nil, converter] else # by name [converter, nil] end end end
#parser (private)
[ GitHub ]#parser_enumerator (private)
[ GitHub ]#parser_fields_converter (private)
[ GitHub ]# File 'lib/csv.rb', line 2788
def parser_fields_converter @parser_fields_converter ||= build_parser_fields_converter end
#parser_options (private)
[ GitHub ]# File 'lib/csv.rb', line 2834
def @parser_options.merge(header_fields_converter: header_fields_converter, fields_converter: parser_fields_converter) end
#path
[ GitHub ]# File 'lib/csv.rb', line 2279
def path @io.path if @io.respond_to?(:path) end
#puts(row)
Alias for #<<.
# File 'lib/csv.rb', line 2377
alias_method :puts, :<<
#quote_char ⇒ character
Returns the encoded quote character; used for parsing and writing; see Option quote_char
:
CSV.new('').quote_char # => "\""
# File 'lib/csv.rb', line 2029
def quote_char parser.quote_character end
#raw_encoding (private)
Returns the encoding of the internal IO object.
#read ⇒ Array, CSV
Also known as: #readlines
Forms the remaining rows from self
into:
-
A
::CSV::Table
object, if headers are in use. -
An Array of Arrays, otherwise.
The data source must be opened for reading.
Without headers:
string = "foo,0\nbar,1\nbaz,2\n"
path = 't.csv'
File.write(path, string)
csv = CSV.open(path)
csv.read # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
With headers:
string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
path = 't.csv'
File.write(path, string)
csv = CSV.open(path, headers: true)
csv.read # => #<CSV::Table mode:col_or_row row_count:4>
Raises an exception if the source is not opened for reading:
string = "foo,0\nbar,1\nbaz,2\n"
csv = CSV.new(string)
csv.close
# Raises IOError (not opened for reading)
csv.read
#readline
Alias for #shift.
# File 'lib/csv.rb', line 2680
alias_method :readline, :shift
#readlines
Alias for #read.
# File 'lib/csv.rb', line 2603
alias_method :readlines, :read
#rewind
Rewinds the underlying IO object and resets CSV’s lineno() counter.
# File 'lib/csv.rb', line 2312
def rewind @parser = nil @parser_enumerator = nil @eof_error = nil @writer.rewind if @writer @io.rewind end
#row_sep ⇒ String
Returns the encoded row separator; used for parsing and writing; see Option row_sep
:
CSV.new('').row_sep # => "\n"
# File 'lib/csv.rb', line 2019
def row_sep parser.row_separator end
#shift ⇒ Array, ... Also known as: #gets, #readline
Returns the next row of data as:
-
An Array if no headers are used.
-
A
::CSV::Row
object if headers are used.
The data source must be opened for reading.
Without headers:
string = "foo,0\nbar,1\nbaz,2\n"
csv = CSV.new(string)
csv.shift # => ["foo", "0"]
csv.shift # => ["bar", "1"]
csv.shift # => ["baz", "2"]
csv.shift # => nil
With headers:
string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
csv = CSV.new(string, headers: true)
csv.shift # => #<CSV::Row "Name":"foo" "Value":"0">
csv.shift # => #<CSV::Row "Name":"bar" "Value":"1">
csv.shift # => #<CSV::Row "Name":"baz" "Value":"2">
csv.shift # => nil
Raises an exception if the source is not opened for reading:
string = "foo,0\nbar,1\nbaz,2\n"
csv = CSV.new(string)
csv.close
# Raises IOError (not opened for reading)
csv.shift
# File 'lib/csv.rb', line 2668
def shift if @eof_error eof_error, @eof_error = @eof_error, nil raise eof_error end begin parser_enumerator.next rescue StopIteration nil end end
#skip_lines ⇒ Regexp
?
Returns the Regexp used to identify comment lines; used for parsing; see Option skip_lines
:
CSV.new('').skip_lines # => nil
# File 'lib/csv.rb', line 2063
def skip_lines parser.skip_lines end
#stat(*args)
# File 'lib/csv.rb', line 2283
def stat(*args) raise NotImplementedError unless @io.respond_to?(:stat) @io.stat(*args) end
#to_i
# File 'lib/csv.rb', line 2288
def to_i raise NotImplementedError unless @io.respond_to?(:to_i) @io.to_i end
#to_io
[ GitHub ]# File 'lib/csv.rb', line 2293
def to_io @io.respond_to?(:to_io) ? @io.to_io : @io end
#writer (private)
[ GitHub ]#writer_fields_converter (private)
[ GitHub ]# File 'lib/csv.rb', line 2813
def writer_fields_converter @writer_fields_converter ||= build_writer_fields_converter end
#writer_options (private)
[ GitHub ]# File 'lib/csv.rb', line 2847
def @writer_options.merge(header_fields_converter: header_fields_converter, fields_converter: writer_fields_converter) end