csv 3.1.5 → 3.1.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (32) hide show
  1. checksums.yaml +4 -4
  2. data/NEWS.md +36 -0
  3. data/doc/arguments/io.rdoc +5 -0
  4. data/doc/options/common/col_sep.rdoc +63 -0
  5. data/doc/options/common/quote_char.rdoc +42 -0
  6. data/doc/{row_sep.rdoc → options/common/row_sep.rdoc} +15 -6
  7. data/doc/{force_quotes.rdoc → options/generating/force_quotes.rdoc} +0 -0
  8. data/doc/{quote_empty.rdoc → options/generating/quote_empty.rdoc} +0 -0
  9. data/doc/{write_converters.rdoc → options/generating/write_converters.rdoc} +8 -6
  10. data/doc/{write_empty_value.rdoc → options/generating/write_empty_value.rdoc} +0 -0
  11. data/doc/{write_headers.rdoc → options/generating/write_headers.rdoc} +0 -0
  12. data/doc/{write_nil_value.rdoc → options/generating/write_nil_value.rdoc} +1 -1
  13. data/doc/options/parsing/converters.rdoc +46 -0
  14. data/doc/{empty_value.rdoc → options/parsing/empty_value.rdoc} +0 -0
  15. data/doc/{field_size_limit.rdoc → options/parsing/field_size_limit.rdoc} +0 -0
  16. data/doc/options/parsing/header_converters.rdoc +43 -0
  17. data/doc/{headers.rdoc → options/parsing/headers.rdoc} +0 -0
  18. data/doc/{liberal_parsing.rdoc → options/parsing/liberal_parsing.rdoc} +0 -0
  19. data/doc/{nil_value.rdoc → options/parsing/nil_value.rdoc} +0 -0
  20. data/doc/{return_headers.rdoc → options/parsing/return_headers.rdoc} +0 -0
  21. data/doc/{skip_blanks.rdoc → options/parsing/skip_blanks.rdoc} +0 -0
  22. data/doc/{skip_lines.rdoc → options/parsing/skip_lines.rdoc} +0 -0
  23. data/doc/{strip.rdoc → options/parsing/strip.rdoc} +0 -0
  24. data/doc/{unconverted_fields.rdoc → options/parsing/unconverted_fields.rdoc} +0 -0
  25. data/lib/csv.rb +1334 -495
  26. data/lib/csv/version.rb +1 -1
  27. data/lib/csv/writer.rb +45 -4
  28. metadata +38 -23
  29. data/doc/col_sep.rdoc +0 -45
  30. data/doc/converters.rdoc +0 -45
  31. data/doc/header_converters.rdoc +0 -31
  32. data/doc/quote_char.rdoc +0 -32
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: eec352a246dc1189213c78e35541e9903f172889792b92a23d6b8d7215d9ae37
4
- data.tar.gz: 63754025784b9d6d26686b48efe8627b18c1aaa26e14f1261d14a09a4921612e
3
+ metadata.gz: 684d334d79d666022640de8b3bfa8d2e6fa879cb0c9e59349e9adf8307147fa0
4
+ data.tar.gz: 6298def337c705d19acb6d1da52560aa53f0dfeba5660202d8fc0259418d96a1
5
5
  SHA512:
6
- metadata.gz: c1b9895d4735d3f7a1376765d8e71a03388d4b8f52ace5a8eab3126e1f3167f77fcfd312212fdbdbda496d4a2f837a966bf33b871bee96f633c536b566ce0a9f
7
- data.tar.gz: 9347baa988315b544d41ec23ded72a812dec09b7c0832c72bc4ff3be950e25d0f2184f9ed43967113ddb63e56e29c847bffb469b7883ad4207b913368057b58c
6
+ metadata.gz: 42349aa586b53f75c75ea29a5388889c21645b24e1ad8ac8e1752697f94dc9e7564b62f36b2b6219516f34c1a27bbf581566f3f2dafef556f9783b907e932d04
7
+ data.tar.gz: 69319007e9a35acb7659d73b5c9a38256a572a5a21ef59365b8f4fd0fee9d06c2c0c89ae346bf701e6c0af430fc99868c625323cc75f620340eb80006ce0d036
data/NEWS.md CHANGED
@@ -1,5 +1,41 @@
1
1
  # News
2
2
 
3
+ ## 3.1.6 - 2020-07-20
4
+
5
+ ### Improvements
6
+
7
+ * Improved document.
8
+ [GitHub#127][GitHub#135][GitHub#136][GitHub#137][GitHub#139][GitHub#140]
9
+ [GitHub#141][GitHub#142][GitHub#143][GitHub#145][GitHub#146][GitHub#148]
10
+ [GitHub#148][GitHub#151][GitHub#152][GitHub#154][GitHub#155][GitHub#157]
11
+ [Patch by Burdette Lamar]
12
+
13
+ * `CSV.open`: Added support for `undef: :replace`.
14
+ [GitHub#129][Patch by Koichi ITO]
15
+
16
+ * `CSV.open`: Added support for `invalid: :replace`.
17
+ [GitHub#129][Patch by Koichi ITO]
18
+
19
+ * Don't run quotable check for invalid encoding field values.
20
+ [GitHub#131][Patch by Koichi ITO]
21
+
22
+ * Added support for specifying the target indexes and names to
23
+ `force_quotes:`.
24
+ [GitHub#153][Reported by Aleksandr]
25
+
26
+ * `CSV.generate`: Changed to use the encoding of the first non-ASCII
27
+ field rather than the encoding of ASCII only field.
28
+
29
+ * Changed to require the stringio gem 0.1.3 or later.
30
+
31
+ ### Thanks
32
+
33
+ * Burdette Lamar
34
+
35
+ * Koichi ITO
36
+
37
+ * Aleksandr
38
+
3
39
  ## 3.1.5 - 2020-05-18
4
40
 
5
41
  ### Improvements
@@ -0,0 +1,5 @@
1
+ * Argument +io+ should be an IO object that is:
2
+ * Open for reading; on return, the IO object will be closed.
3
+ * Positioned at the beginning.
4
+ To position at the end, for appending, use method CSV.generate.
5
+ For any other positioning, pass a preset \StringIO object instead.
@@ -0,0 +1,63 @@
1
+ ====== Option +col_sep+
2
+
3
+ Specifies the \String field separator to be used
4
+ for both parsing and generating.
5
+ The \String will be transcoded into the data's \Encoding before use.
6
+
7
+ Default value:
8
+ CSV::DEFAULT_OPTIONS.fetch(:col_sep) # => "," (comma)
9
+
10
+ Using the default (comma):
11
+ str = CSV.generate do |csv|
12
+ csv << [:foo, 0]
13
+ csv << [:bar, 1]
14
+ csv << [:baz, 2]
15
+ end
16
+ str # => "foo,0\nbar,1\nbaz,2\n"
17
+ ary = CSV.parse(str)
18
+ ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
19
+
20
+ Using +:+ (colon):
21
+ col_sep = ':'
22
+ str = CSV.generate(col_sep: col_sep) do |csv|
23
+ csv << [:foo, 0]
24
+ csv << [:bar, 1]
25
+ csv << [:baz, 2]
26
+ end
27
+ str # => "foo:0\nbar:1\nbaz:2\n"
28
+ ary = CSV.parse(str, col_sep: col_sep)
29
+ ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
30
+
31
+ Using +::+ (two colons):
32
+ col_sep = '::'
33
+ str = CSV.generate(col_sep: col_sep) do |csv|
34
+ csv << [:foo, 0]
35
+ csv << [:bar, 1]
36
+ csv << [:baz, 2]
37
+ end
38
+ str # => "foo::0\nbar::1\nbaz::2\n"
39
+ ary = CSV.parse(str, col_sep: col_sep)
40
+ ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
41
+
42
+ Using <tt>''</tt> (empty string):
43
+ col_sep = ''
44
+ str = CSV.generate(col_sep: col_sep) do |csv|
45
+ csv << [:foo, 0]
46
+ csv << [:bar, 1]
47
+ csv << [:baz, 2]
48
+ end
49
+ str # => "foo0\nbar1\nbaz2\n"
50
+
51
+ ---
52
+
53
+ Raises an exception if parsing with the empty \String:
54
+ col_sep = ''
55
+ # Raises ArgumentError (:col_sep must be 1 or more characters: "")
56
+ CSV.parse("foo0\nbar1\nbaz2\n", col_sep: col_sep)
57
+
58
+ Raises an exception if the given value is not String-convertible:
59
+ col_sep = BasicObject.new
60
+ # Raises NoMethodError (undefined method `to_s' for #<BasicObject:>)
61
+ CSV.generate(line, col_sep: col_sep)
62
+ # Raises NoMethodError (undefined method `to_s' for #<BasicObject:>)
63
+ CSV.parse(str, col_sep: col_sep)
@@ -0,0 +1,42 @@
1
+ ====== Option +quote_char+
2
+
3
+ Specifies the character (\String of length 1) used used to quote fields
4
+ in both parsing and generating.
5
+ This String will be transcoded into the data's \Encoding before use.
6
+
7
+ Default value:
8
+ CSV::DEFAULT_OPTIONS.fetch(:quote_char) # => "\"" (double quote)
9
+
10
+ This is useful for an application that incorrectly uses <tt>'</tt> (single-quote)
11
+ to quote fields, instead of the correct <tt>"</tt> (double-quote).
12
+
13
+ Using the default (double quote):
14
+ str = CSV.generate do |csv|
15
+ csv << ['foo', 0]
16
+ csv << ["'bar'", 1]
17
+ csv << ['"baz"', 2]
18
+ end
19
+ str # => "foo,0\n'bar',1\n\"\"\"baz\"\"\",2\n"
20
+ ary = CSV.parse(str)
21
+ ary # => [["foo", "0"], ["'bar'", "1"], ["\"baz\"", "2"]]
22
+
23
+ Using <tt>'</tt> (single-quote):
24
+ quote_char = "'"
25
+ str = CSV.generate(quote_char: quote_char) do |csv|
26
+ csv << ['foo', 0]
27
+ csv << ["'bar'", 1]
28
+ csv << ['"baz"', 2]
29
+ end
30
+ str # => "foo,0\n'''bar''',1\n\"baz\",2\n"
31
+ ary = CSV.parse(str, quote_char: quote_char)
32
+ ary # => [["foo", "0"], ["'bar'", "1"], ["\"baz\"", "2"]]
33
+
34
+ ---
35
+
36
+ Raises an exception if the \String length is greater than 1:
37
+ # Raises ArgumentError (:quote_char has to be nil or a single character String)
38
+ CSV.new('', quote_char: 'xx')
39
+
40
+ Raises an exception if the value is not a \String:
41
+ # Raises ArgumentError (:quote_char has to be nil or a single character String)
42
+ CSV.new('', quote_char: :foo)
@@ -12,7 +12,8 @@ When +row_sep+ is a \String, that \String becomes the row separator.
12
12
  The String will be transcoded into the data's Encoding before use.
13
13
 
14
14
  Using <tt>"\n"</tt>:
15
- str = CSV.generate do |csv|
15
+ row_sep = "\n"
16
+ str = CSV.generate(row_sep: row_sep) do |csv|
16
17
  csv << [:foo, 0]
17
18
  csv << [:bar, 1]
18
19
  csv << [:baz, 2]
@@ -57,20 +58,28 @@ Using '' (empty string):
57
58
  ---
58
59
 
59
60
  When +row_sep+ is the \Symbol +:auto+ (the default),
60
- invokes auto-discovery of the row separator.
61
+ generating uses <tt>"\n"</tt> as the row separator:
62
+ str = CSV.generate do |csv|
63
+ csv << [:foo, 0]
64
+ csv << [:bar, 1]
65
+ csv << [:baz, 2]
66
+ end
67
+ str # => "foo,0\nbar,1\nbaz,2\n"
68
+
69
+ Parsing, on the other hand, invokes auto-discovery of the row separator.
61
70
 
62
71
  Auto-discovery reads ahead in the data looking for the next <tt>\r\n</tt>, +\n+, or +\r+ sequence.
63
72
  The sequence will be selected even if it occurs in a quoted field,
64
73
  assuming that you would have the same line endings there.
65
74
 
66
- row_sep = :auto
67
- str = CSV.generate(row_sep: row_sep) do |csv|
75
+ Example:
76
+ str = CSV.generate do |csv|
68
77
  csv << [:foo, 0]
69
78
  csv << [:bar, 1]
70
79
  csv << [:baz, 2]
71
80
  end
72
81
  str # => "foo,0\nbar,1\nbaz,2\n"
73
- ary = CSV.parse(str, row_sep: row_sep)
82
+ ary = CSV.parse(str)
74
83
  ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
75
84
 
76
85
  The default <tt>$INPUT_RECORD_SEPARATOR</tt> (<tt>$/</tt>) is used
@@ -86,6 +95,6 @@ Obviously, discovery takes a little time. Set manually if speed is important. Al
86
95
  Raises an exception if the given value is not String-convertible:
87
96
  row_sep = BasicObject.new
88
97
  # Raises NoMethodError (undefined method `to_s' for #<BasicObject:>)
89
- CSV.generate_line(ary, row_sep: row_sep)
98
+ CSV.generate(ary, row_sep: row_sep)
90
99
  # Raises NoMethodError (undefined method `to_s' for #<BasicObject:>)
91
100
  CSV.parse(str, row_sep: row_sep)
@@ -1,7 +1,7 @@
1
1
  ====== Option +write_converters+
2
2
 
3
- Specifies the \Proc or \Array of Procs that are to be called
4
- for converting each output field.
3
+ Specifies converters to be used in generating fields.
4
+ See {Write Converters}[#class-CSV-label-Write+Converters]
5
5
 
6
6
  Default value:
7
7
  CSV::DEFAULT_OPTIONS.fetch(:write_converters) # => nil
@@ -11,21 +11,23 @@ With no write converter:
11
11
  str # => "\"\na\n\",\tb\t, c \n"
12
12
 
13
13
  With a write converter:
14
- strip_converter = lambda {|field| field.strip }
14
+ strip_converter = proc {|field| field.strip }
15
15
  str = CSV.generate_line(["\na\n", "\tb\t", " c "], write_converters: strip_converter)
16
16
  str # => "a,b,c\n"
17
17
 
18
18
  With two write converters (called in order):
19
- upcase_converter = lambda {|field| field.upcase }
20
- downcase_converter = lambda {|field| field.downcase }
19
+ upcase_converter = proc {|field| field.upcase }
20
+ downcase_converter = proc {|field| field.downcase }
21
21
  write_converters = [upcase_converter, downcase_converter]
22
22
  str = CSV.generate_line(['a', 'b', 'c'], write_converters: write_converters)
23
23
  str # => "a,b,c\n"
24
24
 
25
+ See also {Write Converters}[#class-CSV-label-Write+Converters]
26
+
25
27
  ---
26
28
 
27
29
  Raises an exception if the converter returns a value that is neither +nil+
28
30
  nor \String-convertible:
29
- bad_converter = lambda {|field| BasicObject.new }
31
+ bad_converter = proc {|field| BasicObject.new }
30
32
  # Raises NoMethodError (undefined method `is_a?' for #<BasicObject:>)
31
33
  CSV.generate_line(['a', 'b', 'c'], write_converters: bad_converter)
@@ -1,6 +1,6 @@
1
1
  ====== Option +write_nil_value+
2
2
 
3
- Specifies the object that is to be substituted for each +nil+ field.
3
+ Specifies the object that is to be substituted for each +nil+-valued field.
4
4
 
5
5
  Default value:
6
6
  CSV::DEFAULT_OPTIONS.fetch(:write_nil_value) # => nil
@@ -0,0 +1,46 @@
1
+ ====== Option +converters+
2
+
3
+ Specifies converters to be used in parsing fields.
4
+ See {Field Converters}[#class-CSV-label-Field+Converters]
5
+
6
+ Default value:
7
+ CSV::DEFAULT_OPTIONS.fetch(:converters) # => nil
8
+
9
+ The value may be a field converter name
10
+ (see {Stored Converters}[#class-CSV-label-Stored+Converters]):
11
+ str = '1,2,3'
12
+ # Without a converter
13
+ array = CSV.parse_line(str)
14
+ array # => ["1", "2", "3"]
15
+ # With built-in converter :integer
16
+ array = CSV.parse_line(str, converters: :integer)
17
+ array # => [1, 2, 3]
18
+
19
+ The value may be a converter list
20
+ (see {Converter Lists}[#class-CSV-label-Converter+Lists]):
21
+ str = '1,3.14159'
22
+ # Without converters
23
+ array = CSV.parse_line(str)
24
+ array # => ["1", "3.14159"]
25
+ # With built-in converters
26
+ array = CSV.parse_line(str, converters: [:integer, :float])
27
+ array # => [1, 3.14159]
28
+
29
+ The value may be a \Proc custom converter:
30
+ (see {Custom Field Converters}[#class-CSV-label-Custom+Field+Converters]):
31
+ str = ' foo , bar , baz '
32
+ # Without a converter
33
+ array = CSV.parse_line(str)
34
+ array # => [" foo ", " bar ", " baz "]
35
+ # With a custom converter
36
+ array = CSV.parse_line(str, converters: proc {|field| field.strip })
37
+ array # => ["foo", "bar", "baz"]
38
+
39
+ See also {Custom Field Converters}[#class-CSV-label-Custom+Field+Converters]
40
+
41
+ ---
42
+
43
+ Raises an exception if the converter is not a converter name or a \Proc:
44
+ str = 'foo,0'
45
+ # Raises NoMethodError (undefined method `arity' for nil:NilClass)
46
+ CSV.parse(str, converters: :foo)
@@ -0,0 +1,43 @@
1
+ ====== Option +header_converters+
2
+
3
+ Specifies converters to be used in parsing headers.
4
+ See {Header Converters}[#class-CSV-label-Header+Converters]
5
+
6
+ Default value:
7
+ CSV::DEFAULT_OPTIONS.fetch(:header_converters) # => nil
8
+
9
+ Identical in functionality to option {converters}[#class-CSV-label-Option+converters]
10
+ except that:
11
+ - The converters apply only to the header row.
12
+ - The built-in header converters are +:downcase+ and +:symbol+.
13
+
14
+ This section assumes prior execution of:
15
+ str = <<-EOT
16
+ Name,Value
17
+ foo,0
18
+ bar,1
19
+ baz,2
20
+ EOT
21
+ # With no header converter
22
+ table = CSV.parse(str, headers: true)
23
+ table.headers # => ["Name", "Value"]
24
+
25
+ The value may be a header converter name
26
+ (see {Stored Converters}[#class-CSV-label-Stored+Converters]):
27
+ table = CSV.parse(str, headers: true, header_converters: :downcase)
28
+ table.headers # => ["name", "value"]
29
+
30
+ The value may be a converter list
31
+ (see {Converter Lists}[#class-CSV-label-Converter+Lists]):
32
+ header_converters = [:downcase, :symbol]
33
+ table = CSV.parse(str, headers: true, header_converters: header_converters)
34
+ table.headers # => [:name, :value]
35
+
36
+ The value may be a \Proc custom converter
37
+ (see {Custom Header Converters}[#class-CSV-label-Custom+Header+Converters]):
38
+ upcase_converter = proc {|field| field.upcase }
39
+ table = CSV.parse(str, headers: true, header_converters: upcase_converter)
40
+ table.headers # => ["NAME", "VALUE"]
41
+
42
+ See also {Custom Header Converters}[#class-CSV-label-Custom+Header+Converters]
43
+
data/lib/csv.rb CHANGED
@@ -34,7 +34,7 @@
34
34
  # I'm sure I'll miss something, but I'll try to mention most of the major
35
35
  # differences I am aware of, to help others quickly get up to speed:
36
36
  #
37
- # === CSV Parsing
37
+ # === \CSV Parsing
38
38
  #
39
39
  # * This parser is m17n aware. See CSV for full details.
40
40
  # * This library has a stricter parser and will throw MalformedCSVErrors on
@@ -103,82 +103,209 @@ require_relative "csv/writer"
103
103
 
104
104
  using CSV::MatchP if CSV.const_defined?(:MatchP)
105
105
 
106
- # This class provides a complete interface to CSV files and data. It offers
107
- # tools to enable you to read and write to and from Strings or IO objects, as
108
- # needed.
106
+ # == \CSV
107
+ # \CSV (comma-separated variables) data is a text representation of a table:
108
+ # - A _row_ _separator_ delimits table rows.
109
+ # A common row separator is the newline character <tt>"\n"</tt>.
110
+ # - A _column_ _separator_ delimits fields in a row.
111
+ # A common column separator is the comma character <tt>","</tt>.
109
112
  #
110
- # The most generic interface of the library is:
113
+ # This \CSV \String, with row separator <tt>"\n"</tt>
114
+ # and column separator <tt>","</tt>,
115
+ # has three rows and two columns:
116
+ # "foo,0\nbar,1\nbaz,2\n"
111
117
  #
112
- # csv = CSV.new(io, **options)
118
+ # Despite the name \CSV, a \CSV representation can use different separators.
113
119
  #
114
- # # Reading: IO object should be open for read
115
- # csv.read # => array of rows
116
- # # or
117
- # csv.each do |row|
118
- # # ...
119
- # end
120
- # # or
121
- # row = csv.shift
120
+ # == \Class \CSV
122
121
  #
123
- # # Writing: IO object should be open for write
124
- # csv << row
122
+ # Class \CSV provides methods for:
123
+ # - Parsing \CSV data from a \String object, a \File (via its file path), or an \IO object.
124
+ # - Generating \CSV data to a \String object.
125
125
  #
126
- # There are several specialized class methods for one-statement reading or writing,
127
- # described in the Specialized Methods section.
126
+ # To make \CSV available:
127
+ # require 'csv'
128
128
  #
129
- # If a String is passed into ::new, it is internally wrapped into a StringIO object.
129
+ # All examples here assume that this has been done.
130
130
  #
131
- # +options+ can be used for specifying the particular CSV flavor (column
132
- # separators, row separators, value quoting and so on), and for data conversion,
133
- # see Data Conversion section for the description of the latter.
131
+ # == Keeping It Simple
134
132
  #
135
- # == Specialized Methods
133
+ # A \CSV object has dozens of instance methods that offer fine-grained control
134
+ # of parsing and generating \CSV data.
135
+ # For many needs, though, simpler approaches will do.
136
136
  #
137
- # === Reading
137
+ # This section summarizes the singleton methods in \CSV
138
+ # that allow you to parse and generate without explicitly
139
+ # creating \CSV objects.
140
+ # For details, follow the links.
138
141
  #
139
- # # From a file: all at once
140
- # arr_of_rows = CSV.read("path/to/file.csv", **options)
141
- # # iterator-style:
142
- # CSV.foreach("path/to/file.csv", **options) do |row|
143
- # # ...
144
- # end
142
+ # === Simple Parsing
145
143
  #
146
- # # From a string
147
- # arr_of_rows = CSV.parse("CSV,data,String", **options)
148
- # # or
149
- # CSV.parse("CSV,data,String", **options) do |row|
150
- # # ...
151
- # end
144
+ # Parsing methods commonly return either of:
145
+ # - An \Array of Arrays of Strings:
146
+ # - The outer \Array is the entire "table".
147
+ # - Each inner \Array is a row.
148
+ # - Each \String is a field.
149
+ # - A CSV::Table object. For details, see
150
+ # {\CSV with Headers}[#class-CSV-label-CSV+with+Headers].
152
151
  #
153
- # === Writing
152
+ # ==== Parsing a \String
154
153
  #
155
- # # To a file
156
- # CSV.open("path/to/file.csv", "wb") do |csv|
157
- # csv << ["row", "of", "CSV", "data"]
158
- # csv << ["another", "row"]
159
- # # ...
160
- # end
154
+ # The input to be parsed can be a string:
155
+ # string = "foo,0\nbar,1\nbaz,2\n"
156
+ #
157
+ # \Method CSV.parse returns the entire \CSV data:
158
+ # CSV.parse(string) # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
159
+ #
160
+ # \Method CSV.parse_line returns only the first row:
161
+ # CSV.parse_line(string) # => ["foo", "0"]
162
+ #
163
+ # \CSV extends class \String with instance method String#parse_csv,
164
+ # which also returns only the first row:
165
+ # string.parse_csv # => ["foo", "0"]
166
+ #
167
+ # ==== Parsing Via a \File Path
168
+ #
169
+ # The input to be parsed can be in a file:
170
+ # string = "foo,0\nbar,1\nbaz,2\n"
171
+ # path = 't.csv'
172
+ # File.write(path, string)
173
+ #
174
+ # \Method CSV.read returns the entire \CSV data:
175
+ # CSV.read(path) # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
176
+ #
177
+ # \Method CSV.foreach iterates, passing each row to the given block:
178
+ # CSV.foreach(path) do |row|
179
+ # p row
180
+ # end
181
+ # Output:
182
+ # ["foo", "0"]
183
+ # ["bar", "1"]
184
+ # ["baz", "2"]
185
+ #
186
+ # \Method CSV.table returns the entire \CSV data as a CSV::Table object:
187
+ # CSV.table(path) # => #<CSV::Table mode:col_or_row row_count:3>
188
+ #
189
+ # ==== Parsing from an Open \IO Stream
190
+ #
191
+ # The input to be parsed can be in an open \IO stream:
192
+ #
193
+ # \Method CSV.read returns the entire \CSV data:
194
+ # File.open(path) do |file|
195
+ # CSV.read(file)
196
+ # end # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
197
+ #
198
+ # As does method CSV.parse:
199
+ # File.open(path) do |file|
200
+ # CSV.parse(file)
201
+ # end # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
161
202
  #
162
- # # To a String
163
- # csv_string = CSV.generate do |csv|
164
- # csv << ["row", "of", "CSV", "data"]
165
- # csv << ["another", "row"]
166
- # # ...
203
+ # \Method CSV.parse_line returns only the first row:
204
+ # File.open(path) do |file|
205
+ # CSV.parse_line(file)
206
+ # end # => ["foo", "0"]
207
+ #
208
+ # \Method CSV.foreach iterates, passing each row to the given block:
209
+ # File.open(path) do |file|
210
+ # CSV.foreach(file) do |row|
211
+ # p row
212
+ # end
213
+ # end
214
+ # Output:
215
+ # ["foo", "0"]
216
+ # ["bar", "1"]
217
+ # ["baz", "2"]
218
+ #
219
+ # \Method CSV.table returns the entire \CSV data as a CSV::Table object:
220
+ # File.open(path) do |file|
221
+ # CSV.table(file)
222
+ # end # => #<CSV::Table mode:col_or_row row_count:3>
223
+ #
224
+ # === Simple Generating
225
+ #
226
+ # \Method CSV.generate returns a \String;
227
+ # this example uses method CSV#<< to append the rows
228
+ # that are to be generated:
229
+ # output_string = CSV.generate do |csv|
230
+ # csv << ['foo', 0]
231
+ # csv << ['bar', 1]
232
+ # csv << ['baz', 2]
167
233
  # end
234
+ # output_string # => "foo,0\nbar,1\nbaz,2\n"
168
235
  #
169
- # === Shortcuts
236
+ # \Method CSV.generate_line returns a \String containing the single row
237
+ # constructed from an \Array:
238
+ # CSV.generate_line(['foo', '0']) # => "foo,0\n"
170
239
  #
171
- # # Core extensions for converting one line
172
- # csv_string = ["CSV", "data"].to_csv # to CSV
173
- # csv_array = "CSV,String".parse_csv # from CSV
240
+ # \CSV extends class \Array with instance method <tt>Array#to_csv</tt>,
241
+ # which forms an \Array into a \String:
242
+ # ['foo', '0'].to_csv # => "foo,0\n"
174
243
  #
175
- # # CSV() method
176
- # CSV { |csv_out| csv_out << %w{my data here} } # to $stdout
177
- # CSV(csv = "") { |csv_str| csv_str << %w{my data here} } # to a String
178
- # CSV($stderr) { |csv_err| csv_err << %w{my data here} } # to $stderr
179
- # CSV($stdin) { |csv_in| csv_in.each { |row| p row } } # from $stdin
244
+ # === "Filtering" \CSV
180
245
  #
181
- # == Options
246
+ # \Method CSV.filter provides a Unix-style filter for \CSV data.
247
+ # The input data is processed to form the output data:
248
+ # in_string = "foo,0\nbar,1\nbaz,2\n"
249
+ # out_string = ''
250
+ # CSV.filter(in_string, out_string) do |row|
251
+ # row[0] = row[0].upcase
252
+ # row[1] *= 4
253
+ # end
254
+ # out_string # => "FOO,0000\nBAR,1111\nBAZ,2222\n"
255
+ #
256
+ # == \CSV Objects
257
+ #
258
+ # There are three ways to create a \CSV object:
259
+ # - \Method CSV.new returns a new \CSV object.
260
+ # - \Method CSV.instance returns a new or cached \CSV object.
261
+ # - \Method \CSV() also returns a new or cached \CSV object.
262
+ #
263
+ # === Instance Methods
264
+ #
265
+ # \CSV has three groups of instance methods:
266
+ # - Its own internally defined instance methods.
267
+ # - Methods included by module Enumerable.
268
+ # - Methods delegated to class IO. See below.
269
+ #
270
+ # ==== Delegated Methods
271
+ #
272
+ # For convenience, a CSV object will delegate to many methods in class IO.
273
+ # (A few have wrapper "guard code" in \CSV.) You may call:
274
+ # * IO#binmode
275
+ # * #binmode?
276
+ # * IO#close
277
+ # * IO#close_read
278
+ # * IO#close_write
279
+ # * IO#closed?
280
+ # * #eof
281
+ # * #eof?
282
+ # * IO#external_encoding
283
+ # * IO#fcntl
284
+ # * IO#fileno
285
+ # * #flock
286
+ # * IO#flush
287
+ # * IO#fsync
288
+ # * IO#internal_encoding
289
+ # * #ioctl
290
+ # * IO#isatty
291
+ # * #path
292
+ # * IO#pid
293
+ # * IO#pos
294
+ # * IO#pos=
295
+ # * IO#reopen
296
+ # * #rewind
297
+ # * IO#seek
298
+ # * #stat
299
+ # * IO#string
300
+ # * IO#sync
301
+ # * IO#sync=
302
+ # * IO#tell
303
+ # * #to_i
304
+ # * #to_io
305
+ # * IO#truncate
306
+ # * IO#tty?
307
+ #
308
+ # === Options
182
309
  #
183
310
  # The default values for options are:
184
311
  # DEFAULT_OPTIONS = {
@@ -208,59 +335,90 @@ using CSV::MatchP if CSV.const_defined?(:MatchP)
208
335
  # strip: false,
209
336
  # }
210
337
  #
211
- # === Options for Parsing
338
+ # ==== Options for Parsing
339
+ #
340
+ # Options for parsing, described in detail below, include:
341
+ # - +row_sep+: Specifies the row separator; used to delimit rows.
342
+ # - +col_sep+: Specifies the column separator; used to delimit fields.
343
+ # - +quote_char+: Specifies the quote character; used to quote fields.
344
+ # - +field_size_limit+: Specifies the maximum field size allowed.
345
+ # - +converters+: Specifies the field converters to be used.
346
+ # - +unconverted_fields+: Specifies whether unconverted fields are to be available.
347
+ # - +headers+: Specifies whether data contains headers,
348
+ # or specifies the headers themselves.
349
+ # - +return_headers+: Specifies whether headers are to be returned.
350
+ # - +header_converters+: Specifies the header converters to be used.
351
+ # - +skip_blanks+: Specifies whether blanks lines are to be ignored.
352
+ # - +skip_lines+: Specifies how comments lines are to be recognized.
353
+ # - +strip+: Specifies whether leading and trailing whitespace are
354
+ # to be stripped from fields..
355
+ # - +liberal_parsing+: Specifies whether \CSV should attempt to parse
356
+ # non-compliant data.
357
+ # - +nil_value+: Specifies the object that is to be substituted for each null (no-text) field.
358
+ # - +empty_value+: Specifies the object that is to be substituted for each empty field.
212
359
  #
213
- # :include: ../doc/col_sep.rdoc
360
+ # :include: ../doc/options/common/row_sep.rdoc
214
361
  #
215
- # :include: ../doc/row_sep.rdoc
362
+ # :include: ../doc/options/common/col_sep.rdoc
216
363
  #
217
- # :include: ../doc/quote_char.rdoc
364
+ # :include: ../doc/options/common/quote_char.rdoc
218
365
  #
219
- # :include: ../doc/field_size_limit.rdoc
366
+ # :include: ../doc/options/parsing/field_size_limit.rdoc
220
367
  #
221
- # :include: ../doc/converters.rdoc
368
+ # :include: ../doc/options/parsing/converters.rdoc
222
369
  #
223
- # :include: ../doc/unconverted_fields.rdoc
370
+ # :include: ../doc/options/parsing/unconverted_fields.rdoc
224
371
  #
225
- # :include: ../doc/headers.rdoc
372
+ # :include: ../doc/options/parsing/headers.rdoc
226
373
  #
227
- # :include: ../doc/return_headers.rdoc
374
+ # :include: ../doc/options/parsing/return_headers.rdoc
228
375
  #
229
- # :include: ../doc/header_converters.rdoc
376
+ # :include: ../doc/options/parsing/header_converters.rdoc
230
377
  #
231
- # :include: ../doc/skip_blanks.rdoc
378
+ # :include: ../doc/options/parsing/skip_blanks.rdoc
232
379
  #
233
- # :include: ../doc/skip_lines.rdoc
380
+ # :include: ../doc/options/parsing/skip_lines.rdoc
234
381
  #
235
- # :include: ../doc/liberal_parsing.rdoc
382
+ # :include: ../doc/options/parsing/strip.rdoc
236
383
  #
237
- # :include: ../doc/nil_value.rdoc
384
+ # :include: ../doc/options/parsing/liberal_parsing.rdoc
238
385
  #
239
- # :include: ../doc/empty_value.rdoc
386
+ # :include: ../doc/options/parsing/nil_value.rdoc
240
387
  #
241
- # === Options for Generating
388
+ # :include: ../doc/options/parsing/empty_value.rdoc
242
389
  #
243
- # :include: ../doc/col_sep.rdoc
390
+ # ==== Options for Generating
244
391
  #
245
- # :include: ../doc/row_sep.rdoc
392
+ # Options for generating, described in detail below, include:
393
+ # - +row_sep+: Specifies the row separator; used to delimit rows.
394
+ # - +col_sep+: Specifies the column separator; used to delimit fields.
395
+ # - +quote_char+: Specifies the quote character; used to quote fields.
396
+ # - +write_headers+: Specifies whether headers are to be written.
397
+ # - +force_quotes+: Specifies whether each output field is to be quoted.
398
+ # - +quote_empty+: Specifies whether each empty output field is to be quoted.
399
+ # - +write_converters+: Specifies the field converters to be used in writing.
400
+ # - +write_nil_value+: Specifies the object that is to be substituted for each +nil+-valued field.
401
+ # - +write_empty_value+: Specifies the object that is to be substituted for each empty field.
246
402
  #
247
- # :include: ../doc/quote_char.rdoc
403
+ # :include: ../doc/options/common/row_sep.rdoc
248
404
  #
249
- # :include: ../doc/write_headers.rdoc
405
+ # :include: ../doc/options/common/col_sep.rdoc
250
406
  #
251
- # :include: ../doc/force_quotes.rdoc
407
+ # :include: ../doc/options/common/quote_char.rdoc
252
408
  #
253
- # :include: ../doc/quote_empty.rdoc
409
+ # :include: ../doc/options/generating/write_headers.rdoc
254
410
  #
255
- # :include: ../doc/write_converters.rdoc
411
+ # :include: ../doc/options/generating/force_quotes.rdoc
256
412
  #
257
- # :include: ../doc/write_nil_value.rdoc
413
+ # :include: ../doc/options/generating/quote_empty.rdoc
258
414
  #
259
- # :include: ../doc/write_empty_value.rdoc
415
+ # :include: ../doc/options/generating/write_converters.rdoc
260
416
  #
261
- # :include: ../doc/strip.rdoc
417
+ # :include: ../doc/options/generating/write_nil_value.rdoc
262
418
  #
263
- # == CSV with headers
419
+ # :include: ../doc/options/generating/write_empty_value.rdoc
420
+ #
421
+ # === \CSV with Headers
264
422
  #
265
423
  # CSV allows to specify column names of CSV file, whether they are in data, or
266
424
  # provided separately. If headers are specified, reading methods return an instance
@@ -282,54 +440,188 @@ using CSV::MatchP if CSV.const_defined?(:MatchP)
282
440
  # data = CSV.parse('Bob,Engineering,1000', headers: %i[name department salary])
283
441
  # data.first #=> #<CSV::Row name:"Bob" department:"Engineering" salary:"1000">
284
442
  #
285
- # == \CSV \Converters
286
- #
287
- # By default, each field parsed by \CSV is formed into a \String.
288
- # You can use a _converter_ to convert certain fields into other Ruby objects.
289
- #
290
- # When you specify a converter for parsing,
291
- # each parsed field is passed to the converter;
292
- # its return value becomes the new value for the field.
443
+ # === \Converters
444
+ #
445
+ # By default, each value (field or header) parsed by \CSV is formed into a \String.
446
+ # You can use a _field_ _converter_ or _header_ _converter_
447
+ # to intercept and modify the parsed values:
448
+ # - See {Field Converters}[#class-CSV-label-Field+Converters].
449
+ # - See {Header Converters}[#class-CSV-label-Header+Converters].
450
+ #
451
+ # Also by default, each value to be written during generation is written 'as-is'.
452
+ # You can use a _write_ _converter_ to modify values before writing.
453
+ # - See {Write Converters}[#class-CSV-label-Write+Converters].
454
+ #
455
+ # ==== Specifying \Converters
456
+ #
457
+ # You can specify converters for parsing or generating in the +options+
458
+ # argument to various \CSV methods:
459
+ # - Option +converters+ for converting parsed field values.
460
+ # - Option +header_converters+ for converting parsed header values.
461
+ # - Option +write_converters+ for converting values to be written (generated).
462
+ #
463
+ # There are three forms for specifying converters:
464
+ # - A converter proc: executable code to be used for conversion.
465
+ # - A converter name: the name of a stored converter.
466
+ # - A converter list: an array of converter procs, converter names, and converter lists.
467
+ #
468
+ # ===== Converter Procs
469
+ #
470
+ # This converter proc, +strip_converter+, accepts a value +field+
471
+ # and returns <tt>field.strip</tt>:
472
+ # strip_converter = proc {|field| field.strip }
473
+ # In this call to <tt>CSV.parse</tt>,
474
+ # the keyword argument <tt>converters: string_converter</tt>
475
+ # specifies that:
476
+ # - \Proc +string_converter+ is to be called for each parsed field.
477
+ # - The converter's return value is to replace the +field+ value.
478
+ # Example:
479
+ # string = " foo , 0 \n bar , 1 \n baz , 2 \n"
480
+ # array = CSV.parse(string, converters: strip_converter)
481
+ # array # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
482
+ #
483
+ # A converter proc can receive a second argument, +field_info+,
484
+ # that contains details about the field.
485
+ # This modified +strip_converter+ displays its arguments:
486
+ # strip_converter = proc do |field, field_info|
487
+ # p [field, field_info]
488
+ # field.strip
489
+ # end
490
+ # string = " foo , 0 \n bar , 1 \n baz , 2 \n"
491
+ # array = CSV.parse(string, converters: strip_converter)
492
+ # array # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
493
+ # Output:
494
+ # [" foo ", #<struct CSV::FieldInfo index=0, line=1, header=nil>]
495
+ # [" 0 ", #<struct CSV::FieldInfo index=1, line=1, header=nil>]
496
+ # [" bar ", #<struct CSV::FieldInfo index=0, line=2, header=nil>]
497
+ # [" 1 ", #<struct CSV::FieldInfo index=1, line=2, header=nil>]
498
+ # [" baz ", #<struct CSV::FieldInfo index=0, line=3, header=nil>]
499
+ # [" 2 ", #<struct CSV::FieldInfo index=1, line=3, header=nil>]
500
+ # Each CSV::Info object shows:
501
+ # - The 0-based field index.
502
+ # - The 1-based line index.
503
+ # - The field header, if any.
504
+ #
505
+ # ===== Stored \Converters
506
+ #
507
+ # A converter may be given a name and stored in a structure where
508
+ # the parsing methods can find it by name.
509
+ #
510
+ # The storage structure for field converters is the \Hash CSV::Converters.
511
+ # It has several built-in converter procs:
512
+ # - <tt>:integer</tt>: converts each \String-embedded integer into a true \Integer.
513
+ # - <tt>:float</tt>: converts each \String-embedded float into a true \Float.
514
+ # - <tt>:date</tt>: converts each \String-embedded date into a true \Date.
515
+ # - <tt>:date_time</tt>: converts each \String-embedded date-time into a true \DateTime
516
+ # .
517
+ # This example creates a converter proc, then stores it:
518
+ # strip_converter = proc {|field| field.strip }
519
+ # CSV::Converters[:strip] = strip_converter
520
+ # Then the parsing method call can refer to the converter
521
+ # by its name, <tt>:strip</tt>:
522
+ # string = " foo , 0 \n bar , 1 \n baz , 2 \n"
523
+ # array = CSV.parse(string, converters: :strip)
524
+ # array # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
525
+ #
526
+ # The storage structure for header converters is the \Hash CSV::HeaderConverters,
527
+ # which works in the same way.
528
+ # It also has built-in converter procs:
529
+ # - <tt>:downcase</tt>: Downcases each header.
530
+ # - <tt>:symbol</tt>: Converts each header to a \Symbol.
531
+ #
532
+ # There is no such storage structure for write headers.
533
+ #
534
+ # ===== Converter Lists
535
+ #
536
+ # A _converter_ _list_ is an \Array that may include any assortment of:
537
+ # - Converter procs.
538
+ # - Names of stored converters.
539
+ # - Nested converter lists.
540
+ #
541
+ # Examples:
542
+ # numeric_converters = [:integer, :float]
543
+ # date_converters = [:date, :date_time]
544
+ # [numeric_converters, strip_converter]
545
+ # [strip_converter, date_converters, :float]
546
+ #
547
+ # Like a converter proc, a converter list may be named and stored in either
548
+ # \CSV::Converters or CSV::HeaderConverters:
549
+ # CSV::Converters[:custom] = [strip_converter, date_converters, :float]
550
+ # CSV::HeaderConverters[:custom] = [:downcase, :symbol]
551
+ #
552
+ # There are two built-in converter lists:
553
+ # CSV::Converters[:numeric] # => [:integer, :float]
554
+ # CSV::Converters[:all] # => [:date_time, :numeric]
555
+ #
556
+ # ==== Field \Converters
557
+ #
558
+ # With no conversion, all parsed fields in all rows become Strings:
559
+ # string = "foo,0\nbar,1\nbaz,2\n"
560
+ # ary = CSV.parse(string)
561
+ # ary # => # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
562
+ #
563
+ # When you specify a field converter, each parsed field is passed to the converter;
564
+ # its return value becomes the stored value for the field.
293
565
  # A converter might, for example, convert an integer embedded in a \String
294
566
  # into a true \Integer.
295
567
  # (In fact, that's what built-in field converter +:integer+ does.)
296
568
  #
297
- # There are additional built-in \converters, and custom \converters are also supported.
298
- #
299
- # All \converters try to transcode fields to UTF-8 before converting.
300
- # The conversion will fail if the data cannot be transcoded, leaving the field unchanged.
301
- #
302
- # === Field \Converters
303
- #
304
- # There are three ways to use field \converters;
305
- # these examples use built-in field converter +:integer+,
306
- # which converts each parsed integer string to a true \Integer.
307
- #
308
- # Option +converters+ with a singleton parsing method:
309
- # ary = CSV.parse_line('0,1,2', converters: :integer)
310
- # ary # => [0, 1, 2]
311
- #
312
- # Option +converters+ with a new \CSV instance:
313
- # csv = CSV.new('0,1,2', converters: :integer)
314
- # # Field converters in effect:
315
- # csv.converters # => [:integer]
316
- # csv.shift # => [0, 1, 2]
317
- #
318
- # Method #convert adds a field converter to a \CSV instance:
319
- # csv = CSV.new('0,1,2')
569
+ # There are three ways to use field \converters.
570
+ #
571
+ # - Using option {converters}[#class-CSV-label-Option+converters] with a parsing method:
572
+ # ary = CSV.parse(string, converters: :integer)
573
+ # ary # => [0, 1, 2] # => [["foo", 0], ["bar", 1], ["baz", 2]]
574
+ # - Using option {converters}[#class-CSV-label-Option+converters] with a new \CSV instance:
575
+ # csv = CSV.new(string, converters: :integer)
576
+ # # Field converters in effect:
577
+ # csv.converters # => [:integer]
578
+ # csv.read # => [["foo", 0], ["bar", 1], ["baz", 2]]
579
+ # - Using method #convert to add a field converter to a \CSV instance:
580
+ # csv = CSV.new(string)
581
+ # # Add a converter.
582
+ # csv.convert(:integer)
583
+ # csv.converters # => [:integer]
584
+ # csv.read # => [["foo", 0], ["bar", 1], ["baz", 2]]
585
+ #
586
+ # Installing a field converter does not affect already-read rows:
587
+ # csv = CSV.new(string)
588
+ # csv.shift # => ["foo", "0"]
320
589
  # # Add a converter.
321
590
  # csv.convert(:integer)
322
591
  # csv.converters # => [:integer]
323
- # csv.shift # => [0, 1, 2]
592
+ # csv.read # => [["bar", 1], ["baz", 2]]
324
593
  #
325
- # ---
326
- #
327
- # The built-in field \converters are in \Hash CSV::Converters.
328
- # The \Symbol keys there are the names of the \converters:
329
- #
330
- # CSV::Converters.keys # => [:integer, :float, :numeric, :date, :date_time, :all]
594
+ # There are additional built-in \converters, and custom \converters are also supported.
331
595
  #
332
- # Converter +:integer+ converts each field that +Integer()+ accepts:
596
+ # ===== Built-In Field \Converters
597
+ #
598
+ # The built-in field converters are in \Hash CSV::Converters:
599
+ # - Each key is a field converter name.
600
+ # - Each value is one of:
601
+ # - A \Proc field converter.
602
+ # - An \Array of field converter names.
603
+ #
604
+ # Display:
605
+ # CSV::Converters.each_pair do |name, value|
606
+ # if value.kind_of?(Proc)
607
+ # p [name, value.class]
608
+ # else
609
+ # p [name, value]
610
+ # end
611
+ # end
612
+ # Output:
613
+ # [:integer, Proc]
614
+ # [:float, Proc]
615
+ # [:numeric, [:integer, :float]]
616
+ # [:date, Proc]
617
+ # [:date_time, Proc]
618
+ # [:all, [:date_time, :numeric]]
619
+ #
620
+ # Each of these converters transcodes values to UTF-8 before attempting conversion.
621
+ # If a value cannot be transcoded to UTF-8 the conversion will
622
+ # fail and the value will remain unconverted.
623
+ #
624
+ # Converter +:integer+ converts each field that Integer() accepts:
333
625
  # data = '0,1,2,x'
334
626
  # # Without the converter
335
627
  # csv = CSV.parse_line(data)
@@ -338,7 +630,7 @@ using CSV::MatchP if CSV.const_defined?(:MatchP)
338
630
  # csv = CSV.parse_line(data, converters: :integer)
339
631
  # csv # => [0, 1, 2, "x"]
340
632
  #
341
- # Converter +:float+ converts each field that +Float()+ accepts:
633
+ # Converter +:float+ converts each field that Float() accepts:
342
634
  # data = '1.0,3.14159,x'
343
635
  # # Without the converter
344
636
  # csv = CSV.parse_line(data)
@@ -349,7 +641,7 @@ using CSV::MatchP if CSV.const_defined?(:MatchP)
349
641
  #
350
642
  # Converter +:numeric+ converts with both +:integer+ and +:float+..
351
643
  #
352
- # Converter +:date+ converts each field that +Date::parse()+ accepts:
644
+ # Converter +:date+ converts each field that Date::parse accepts:
353
645
  # data = '2001-02-03,x'
354
646
  # # Without the converter
355
647
  # csv = CSV.parse_line(data)
@@ -358,7 +650,7 @@ using CSV::MatchP if CSV.const_defined?(:MatchP)
358
650
  # csv = CSV.parse_line(data, converters: :date)
359
651
  # csv # => [#<Date: 2001-02-03 ((2451944j,0s,0n),+0s,2299161j)>, "x"]
360
652
  #
361
- # Converter +:date_time+ converts each field that +DateTime::parse() accepts:
653
+ # Converter +:date_time+ converts each field that DateTime::parse accepts:
362
654
  # data = '2020-05-07T14:59:00-05:00,x'
363
655
  # # Without the converter
364
656
  # csv = CSV.parse_line(data)
@@ -378,19 +670,18 @@ using CSV::MatchP if CSV.const_defined?(:MatchP)
378
670
  # csv.convert(:date)
379
671
  # csv.converters # => [:integer, :date]
380
672
  #
381
- # You can add a custom field converter to \Hash CSV::Converters:
382
- # strip_converter = proc {|field| field.strip}
383
- # CSV::Converters[:strip] = strip_converter
384
- # CSV::Converters.keys # => [:integer, :float, :numeric, :date, :date_time, :all, :strip]
385
- #
386
- # Then use it to convert fields:
387
- # str = ' foo , 0 '
388
- # ary = CSV.parse_line(str, converters: :strip)
389
- # ary # => ["foo", "0"]
673
+ # ===== Custom Field \Converters
390
674
  #
391
- # See {Custom Converters}[#class-CSV-label-Custom+Converters].
675
+ # You can define a custom field converter:
676
+ # strip_converter = proc {|field| field.strip }
677
+ # Add it to the \Converters \Hash:
678
+ # CSV::Converters[:strip] = strip_converter
679
+ # Use it by name:
680
+ # string = " foo , 0 \n bar , 1 \n baz , 2 \n"
681
+ # array = CSV.parse(string, converters: strip_converter)
682
+ # array # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
392
683
  #
393
- # === Header \Converters
684
+ # ==== Header \Converters
394
685
  #
395
686
  # Header converters operate only on headers (and not on other rows).
396
687
  #
@@ -398,43 +689,42 @@ using CSV::MatchP if CSV.const_defined?(:MatchP)
398
689
  # these examples use built-in header converter +:dowhcase+,
399
690
  # which downcases each parsed header.
400
691
  #
401
- # Option +header_converters+ with a singleton parsing method:
402
- # str = "Name,Count\nFoo,0\n,Bar,1\nBaz,2"
403
- # tbl = CSV.parse(str, headers: true, header_converters: :downcase)
404
- # tbl.class # => CSV::Table
405
- # tbl.headers # => ["name", "count"]
406
- #
407
- # Option +header_converters+ with a new \CSV instance:
408
- # csv = CSV.new(str, header_converters: :downcase)
409
- # # Header converters in effect:
410
- # csv.header_converters # => [:downcase]
411
- # tbl = CSV.parse(str, headers: true)
412
- # tbl.headers # => ["Name", "Count"]
413
- #
414
- # Method #header_convert adds a header converter to a \CSV instance:
415
- # csv = CSV.new(str)
416
- # # Add a header converter.
417
- # csv.header_convert(:downcase)
418
- # csv.header_converters # => [:downcase]
419
- # tbl = CSV.parse(str, headers: true)
420
- # tbl.headers # => ["Name", "Count"]
421
- #
422
- # ---
423
- #
424
- # The built-in header \converters are in \Hash CSV::Converters.
425
- # The \Symbol keys there are the names of the \converters:
426
- #
692
+ # - Option +header_converters+ with a singleton parsing method:
693
+ # string = "Name,Count\nFoo,0\n,Bar,1\nBaz,2"
694
+ # tbl = CSV.parse(string, headers: true, header_converters: :downcase)
695
+ # tbl.class # => CSV::Table
696
+ # tbl.headers # => ["name", "count"]
697
+ #
698
+ # - Option +header_converters+ with a new \CSV instance:
699
+ # csv = CSV.new(string, header_converters: :downcase)
700
+ # # Header converters in effect:
701
+ # csv.header_converters # => [:downcase]
702
+ # tbl = CSV.parse(string, headers: true)
703
+ # tbl.headers # => ["Name", "Count"]
704
+ #
705
+ # - Method #header_convert adds a header converter to a \CSV instance:
706
+ # csv = CSV.new(string)
707
+ # # Add a header converter.
708
+ # csv.header_convert(:downcase)
709
+ # csv.header_converters # => [:downcase]
710
+ # tbl = CSV.parse(string, headers: true)
711
+ # tbl.headers # => ["Name", "Count"]
712
+ #
713
+ # ===== Built-In Header \Converters
714
+ #
715
+ # The built-in header \converters are in \Hash CSV::HeaderConverters.
716
+ # The keys there are the names of the \converters:
427
717
  # CSV::HeaderConverters.keys # => [:downcase, :symbol]
428
718
  #
429
719
  # Converter +:downcase+ converts each header by downcasing it:
430
- # str = "Name,Count\nFoo,0\n,Bar,1\nBaz,2"
431
- # tbl = CSV.parse(str, headers: true, header_converters: :downcase)
720
+ # string = "Name,Count\nFoo,0\n,Bar,1\nBaz,2"
721
+ # tbl = CSV.parse(string, headers: true, header_converters: :downcase)
432
722
  # tbl.class # => CSV::Table
433
723
  # tbl.headers # => ["name", "count"]
434
724
  #
435
- # Converter +:symbol+ by making it into a \Symbol:
436
- # str = "Name,Count\nFoo,0\n,Bar,1\nBaz,2"
437
- # tbl = CSV.parse(str, headers: true, header_converters: :symbol)
725
+ # Converter +:symbol+ converts each header by making it into a \Symbol:
726
+ # string = "Name,Count\nFoo,0\n,Bar,1\nBaz,2"
727
+ # tbl = CSV.parse(string, headers: true, header_converters: :symbol)
438
728
  # tbl.headers # => [:name, :count]
439
729
  # Details:
440
730
  # - Strips leading and trailing whitespace.
@@ -443,46 +733,44 @@ using CSV::MatchP if CSV.const_defined?(:MatchP)
443
733
  # - Removes non-word characters.
444
734
  # - Makes the string into a \Symbol.
445
735
  #
446
- # You can add a custom header converter to \Hash CSV::HeaderConverters:
447
- # strip_converter = proc {|field| field.strip}
448
- # CSV::HeaderConverters[:strip] = strip_converter
449
- # CSV::HeaderConverters.keys # => [:downcase, :symbol, :strip]
450
- #
451
- # Then use it to convert headers:
452
- # str = " Name , Value \nfoo,0\nbar,1\nbaz,2"
453
- # tbl = CSV.parse(str, headers: true, header_converters: :strip)
454
- # tbl.headers # => ["Name", "Value"]
455
- #
456
- # See {Custom Converters}[#class-CSV-label-Custom+Converters].
457
- #
458
- # === Custom \Converters
459
- #
460
- # You can define custom \converters.
461
- #
462
- # The \converter is a \Proc that is called with two arguments,
463
- # \String +field+ and CSV::FieldInfo +field_info+;
464
- # it returns a \String that will become the field value:
465
- # converter = proc {|field, field_info| <some_string> }
736
+ # ===== Custom Header \Converters
466
737
  #
467
- # To illustrate:
468
- # converter = proc {|field, field_info| p [field, field_info]; field}
469
- # ary = CSV.parse_line('foo,0', converters: converter)
738
+ # You can define a custom header converter:
739
+ # upcase_converter = proc {|header| header.upcase }
740
+ # Add it to the \HeaderConverters \Hash:
741
+ # CSV::HeaderConverters[:upcase] = upcase_converter
742
+ # Use it by name:
743
+ # string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
744
+ # table = CSV.parse(string, headers: true, converters: upcase_converter)
745
+ # table # => #<CSV::Table mode:col_or_row row_count:4>
746
+ # table.headers # => ["Name", "Value"]
470
747
  #
471
- # Produces:
472
- # ["foo", #<struct CSV::FieldInfo index=0, line=1, header=nil>]
473
- # ["0", #<struct CSV::FieldInfo index=1, line=1, header=nil>]
748
+ # ===== Write \Converters
474
749
  #
475
- # In each of the output lines:
476
- # - The first \Array element is the passed \String field.
477
- # - The second is a \FieldInfo structure containing information about the field:
478
- # - The 0-based column index.
479
- # - The 1-based line number.
480
- # - The header for the column, if available.
481
- #
482
- # If the \converter does not need +field_info+, it can be omitted:
483
- # converter = proc {|field| ... }
484
- #
485
- # == CSV and Character Encodings (M17n or Multilingualization)
750
+ # When you specify a write converter for generating \CSV,
751
+ # each field to be written is passed to the converter;
752
+ # its return value becomes the new value for the field.
753
+ # A converter might, for example, strip whitespace from a field.
754
+ #
755
+ # - Using no write converter (all fields unmodified):
756
+ # output_string = CSV.generate do |csv|
757
+ # csv << [' foo ', 0]
758
+ # csv << [' bar ', 1]
759
+ # csv << [' baz ', 2]
760
+ # end
761
+ # output_string # => " foo ,0\n bar ,1\n baz ,2\n"
762
+ # - Using option +write_converters+:
763
+ # strip_converter = proc {|field| field.respond_to?(:strip) ? field.strip : field }
764
+ # upcase_converter = proc {|field| field.respond_to?(:upcase) ? field.upcase : field }
765
+ # converters = [strip_converter, upcase_converter]
766
+ # output_string = CSV.generate(write_converters: converters) do |csv|
767
+ # csv << [' foo ', 0]
768
+ # csv << [' bar ', 1]
769
+ # csv << [' baz ', 2]
770
+ # end
771
+ # output_string # => "FOO,0\nBAR,1\nBAZ,2\n"
772
+ #
773
+ # === Character Encodings (M17n or Multilingualization)
486
774
  #
487
775
  # This new CSV parser is m17n savvy. The parser works in the Encoding of the IO
488
776
  # or String object being read from or written to. Your data is never transcoded
@@ -563,30 +851,12 @@ class CSV
563
851
  # The encoding used by all converters.
564
852
  ConverterEncoding = Encoding.find("UTF-8")
565
853
 
854
+ # A \Hash containing the names and \Procs for the built-in field converters.
855
+ # See {Built-In Field Converters}[#class-CSV-label-Built-In+Field+Converters].
566
856
  #
567
- # This Hash holds the built-in converters of CSV that can be accessed by name.
568
- # You can select Converters with CSV.convert() or through the +options+ Hash
569
- # passed to CSV::new().
570
- #
571
- # <b><tt>:integer</tt></b>:: Converts any field Integer() accepts.
572
- # <b><tt>:float</tt></b>:: Converts any field Float() accepts.
573
- # <b><tt>:numeric</tt></b>:: A combination of <tt>:integer</tt>
574
- # and <tt>:float</tt>.
575
- # <b><tt>:date</tt></b>:: Converts any field Date::parse() accepts.
576
- # <b><tt>:date_time</tt></b>:: Converts any field DateTime::parse() accepts.
577
- # <b><tt>:all</tt></b>:: All built-in converters. A combination of
578
- # <tt>:date_time</tt> and <tt>:numeric</tt>.
579
- #
580
- # All built-in converters transcode field data to UTF-8 before attempting a
581
- # conversion. If your data cannot be transcoded to UTF-8 the conversion will
582
- # fail and the field will remain unchanged.
583
- #
584
- # This Hash is intentionally left unfrozen and users should feel free to add
585
- # values to it that can be accessed by all CSV objects.
586
- #
587
- # To add a combo field, the value should be an Array of names. Combo fields
588
- # can be nested with other combo fields.
589
- #
857
+ # This \Hash is intentionally left unfrozen, and may be extended with
858
+ # custom field converters.
859
+ # See {Custom Field Converters}[#class-CSV-label-Custom+Field+Converters].
590
860
  Converters = {
591
861
  integer: lambda { |f|
592
862
  Integer(f.encode(ConverterEncoding)) rescue f
@@ -614,27 +884,12 @@ class CSV
614
884
  all: [:date_time, :numeric],
615
885
  }
616
886
 
887
+ # A \Hash containing the names and \Procs for the built-in header converters.
888
+ # See {Built-In Header Converters}[#class-CSV-label-Built-In+Header+Converters].
617
889
  #
618
- # This Hash holds the built-in header converters of CSV that can be accessed
619
- # by name. You can select HeaderConverters with CSV.header_convert() or
620
- # through the +options+ Hash passed to CSV::new().
621
- #
622
- # <b><tt>:downcase</tt></b>:: Calls downcase() on the header String.
623
- # <b><tt>:symbol</tt></b>:: Leading/trailing spaces are dropped, string is
624
- # downcased, remaining spaces are replaced with
625
- # underscores, non-word characters are dropped,
626
- # and finally to_sym() is called.
627
- #
628
- # All built-in header converters transcode header data to UTF-8 before
629
- # attempting a conversion. If your data cannot be transcoded to UTF-8 the
630
- # conversion will fail and the header will remain unchanged.
631
- #
632
- # This Hash is intentionally left unfrozen and users should feel free to add
633
- # values to it that can be accessed by all CSV objects.
634
- #
635
- # To add a combo field, the value should be an Array of names. Combo fields
636
- # can be nested with other combo fields.
637
- #
890
+ # This \Hash is intentionally left unfrozen, and may be extended with
891
+ # custom field converters.
892
+ # See {Custom Header Converters}[#class-CSV-label-Custom+Header+Converters].
638
893
  HeaderConverters = {
639
894
  downcase: lambda { |h| h.encode(ConverterEncoding).downcase },
640
895
  symbol: lambda { |h|
@@ -671,18 +926,47 @@ class CSV
671
926
  }.freeze
672
927
 
673
928
  class << self
929
+ # :call-seq:
930
+ # instance(string, **options)
931
+ # instance(io = $stdout, **options)
932
+ # instance(string, **options) {|csv| ... }
933
+ # instance(io = $stdout, **options) {|csv| ... }
674
934
  #
675
- # This method will return a CSV instance, just like CSV::new(), but the
676
- # instance will be cached and returned for all future calls to this method for
677
- # the same +data+ object (tested by Object#object_id()) with the same
678
- # +options+.
935
+ # Creates or retrieves cached \CSV objects.
936
+ # For arguments and options, see CSV.new.
679
937
  #
680
- # See {Options for Parsing}[#class-CSV-label-Options+for+Parsing]
681
- # and {Options for Generating}[#class-CSV-label-Options+for+Generating].
938
+ # ---
682
939
  #
683
- # If a block is given, the instance is passed to the block and the return
684
- # value becomes the return value of the block.
940
+ # With no block given, returns a \CSV object.
685
941
  #
942
+ # The first call to +instance+ creates and caches a \CSV object:
943
+ # s0 = 's0'
944
+ # csv0 = CSV.instance(s0)
945
+ # csv0.class # => CSV
946
+ #
947
+ # Subsequent calls to +instance+ with that _same_ +string+ or +io+
948
+ # retrieve that same cached object:
949
+ # csv1 = CSV.instance(s0)
950
+ # csv1.class # => CSV
951
+ # csv1.equal?(csv0) # => true # Same CSV object
952
+ #
953
+ # A subsequent call to +instance+ with a _different_ +string+ or +io+
954
+ # creates and caches a _different_ \CSV object.
955
+ # s1 = 's1'
956
+ # csv2 = CSV.instance(s1)
957
+ # csv2.equal?(csv0) # => false # Different CSV object
958
+ #
959
+ # All the cached objects remains available:
960
+ # csv3 = CSV.instance(s0)
961
+ # csv3.equal?(csv0) # true # Same CSV object
962
+ # csv4 = CSV.instance(s1)
963
+ # csv4.equal?(csv2) # true # Same CSV object
964
+ #
965
+ # ---
966
+ #
967
+ # When a block is given, calls the block with the created or retrieved
968
+ # \CSV object; returns the block's return value:
969
+ # CSV.instance(s0) {|csv| :foo } # => :foo
686
970
  def instance(data = $stdout, **options)
687
971
  # create a _signature_ for this method call, data object and options
688
972
  sig = [data.object_id] +
@@ -699,33 +983,61 @@ class CSV
699
983
  end
700
984
  end
701
985
 
702
- #
703
986
  # :call-seq:
704
- # filter( **options ) { |row| ... }
705
- # filter( input, **options ) { |row| ... }
706
- # filter( input, output, **options ) { |row| ... }
987
+ # filter(**options) {|row| ... }
988
+ # filter(in_string, **options) {|row| ... }
989
+ # filter(in_io, **options) {|row| ... }
990
+ # filter(in_string, out_string, **options) {|row| ... }
991
+ # filter(in_string, out_io, **options) {|row| ... }
992
+ # filter(in_io, out_string, **options) {|row| ... }
993
+ # filter(in_io, out_io, **options) {|row| ... }
707
994
  #
708
- # This method is a convenience for building Unix-like filters for CSV data.
709
- # Each row is yielded to the provided block which can alter it as needed.
710
- # After the block returns, the row is appended to +output+ altered or not.
995
+ # Reads \CSV input and writes \CSV output.
711
996
  #
712
- # The +input+ and +output+ arguments can be anything CSV::new() accepts
713
- # (generally String or IO objects). If not given, they default to
714
- # <tt>ARGF</tt> and <tt>$stdout</tt>.
997
+ # For each input row:
998
+ # - Forms the data into:
999
+ # - A CSV::Row object, if headers are in use.
1000
+ # - An \Array of Arrays, otherwise.
1001
+ # - Calls the block with that object.
1002
+ # - Appends the block's return value to the output.
715
1003
  #
716
- # The +options+ parameter is also filtered down to CSV::new() after some
717
- # clever key parsing. Any key beginning with <tt>:in_</tt> or
718
- # <tt>:input_</tt> will have that leading identifier stripped and will only
719
- # be used in the +options+ Hash for the +input+ object. Keys starting with
720
- # <tt>:out_</tt> or <tt>:output_</tt> affect only +output+. All other keys
721
- # are assigned to both objects.
722
- #
723
- # See {Options for Parsing}[#class-CSV-label-Options+for+Parsing]
724
- # and {Options for Generating}[#class-CSV-label-Options+for+Generating].
725
- #
726
- # The <tt>:output_row_sep</tt> +option+ defaults to
727
- # <tt>$INPUT_RECORD_SEPARATOR</tt> (<tt>$/</tt>).
1004
+ # Arguments:
1005
+ # * \CSV source:
1006
+ # * Argument +in_string+, if given, should be a \String object;
1007
+ # it will be put into a new StringIO object positioned at the beginning.
1008
+ # * Argument +in_io+, if given, should be an IO object that is
1009
+ # open for reading; on return, the IO object will be closed.
1010
+ # * If neither +in_string+ nor +in_io+ is given,
1011
+ # the input stream defaults to {ARGF}[https://ruby-doc.org/core/ARGF.html].
1012
+ # * \CSV output:
1013
+ # * Argument +out_string+, if given, should be a \String object;
1014
+ # it will be put into a new StringIO object positioned at the beginning.
1015
+ # * Argument +out_io+, if given, should be an IO object that is
1016
+ # ppen for writing; on return, the IO object will be closed.
1017
+ # * If neither +out_string+ nor +out_io+ is given,
1018
+ # the output stream defaults to <tt>$stdout</tt>.
1019
+ # * Argument +options+ should be keyword arguments.
1020
+ # - Each argument name that is prefixed with +in_+ or +input_+
1021
+ # is stripped of its prefix and is treated as an option
1022
+ # for parsing the input.
1023
+ # Option +input_row_sep+ defaults to <tt>$INPUT_RECORD_SEPARATOR</tt>.
1024
+ # - Each argument name that is prefixed with +out_+ or +output_+
1025
+ # is stripped of its prefix and is treated as an option
1026
+ # for generating the output.
1027
+ # Option +output_row_sep+ defaults to <tt>$INPUT_RECORD_SEPARATOR</tt>.
1028
+ # - Each argument not prefixed as above is treated as an option
1029
+ # both for parsing the input and for generating the output.
1030
+ # - See {Options for Parsing}[#class-CSV-label-Options+for+Parsing]
1031
+ # and {Options for Generating}[#class-CSV-label-Options+for+Generating].
728
1032
  #
1033
+ # Example:
1034
+ # in_string = "foo,0\nbar,1\nbaz,2\n"
1035
+ # out_string = ''
1036
+ # CSV.filter(in_string, out_string) do |row|
1037
+ # row[0] = row[0].upcase
1038
+ # row[1] *= 4
1039
+ # end
1040
+ # out_string # => "FOO,0000\nBAR,1111\nBAZ,2222\n"
729
1041
  def filter(input=nil, output=nil, **options)
730
1042
  # parse options for input, output, or both
731
1043
  in_options, out_options = Hash.new, {row_sep: $INPUT_RECORD_SEPARATOR}
@@ -752,20 +1064,111 @@ class CSV
752
1064
  end
753
1065
 
754
1066
  #
755
- # This method is intended as the primary interface for reading CSV files. You
756
- # pass a +path+ and any +options+ you wish to set for the read. Each row of
757
- # file will be passed to the provided +block+ in turn.
1067
+ # :call-seq:
1068
+ # foreach(path, mode='r', **options) {|row| ... )
1069
+ # foreach(io, mode='r', **options {|row| ... )
1070
+ # foreach(path, mode='r', headers: ..., **options) {|row| ... )
1071
+ # foreach(io, mode='r', headers: ..., **options {|row| ... )
1072
+ # foreach(path, mode='r', **options) -> new_enumerator
1073
+ # foreach(io, mode='r', **options -> new_enumerator
1074
+ #
1075
+ # Calls the block with each row read from source +path+ or +io+.
1076
+ #
1077
+ # * Argument +path+, if given, must be the path to a file.
1078
+ # :include: ../doc/arguments/io.rdoc
1079
+ # * Argument +mode+, if given, must be a \File mode
1080
+ # See {Open Mode}[IO.html#method-c-new-label-Open+Mode].
1081
+ # * Arguments <tt>**options</tt> must be keyword options.
1082
+ # See {Options for Parsing}[#class-CSV-label-Options+for+Parsing].
1083
+ # * This method optionally accepts an additional <tt>:encoding</tt> option
1084
+ # that you can use to specify the Encoding of the data read from +path+ or +io+.
1085
+ # You must provide this unless your data is in the encoding
1086
+ # given by <tt>Encoding::default_external</tt>.
1087
+ # Parsing will use this to determine how to parse the data.
1088
+ # You may provide a second Encoding to
1089
+ # have the data transcoded as it is read. For example,
1090
+ # encoding: 'UTF-32BE:UTF-8'
1091
+ # would read +UTF-32BE+ data from the file
1092
+ # but transcode it to +UTF-8+ before parsing.
1093
+ #
1094
+ # ====== Without Option +headers+
1095
+ #
1096
+ # Without option +headers+, returns each row as an \Array object.
1097
+ #
1098
+ # These examples assume prior execution of:
1099
+ # string = "foo,0\nbar,1\nbaz,2\n"
1100
+ # path = 't.csv'
1101
+ # File.write(path, string)
1102
+ #
1103
+ # Read rows from a file at +path+:
1104
+ # CSV.foreach(path) {|row| p row }
1105
+ # Output:
1106
+ # ["foo", "0"]
1107
+ # ["bar", "1"]
1108
+ # ["baz", "2"]
1109
+ #
1110
+ # Read rows from an \IO object:
1111
+ # File.open(path) do |file|
1112
+ # CSV.foreach(file) {|row| p row }
1113
+ # end
1114
+ #
1115
+ # Output:
1116
+ # ["foo", "0"]
1117
+ # ["bar", "1"]
1118
+ # ["baz", "2"]
1119
+ #
1120
+ # Returns a new \Enumerator if no block given:
1121
+ # CSV.foreach(path) # => #<Enumerator: CSV:foreach("t.csv", "r")>
1122
+ # CSV.foreach(File.open(path)) # => #<Enumerator: CSV:foreach(#<File:t.csv>, "r")>
1123
+ #
1124
+ # Issues a warning if an encoding is unsupported:
1125
+ # CSV.foreach(File.open(path), encoding: 'foo:bar') {|row| }
1126
+ # Output:
1127
+ # warning: Unsupported encoding foo ignored
1128
+ # warning: Unsupported encoding bar ignored
1129
+ #
1130
+ # ====== With Option +headers+
1131
+ #
1132
+ # With {option +headers+}[#class-CSV-label-Option+headers],
1133
+ # returns each row as a CSV::Row object.
758
1134
  #
759
- # See {Options for Parsing}[#class-CSV-label-Options+for+Parsing].
1135
+ # These examples assume prior execution of:
1136
+ # string = "Name,Count\nfoo,0\nbar,1\nbaz,2\n"
1137
+ # path = 't.csv'
1138
+ # File.write(path, string)
760
1139
  #
761
- # The +options+ parameter can be anything CSV::new() understands. This method
762
- # also understands an additional <tt>:encoding</tt> parameter that you can use
763
- # to specify the Encoding of the data in the file to be read. You must provide
764
- # this unless your data is in Encoding::default_external(). CSV will use this
765
- # to determine how to parse the data. You may provide a second Encoding to
766
- # have the data transcoded as it is read. For example,
767
- # <tt>encoding: "UTF-32BE:UTF-8"</tt> would read UTF-32BE data from the file
768
- # but transcode it to UTF-8 before CSV parses it.
1140
+ # Read rows from a file at +path+:
1141
+ # CSV.foreach(path, headers: true) {|row| p row }
1142
+ #
1143
+ # Output:
1144
+ # #<CSV::Row "Name":"foo" "Count":"0">
1145
+ # #<CSV::Row "Name":"bar" "Count":"1">
1146
+ # #<CSV::Row "Name":"baz" "Count":"2">
1147
+ #
1148
+ # Read rows from an \IO object:
1149
+ # File.open(path) do |file|
1150
+ # CSV.foreach(file, headers: true) {|row| p row }
1151
+ # end
1152
+ #
1153
+ # Output:
1154
+ # #<CSV::Row "Name":"foo" "Count":"0">
1155
+ # #<CSV::Row "Name":"bar" "Count":"1">
1156
+ # #<CSV::Row "Name":"baz" "Count":"2">
1157
+ #
1158
+ # ---
1159
+ #
1160
+ # Raises an exception if +path+ is a \String, but not the path to a readable file:
1161
+ # # Raises Errno::ENOENT (No such file or directory @ rb_sysopen - nosuch.csv):
1162
+ # CSV.foreach('nosuch.csv') {|row| }
1163
+ #
1164
+ # Raises an exception if +io+ is an \IO object, but not open for reading:
1165
+ # io = File.open(path, 'w') {|row| }
1166
+ # # Raises TypeError (no implicit conversion of nil into String):
1167
+ # CSV.foreach(io) {|row| }
1168
+ #
1169
+ # Raises an exception if +mode+ is invalid:
1170
+ # # Raises ArgumentError (invalid access mode nosuch):
1171
+ # CSV.foreach(path, 'nosuch') {|row| }
769
1172
  #
770
1173
  def foreach(path, mode="r", **options, &block)
771
1174
  return to_enum(__method__, path, mode, **options) unless block_given?
@@ -776,23 +1179,63 @@ class CSV
776
1179
 
777
1180
  #
778
1181
  # :call-seq:
779
- # generate( str, **options ) { |csv| ... }
780
- # generate( **options ) { |csv| ... }
1182
+ # generate(csv_string, **options) {|csv| ... }
1183
+ # generate(**options) {|csv| ... }
781
1184
  #
782
- # This method wraps a String you provide, or an empty default String, in a
783
- # CSV object which is passed to the provided block. You can use the block to
784
- # append CSV rows to the String and when the block exits, the final String
785
- # will be returned.
1185
+ # * Argument +csv_string+, if given, must be a \String object;
1186
+ # defaults to a new empty \String.
1187
+ # * Arguments +options+, if given, should be generating options.
1188
+ # See {Options for Generating}[#class-CSV-label-Options+for+Generating].
786
1189
  #
787
- # Note that a passed String *is* modified by this method. Call dup() before
788
- # passing if you need a new String.
1190
+ # ---
1191
+ #
1192
+ # Creates a new \CSV object via <tt>CSV.new(csv_string, **options)</tt>;
1193
+ # calls the block with the \CSV object, which the block may modify;
1194
+ # returns the \String generated from the \CSV object.
789
1195
  #
790
- # See {Options for Generating}[#class-CSV-label-Options+for+Generating].
1196
+ # Note that a passed \String *is* modified by this method.
1197
+ # Pass <tt>csv_string</tt>.dup if the \String must be preserved.
791
1198
  #
792
1199
  # This method has one additional option: <tt>:encoding</tt>,
793
1200
  # which sets the base Encoding for the output if no no +str+ is specified.
794
1201
  # CSV needs this hint if you plan to output non-ASCII compatible data.
795
1202
  #
1203
+ # ---
1204
+ #
1205
+ # Add lines:
1206
+ # input_string = "foo,0\nbar,1\nbaz,2\n"
1207
+ # output_string = CSV.generate(input_string) do |csv|
1208
+ # csv << ['bat', 3]
1209
+ # csv << ['bam', 4]
1210
+ # end
1211
+ # output_string # => "foo,0\nbar,1\nbaz,2\nbat,3\nbam,4\n"
1212
+ # input_string # => "foo,0\nbar,1\nbaz,2\nbat,3\nbam,4\n"
1213
+ # output_string.equal?(input_string) # => true # Same string, modified
1214
+ #
1215
+ # Add lines into new string, preserving old string:
1216
+ # input_string = "foo,0\nbar,1\nbaz,2\n"
1217
+ # output_string = CSV.generate(input_string.dup) do |csv|
1218
+ # csv << ['bat', 3]
1219
+ # csv << ['bam', 4]
1220
+ # end
1221
+ # output_string # => "foo,0\nbar,1\nbaz,2\nbat,3\nbam,4\n"
1222
+ # input_string # => "foo,0\nbar,1\nbaz,2\n"
1223
+ # output_string.equal?(input_string) # => false # Different strings
1224
+ #
1225
+ # Create lines from nothing:
1226
+ # output_string = CSV.generate do |csv|
1227
+ # csv << ['foo', 0]
1228
+ # csv << ['bar', 1]
1229
+ # csv << ['baz', 2]
1230
+ # end
1231
+ # output_string # => "foo,0\nbar,1\nbaz,2\n"
1232
+ #
1233
+ # ---
1234
+ #
1235
+ # Raises an exception if +csv_string+ is not a \String object:
1236
+ # # Raises TypeError (no implicit conversion of Integer into String)
1237
+ # CSV.generate(0)
1238
+ #
796
1239
  def generate(str=nil, **options)
797
1240
  encoding = options[:encoding]
798
1241
  # add a default empty String, if none was given
@@ -846,80 +1289,103 @@ class CSV
846
1289
  str = +""
847
1290
  if options[:encoding]
848
1291
  str.force_encoding(options[:encoding])
849
- elsif field = row.find {|f| f.is_a?(String)}
850
- str.force_encoding(field.encoding)
1292
+ else
1293
+ fallback_encoding = nil
1294
+ output_encoding = nil
1295
+ row.each do |field|
1296
+ next unless field.is_a?(String)
1297
+ fallback_encoding ||= field.encoding
1298
+ next if field.ascii_only?
1299
+ output_encoding = field.encoding
1300
+ break
1301
+ end
1302
+ output_encoding ||= fallback_encoding
1303
+ if output_encoding
1304
+ str.force_encoding(output_encoding)
1305
+ end
851
1306
  end
852
1307
  (new(str, **options) << row).string
853
1308
  end
854
1309
 
855
1310
  #
856
1311
  # :call-seq:
857
- # open( filename, mode = "rb", **options ) { |faster_csv| ... }
858
- # open( filename, **options ) { |faster_csv| ... }
859
- # open( filename, mode = "rb", **options )
860
- # open( filename, **options )
861
- #
862
- # This method opens an IO object, and wraps that with CSV. This is intended
863
- # as the primary interface for writing a CSV file.
864
- #
865
- # You must pass a +filename+ and may optionally add a +mode+ for Ruby's
866
- # open().
867
- #
868
- # See {Options for Generating}[#class-CSV-label-Options+for+Generating].
869
- #
870
- # This method works like Ruby's open() call, in that it will pass a CSV object
871
- # to a provided block and close it when the block terminates, or it will
872
- # return the CSV object when no block is provided. (*Note*: This is different
873
- # from the Ruby 1.8 CSV library which passed rows to the block. Use
874
- # CSV::foreach() for that behavior.)
875
- #
876
- # You must provide a +mode+ with an embedded Encoding designator unless your
877
- # data is in Encoding::default_external(). CSV will check the Encoding of the
878
- # underlying IO object (set by the +mode+ you pass) to determine how to parse
879
- # the data. You may provide a second Encoding to have the data transcoded as
880
- # it is read just as you can with a normal call to IO::open(). For example,
881
- # <tt>"rb:UTF-32BE:UTF-8"</tt> would read UTF-32BE data from the file but
882
- # transcode it to UTF-8 before CSV parses it.
883
- #
884
- # An opened CSV object will delegate to many IO methods for convenience. You
885
- # may call:
886
- #
887
- # * binmode()
888
- # * binmode?()
889
- # * close()
890
- # * close_read()
891
- # * close_write()
892
- # * closed?()
893
- # * eof()
894
- # * eof?()
895
- # * external_encoding()
896
- # * fcntl()
897
- # * fileno()
898
- # * flock()
899
- # * flush()
900
- # * fsync()
901
- # * internal_encoding()
902
- # * ioctl()
903
- # * isatty()
904
- # * path()
905
- # * pid()
906
- # * pos()
907
- # * pos=()
908
- # * reopen()
909
- # * seek()
910
- # * stat()
911
- # * sync()
912
- # * sync=()
913
- # * tell()
914
- # * to_i()
915
- # * to_io()
916
- # * truncate()
917
- # * tty?()
1312
+ # open(file_path, mode = "rb", **options ) -> new_csv
1313
+ # open(io, mode = "rb", **options ) -> new_csv
1314
+ # open(file_path, mode = "rb", **options ) { |csv| ... } -> object
1315
+ # open(io, mode = "rb", **options ) { |csv| ... } -> object
1316
+ #
1317
+ # possible options elements:
1318
+ # hash form:
1319
+ # :invalid => nil # raise error on invalid byte sequence (default)
1320
+ # :invalid => :replace # replace invalid byte sequence
1321
+ # :undef => :replace # replace undefined conversion
1322
+ # :replace => string # replacement string ("?" or "\uFFFD" if not specified)
1323
+ #
1324
+ # * Argument +path+, if given, must be the path to a file.
1325
+ # :include: ../doc/arguments/io.rdoc
1326
+ # * Argument +mode+, if given, must be a \File mode
1327
+ # See {Open Mode}[IO.html#method-c-new-label-Open+Mode].
1328
+ # * Arguments <tt>**options</tt> must be keyword options.
1329
+ # See {Options for Generating}[#class-CSV-label-Options+for+Generating].
1330
+ # * This method optionally accepts an additional <tt>:encoding</tt> option
1331
+ # that you can use to specify the Encoding of the data read from +path+ or +io+.
1332
+ # You must provide this unless your data is in the encoding
1333
+ # given by <tt>Encoding::default_external</tt>.
1334
+ # Parsing will use this to determine how to parse the data.
1335
+ # You may provide a second Encoding to
1336
+ # have the data transcoded as it is read. For example,
1337
+ # encoding: 'UTF-32BE:UTF-8'
1338
+ # would read +UTF-32BE+ data from the file
1339
+ # but transcode it to +UTF-8+ before parsing.
1340
+ #
1341
+ # ---
1342
+ #
1343
+ # These examples assume prior execution of:
1344
+ # string = "foo,0\nbar,1\nbaz,2\n"
1345
+ # path = 't.csv'
1346
+ # File.write(path, string)
1347
+ #
1348
+ # ---
1349
+ #
1350
+ # With no block given, returns a new \CSV object.
918
1351
  #
1352
+ # Create a \CSV object using a file path:
1353
+ # csv = CSV.open(path)
1354
+ # csv # => #<CSV io_type:File io_path:"t.csv" encoding:UTF-8 lineno:0 col_sep:"," row_sep:"\n" quote_char:"\"">
1355
+ #
1356
+ # Create a \CSV object using an open \File:
1357
+ # csv = CSV.open(File.open(path))
1358
+ # csv # => #<CSV io_type:File io_path:"t.csv" encoding:UTF-8 lineno:0 col_sep:"," row_sep:"\n" quote_char:"\"">
1359
+ #
1360
+ # ---
1361
+ #
1362
+ # With a block given, calls the block with the created \CSV object;
1363
+ # returns the block's return value:
1364
+ #
1365
+ # Using a file path:
1366
+ # csv = CSV.open(path) {|csv| p csv}
1367
+ # csv # => #<CSV io_type:File io_path:"t.csv" encoding:UTF-8 lineno:0 col_sep:"," row_sep:"\n" quote_char:"\"">
1368
+ # Output:
1369
+ # #<CSV io_type:File io_path:"t.csv" encoding:UTF-8 lineno:0 col_sep:"," row_sep:"\n" quote_char:"\"">
1370
+ #
1371
+ # Using an open \File:
1372
+ # csv = CSV.open(File.open(path)) {|csv| p csv}
1373
+ # csv # => #<CSV io_type:File io_path:"t.csv" encoding:UTF-8 lineno:0 col_sep:"," row_sep:"\n" quote_char:"\"">
1374
+ # Output:
1375
+ # #<CSV io_type:File io_path:"t.csv" encoding:UTF-8 lineno:0 col_sep:"," row_sep:"\n" quote_char:"\"">
1376
+ #
1377
+ # ---
1378
+ #
1379
+ # Raises an exception if the argument is not a \String object or \IO object:
1380
+ # # Raises TypeError (no implicit conversion of Symbol into String)
1381
+ # CSV.open(:foo)
919
1382
  def open(filename, mode="r", **options)
920
1383
  # wrap a File opened with the remaining +args+ with no newline
921
1384
  # decorator
922
1385
  file_opts = {universal_newline: false}.merge(options)
1386
+ options.delete(:invalid)
1387
+ options.delete(:undef)
1388
+ options.delete(:replace)
923
1389
 
924
1390
  begin
925
1391
  f = File.open(filename, mode, **file_opts)
@@ -950,16 +1416,116 @@ class CSV
950
1416
 
951
1417
  #
952
1418
  # :call-seq:
953
- # parse( str, **options ) { |row| ... }
954
- # parse( str, **options )
1419
+ # parse(string) -> array_of_arrays
1420
+ # parse(io) -> array_of_arrays
1421
+ # parse(string, headers: ..., **options) -> csv_table
1422
+ # parse(io, headers: ..., **options) -> csv_table
1423
+ # parse(string, **options) {|row| ... }
1424
+ # parse(io, **options) {|row| ... }
1425
+ #
1426
+ # Parses +string+ or +io+ using the specified +options+.
1427
+ #
1428
+ # - Argument +string+ should be a \String object;
1429
+ # it will be put into a new StringIO object positioned at the beginning.
1430
+ # :include: ../doc/arguments/io.rdoc
1431
+ # - Argument +options+: see {Options for Parsing}[#class-CSV-label-Options+for+Parsing]
1432
+ #
1433
+ # ====== Without Option +headers+
1434
+ #
1435
+ # Without {option +headers+}[#class-CSV-label-Option+headers] case.
1436
+ #
1437
+ # These examples assume prior execution of:
1438
+ # string = "foo,0\nbar,1\nbaz,2\n"
1439
+ # path = 't.csv'
1440
+ # File.write(path, string)
1441
+ #
1442
+ # ---
1443
+ #
1444
+ # With no block given, returns an \Array of Arrays formed from the source.
1445
+ #
1446
+ # Parse a \String:
1447
+ # a_of_a = CSV.parse(string)
1448
+ # a_of_a # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
1449
+ #
1450
+ # Parse an open \File:
1451
+ # a_of_a = File.open(path) do |file|
1452
+ # CSV.parse(file)
1453
+ # end
1454
+ # a_of_a # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
1455
+ #
1456
+ # ---
1457
+ #
1458
+ # With a block given, calls the block with each parsed row:
1459
+ #
1460
+ # Parse a \String:
1461
+ # CSV.parse(string) {|row| p row }
955
1462
  #
956
- # This method can be used to easily parse CSV out of a String. You may either
957
- # provide a +block+ which will be called with each row of the String in turn,
958
- # or just use the returned Array of Arrays (when no +block+ is given).
1463
+ # Output:
1464
+ # ["foo", "0"]
1465
+ # ["bar", "1"]
1466
+ # ["baz", "2"]
1467
+ #
1468
+ # Parse an open \File:
1469
+ # File.open(path) do |file|
1470
+ # CSV.parse(file) {|row| p row }
1471
+ # end
1472
+ #
1473
+ # Output:
1474
+ # ["foo", "0"]
1475
+ # ["bar", "1"]
1476
+ # ["baz", "2"]
1477
+ #
1478
+ # ====== With Option +headers+
1479
+ #
1480
+ # With {option +headers+}[#class-CSV-label-Option+headers] case.
1481
+ #
1482
+ # These examples assume prior execution of:
1483
+ # string = "Name,Count\nfoo,0\nbar,1\nbaz,2\n"
1484
+ # path = 't.csv'
1485
+ # File.write(path, string)
1486
+ #
1487
+ # ---
959
1488
  #
960
- # You pass your +str+ to read from, and an optional +options+.
961
- # See {Options for Parsing}[#class-CSV-label-Options+for+Parsing].
1489
+ # With no block given, returns a CSV::Table object formed from the source.
962
1490
  #
1491
+ # Parse a \String:
1492
+ # csv_table = CSV.parse(string, headers: ['Name', 'Count'])
1493
+ # csv_table # => #<CSV::Table mode:col_or_row row_count:5>
1494
+ #
1495
+ # Parse an open \File:
1496
+ # csv_table = File.open(path) do |file|
1497
+ # CSV.parse(file, headers: ['Name', 'Count'])
1498
+ # end
1499
+ # csv_table # => #<CSV::Table mode:col_or_row row_count:4>
1500
+ #
1501
+ # ---
1502
+ #
1503
+ # With a block given, calls the block with each parsed row,
1504
+ # which has been formed into a CSV::Row object:
1505
+ #
1506
+ # Parse a \String:
1507
+ # CSV.parse(string, headers: ['Name', 'Count']) {|row| p row }
1508
+ #
1509
+ # Output:
1510
+ # # <CSV::Row "Name":"foo" "Count":"0">
1511
+ # # <CSV::Row "Name":"bar" "Count":"1">
1512
+ # # <CSV::Row "Name":"baz" "Count":"2">
1513
+ #
1514
+ # Parse an open \File:
1515
+ # File.open(path) do |file|
1516
+ # CSV.parse(file, headers: ['Name', 'Count']) {|row| p row }
1517
+ # end
1518
+ #
1519
+ # Output:
1520
+ # # <CSV::Row "Name":"foo" "Count":"0">
1521
+ # # <CSV::Row "Name":"bar" "Count":"1">
1522
+ # # <CSV::Row "Name":"baz" "Count":"2">
1523
+ #
1524
+ # ---
1525
+ #
1526
+ # Raises an exception if the argument is not a \String object or \IO object:
1527
+ # # Raises NoMethodError (undefined method `close' for :foo:Symbol)
1528
+ # CSV.parse(:foo)
963
1529
  def parse(str, **options, &block)
964
1530
  csv = new(str, **options)
965
1531
 
@@ -974,35 +1540,59 @@ class CSV
974
1540
  end
975
1541
 
976
1542
  # :call-seq:
977
- # CSV.parse_line(string)
978
- # CSV.parse_line(io)
979
- # CSV.parse_line(string, **options)
980
- # CSV.parse_line(io, **options)
1543
+ # CSV.parse_line(string) -> new_array or nil
1544
+ # CSV.parse_line(io) -> new_array or nil
1545
+ # CSV.parse_line(string, **options) -> new_array or nil
1546
+ # CSV.parse_line(io, **options) -> new_array or nil
1547
+ # CSV.parse_line(string, headers: true, **options) -> csv_row or nil
1548
+ # CSV.parse_line(io, headers: true, **options) -> csv_row or nil
981
1549
  #
982
- # Returns the new \Array created by parsing the first line of +string+ or +io+
1550
+ # Returns the data created by parsing the first line of +string+ or +io+
983
1551
  # using the specified +options+.
984
1552
  #
985
- # Argument +string+ should be a \String object;
986
- # it will be put into a new \StringIO object positioned at the beginning.
1553
+ # - Argument +string+ should be a \String object;
1554
+ # it will be put into a new StringIO object positioned at the beginning.
1555
+ # :include: ../doc/arguments/io.rdoc
1556
+ # - Argument +options+: see {Options for Parsing}[#class-CSV-label-Options+for+Parsing]
987
1557
  #
988
- # Argument +io+ should be an \IO object; it will be positioned at the beginning.
1558
+ # ====== Without Option +headers+
989
1559
  #
990
- # For +options+, see {Options for Parsing}[#class-CSV-label-Options+for+Parsing].
1560
+ # Without option +headers+, returns the first row as a new \Array.
991
1561
  #
992
- # ---
993
- # Returns data from the first line from a String object:
994
- # CSV.parse_line('foo,0') # => ["foo", "0"]
1562
+ # These examples assume prior execution of:
1563
+ # string = "foo,0\nbar,1\nbaz,2\n"
1564
+ # path = 't.csv'
1565
+ # File.write(path, string)
995
1566
  #
996
- # Returns data from the first line from a File object:
997
- # File.write('t.csv', 'foo,0')
998
- # CSV.parse_line(File.open('t.csv')) # => ["foo", "0"]
1567
+ # Parse the first line from a \String object:
1568
+ # CSV.parse_line(string) # => ["foo", "0"]
999
1569
  #
1000
- # Ignores lines after the first:
1001
- # CSV.parse_line("foo,0\nbar,1\nbaz,2") # => ["foo", "0"]
1570
+ # Parse the first line from a File object:
1571
+ # File.open(path) do |file|
1572
+ # CSV.parse_line(file) # => ["foo", "0"]
1573
+ # end # => ["foo", "0"]
1002
1574
  #
1003
1575
  # Returns +nil+ if the argument is an empty \String:
1004
1576
  # CSV.parse_line('') # => nil
1005
1577
  #
1578
+ # ====== With Option +headers+
1579
+ #
1580
+ # With {option +headers+}[#class-CSV-label-Option+headers],
1581
+ # returns the first row as a CSV::Row object.
1582
+ #
1583
+ # These examples assume prior execution of:
1584
+ # string = "Name,Count\nfoo,0\nbar,1\nbaz,2\n"
1585
+ # path = 't.csv'
1586
+ # File.write(path, string)
1587
+ #
1588
+ # Parse the first line from a \String object:
1589
+ # CSV.parse_line(string, headers: true) # => #<CSV::Row "Name":"foo" "Count":"0">
1590
+ #
1591
+ # Parse the first line from a File object:
1592
+ # File.open(path) do |file|
1593
+ # CSV.parse_line(file, headers: true)
1594
+ # end # => #<CSV::Row "Name":"foo" "Count":"0">
1595
+ #
1006
1596
  # ---
1007
1597
  #
1008
1598
  # Raises an exception if the argument is +nil+:
@@ -1014,36 +1604,52 @@ class CSV
1014
1604
  end
1015
1605
 
1016
1606
  #
1017
- # Use to slurp a CSV file into an Array of Arrays. Pass the +path+ to the
1018
- # file and +options+.
1019
- # See {Options for Parsing}[#class-CSV-label-Options+for+Parsing].
1607
+ # :call-seq:
1608
+ # read(source, **options) -> array_of_arrays
1609
+ # read(source, headers: true, **options) -> csv_table
1610
+ #
1611
+ # Opens the given +source+ with the given +options+ (see CSV.open),
1612
+ # reads the source (see CSV#read), and returns the result,
1613
+ # which will be either an \Array of Arrays or a CSV::Table.
1020
1614
  #
1021
- # This method also understands
1022
- # an additional <tt>:encoding</tt> parameter that you can use to specify the
1023
- # Encoding of the data in the file to be read. You must provide this unless
1024
- # your data is in Encoding::default_external(). CSV will use this to determine
1025
- # how to parse the data. You may provide a second Encoding to have the data
1026
- # transcoded as it is read. For example,
1027
- # <tt>encoding: "UTF-32BE:UTF-8"</tt> would read UTF-32BE data from the file
1028
- # but transcode it to UTF-8 before CSV parses it.
1615
+ # Without headers:
1616
+ # string = "foo,0\nbar,1\nbaz,2\n"
1617
+ # path = 't.csv'
1618
+ # File.write(path, string)
1619
+ # CSV.read(path) # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
1029
1620
  #
1621
+ # With headers:
1622
+ # string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
1623
+ # path = 't.csv'
1624
+ # File.write(path, string)
1625
+ # CSV.read(path, headers: true) # => #<CSV::Table mode:col_or_row row_count:4>
1030
1626
  def read(path, **options)
1031
1627
  open(path, **options) { |csv| csv.read }
1032
1628
  end
1033
1629
 
1034
- # Alias for CSV::read().
1630
+ # :call-seq:
1631
+ # CSV.readlines(source, **options)
1632
+ #
1633
+ # Alias for CSV.read.
1035
1634
  def readlines(path, **options)
1036
1635
  read(path, **options)
1037
1636
  end
1038
1637
 
1638
+ # :call-seq:
1639
+ # CSV.table(source, **options)
1039
1640
  #
1040
- # A shortcut for:
1641
+ # Calls CSV.read with +source+, +options+, and certain default options:
1642
+ # - +headers+: +true+
1643
+ # - +converbers+: +:numeric+
1644
+ # - +header_converters+: +:symbol+
1041
1645
  #
1042
- # CSV.read( path, { headers: true,
1043
- # converters: :numeric,
1044
- # header_converters: :symbol }.merge(options) )
1646
+ # Returns a CSV::Table object.
1045
1647
  #
1046
- # See {Options for Parsing}[#class-CSV-label-Options+for+Parsing].
1648
+ # Example:
1649
+ # string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
1650
+ # path = 't.csv'
1651
+ # File.write(path, string)
1652
+ # CSV.table(path) # => #<CSV::Table mode:col_or_row row_count:4>
1047
1653
  def table(path, **options)
1048
1654
  default_options = {
1049
1655
  headers: true,
@@ -1064,23 +1670,17 @@ class CSV
1064
1670
  # Returns the new \CSV object created using +string+ or +io+
1065
1671
  # and the specified +options+.
1066
1672
  #
1067
- # Argument +string+ should be a \String object;
1068
- # it will be put into a new \StringIO object positioned at the beginning.
1673
+ # - Argument +string+ should be a \String object;
1674
+ # it will be put into a new StringIO object positioned at the beginning.
1675
+ # :include: ../doc/arguments/io.rdoc
1676
+ # - Argument +options+: See:
1677
+ # * {Options for Parsing}[#class-CSV-label-Options+for+Parsing]
1678
+ # * {Options for Generating}[#class-CSV-label-Options+for+Generating]
1679
+ # For performance reasons, the options cannot be overridden
1680
+ # in a \CSV object, so those specified here will endure.
1069
1681
  #
1070
- # Argument +io+ should be an \IO object; it will be positioned at the beginning.
1071
- #
1072
- # To position at the end, for appending, use method CSV.generate.
1073
- # For any other positioning, pass a preset StringIO object instead.
1074
- #
1075
- # In addition to the \CSV instance methods, several \IO
1076
- # methods are delegated. See CSV::open for a complete list.
1077
- #
1078
- # For +options+, see:
1079
- # * {Options for Parsing}[#class-CSV-label-Options+for+Parsing]
1080
- # * {Options for Generating}[#class-CSV-label-Options+for+Generating]
1081
- #
1082
- # For performance reasons, the options cannot be overridden
1083
- # in a \CSV object, so the options specified here will endure.
1682
+ # In addition to the \CSV instance methods, several \IO methods are delegated.
1683
+ # See {Delegated Methods}[#class-CSV-label-Delegated+Methods].
1084
1684
  #
1085
1685
  # ---
1086
1686
  #
@@ -1182,51 +1782,67 @@ class CSV
1182
1782
  writer if @writer_options[:write_headers]
1183
1783
  end
1184
1784
 
1785
+ # :call-seq:
1786
+ # csv.col_sep -> string
1185
1787
  #
1186
- # The encoded <tt>:col_sep</tt> used in parsing and writing.
1187
- # See CSV::new for details.
1188
- #
1788
+ # Returns the encoded column separator; used for parsing and writing;
1789
+ # see {Option +col_sep+}[#class-CSV-label-Option+col_sep]:
1790
+ # CSV.new('').col_sep # => ","
1189
1791
  def col_sep
1190
1792
  parser.column_separator
1191
1793
  end
1192
1794
 
1795
+ # :call-seq:
1796
+ # csv.row_sep -> string
1193
1797
  #
1194
- # The encoded <tt>:row_sep</tt> used in parsing and writing.
1195
- # See CSV::new for details.
1196
- #
1798
+ # Returns the encoded row separator; used for parsing and writing;
1799
+ # see {Option +row_sep+}[#class-CSV-label-Option+row_sep]:
1800
+ # CSV.new('').row_sep # => "\n"
1197
1801
  def row_sep
1198
1802
  parser.row_separator
1199
1803
  end
1200
1804
 
1805
+ # :call-seq:
1806
+ # csv.quote_char -> character
1201
1807
  #
1202
- # The encoded <tt>:quote_char</tt> used in parsing and writing.
1203
- # See CSV::new for details.
1204
- #
1808
+ # Returns the encoded quote character; used for parsing and writing;
1809
+ # see {Option +quote_char+}[#class-CSV-label-Option+quote_char]:
1810
+ # CSV.new('').quote_char # => "\""
1205
1811
  def quote_char
1206
1812
  parser.quote_character
1207
1813
  end
1208
1814
 
1815
+ # :call-seq:
1816
+ # csv.field_size_limit -> integer or nil
1209
1817
  #
1210
- # The limit for field size, if any.
1211
- # See CSV::new for details.
1212
- #
1818
+ # Returns the limit for field size; used for parsing;
1819
+ # see {Option +field_size_limit+}[#class-CSV-label-Option+field_size_limit]:
1820
+ # CSV.new('').field_size_limit # => nil
1213
1821
  def field_size_limit
1214
1822
  parser.field_size_limit
1215
1823
  end
1216
1824
 
1825
+ # :call-seq:
1826
+ # csv.skip_lines -> regexp or nil
1217
1827
  #
1218
- # The regex marking a line as a comment.
1219
- # See CSV::new for details.
1220
- #
1828
+ # Returns the \Regexp used to identify comment lines; used for parsing;
1829
+ # see {Option +skip_lines+}[#class-CSV-label-Option+skip_lines]:
1830
+ # CSV.new('').skip_lines # => nil
1221
1831
  def skip_lines
1222
1832
  parser.skip_lines
1223
1833
  end
1224
1834
 
1225
- #
1226
- # Returns the current list of converters in effect. See CSV::new for details.
1227
- # Built-in converters will be returned by name, while others will be returned
1228
- # as is.
1229
- #
1835
+ # :call-seq:
1836
+ # csv.converters -> array
1837
+ #
1838
+ # Returns an \Array containing field converters;
1839
+ # see {Field Converters}[#class-CSV-label-Field+Converters]:
1840
+ # csv = CSV.new('')
1841
+ # csv.converters # => []
1842
+ # csv.convert(:integer)
1843
+ # csv.converters # => [:integer]
1844
+ # csv.convert(proc {|x| x.to_s })
1845
+ # csv.converters
1230
1846
  def converters
1231
1847
  parser_fields_converter.map do |converter|
1232
1848
  name = Converters.rassoc(converter)
@@ -1234,19 +1850,23 @@ class CSV
1234
1850
  end
1235
1851
  end
1236
1852
 
1853
+ # :call-seq:
1854
+ # csv.unconverted_fields? -> object
1237
1855
  #
1238
- # Returns +true+ if unconverted_fields() to parsed results.
1239
- # See CSV::new for details.
1240
- #
1856
+ # Returns the value that determines whether unconverted fields are to be
1857
+ # available; used for parsing;
1858
+ # see {Option +unconverted_fields+}[#class-CSV-label-Option+unconverted_fields]:
1859
+ # CSV.new('').unconverted_fields? # => nil
1241
1860
  def unconverted_fields?
1242
1861
  parser.unconverted_fields?
1243
1862
  end
1244
1863
 
1864
+ # :call-seq:
1865
+ # csv.headers -> object
1245
1866
  #
1246
- # Returns +nil+ if headers will not be used, +true+ if they will but have not
1247
- # yet been read, or the actual headers after they have been read.
1248
- # See CSV::new for details.
1249
- #
1867
+ # Returns the value that determines whether headers are used; used for parsing;
1868
+ # see {Option +headers+}[#class-CSV-label-Option+headers]:
1869
+ # CSV.new('').headers # => nil
1250
1870
  def headers
1251
1871
  if @writer
1252
1872
  @writer.headers
@@ -1258,27 +1878,33 @@ class CSV
1258
1878
  raw_headers
1259
1879
  end
1260
1880
  end
1881
+
1882
+ # :call-seq:
1883
+ # csv.return_headers? -> true or false
1261
1884
  #
1262
- # Returns +true+ if headers will be returned as a row of results.
1263
- # See CSV::new for details.
1264
- #
1885
+ # Returns the value that determines whether headers are to be returned; used for parsing;
1886
+ # see {Option +return_headers+}[#class-CSV-label-Option+return_headers]:
1887
+ # CSV.new('').return_headers? # => false
1265
1888
  def return_headers?
1266
1889
  parser.return_headers?
1267
1890
  end
1268
1891
 
1892
+ # :call-seq:
1893
+ # csv.write_headers? -> true or false
1269
1894
  #
1270
- # Returns +true+ if headers are written in output.
1271
- # See CSV::new for details.
1272
- #
1895
+ # Returns the value that determines whether headers are to be written; used for generating;
1896
+ # see {Option +write_headers+}[#class-CSV-label-Option+write_headers]:
1897
+ # CSV.new('').write_headers? # => nil
1273
1898
  def write_headers?
1274
1899
  @writer_options[:write_headers]
1275
1900
  end
1276
1901
 
1902
+ # :call-seq:
1903
+ # csv.header_converters -> array
1277
1904
  #
1278
- # Returns the current list of converters in effect for headers. See CSV::new
1279
- # for details. Built-in converters will be returned by name, while others
1280
- # will be returned as is.
1281
- #
1905
+ # Returns an \Array containing header converters; used for parsing;
1906
+ # see {Header Converters}[#class-CSV-label-Header+Converters]:
1907
+ # CSV.new('').header_converters # => []
1282
1908
  def header_converters
1283
1909
  header_fields_converter.map do |converter|
1284
1910
  name = HeaderConverters.rassoc(converter)
@@ -1286,34 +1912,74 @@ class CSV
1286
1912
  end
1287
1913
  end
1288
1914
 
1915
+ # :call-seq:
1916
+ # csv.skip_blanks? -> true or false
1289
1917
  #
1290
- # Returns +true+ blank lines are skipped by the parser. See CSV::new
1291
- # for details.
1292
- #
1918
+ # Returns the value that determines whether blank lines are to be ignored; used for parsing;
1919
+ # see {Option +skip_blanks+}[#class-CSV-label-Option+skip_blanks]:
1920
+ # CSV.new('').skip_blanks? # => false
1293
1921
  def skip_blanks?
1294
1922
  parser.skip_blanks?
1295
1923
  end
1296
1924
 
1297
- # Returns +true+ if all output fields are quoted. See CSV::new for details.
1925
+ # :call-seq:
1926
+ # csv.force_quotes? -> true or false
1927
+ #
1928
+ # Returns the value that determines whether all output fields are to be quoted;
1929
+ # used for generating;
1930
+ # see {Option +force_quotes+}[#class-CSV-label-Option+force_quotes]:
1931
+ # CSV.new('').force_quotes? # => false
1298
1932
  def force_quotes?
1299
1933
  @writer_options[:force_quotes]
1300
1934
  end
1301
1935
 
1302
- # Returns +true+ if illegal input is handled. See CSV::new for details.
1936
+ # :call-seq:
1937
+ # csv.liberal_parsing? -> true or false
1938
+ #
1939
+ # Returns the value that determines whether illegal input is to be handled; used for parsing;
1940
+ # see {Option +liberal_parsing+}[#class-CSV-label-Option+liberal_parsing]:
1941
+ # CSV.new('').liberal_parsing? # => false
1303
1942
  def liberal_parsing?
1304
1943
  parser.liberal_parsing?
1305
1944
  end
1306
1945
 
1946
+ # :call-seq:
1947
+ # csv.encoding -> endcoding
1307
1948
  #
1308
- # The Encoding CSV is parsing or writing in. This will be the Encoding you
1309
- # receive parsed data in and/or the Encoding data will be written in.
1310
- #
1949
+ # Returns the encoding used for parsing and generating;
1950
+ # see {Character Encodings (M17n or Multilingualization)}[#class-CSV-label-Character+Encodings+-28M17n+or+Multilingualization-29]:
1951
+ # CSV.new('').encoding # => #<Encoding:UTF-8>
1311
1952
  attr_reader :encoding
1312
1953
 
1313
- #
1314
- # The line number of the last row read from this file. Fields with nested
1315
- # line-end characters will not affect this count.
1316
- #
1954
+ # :call-seq:
1955
+ # csv.line_no -> integer
1956
+ #
1957
+ # Returns the count of the rows parsed or generated.
1958
+ #
1959
+ # Parsing:
1960
+ # string = "foo,0\nbar,1\nbaz,2\n"
1961
+ # path = 't.csv'
1962
+ # File.write(path, string)
1963
+ # CSV.open(path) do |csv|
1964
+ # csv.each do |row|
1965
+ # p [csv.lineno, row]
1966
+ # end
1967
+ # end
1968
+ # Output:
1969
+ # [1, ["foo", "0"]]
1970
+ # [2, ["bar", "1"]]
1971
+ # [3, ["baz", "2"]]
1972
+ #
1973
+ # Generating:
1974
+ # CSV.generate do |csv|
1975
+ # p csv.lineno; csv << ['foo', 0]
1976
+ # p csv.lineno; csv << ['bar', 1]
1977
+ # p csv.lineno; csv << ['baz', 2]
1978
+ # end
1979
+ # Output:
1980
+ # 0
1981
+ # 1
1982
+ # 2
1317
1983
  def lineno
1318
1984
  if @writer
1319
1985
  @writer.lineno
@@ -1322,9 +1988,22 @@ class CSV
1322
1988
  end
1323
1989
  end
1324
1990
 
1325
- #
1326
- # The last row read from this file.
1327
- #
1991
+ # :call-seq:
1992
+ # csv.line -> array
1993
+ #
1994
+ # Returns the line most recently read:
1995
+ # string = "foo,0\nbar,1\nbaz,2\n"
1996
+ # path = 't.csv'
1997
+ # File.write(path, string)
1998
+ # CSV.open(path) do |csv|
1999
+ # csv.each do |row|
2000
+ # p [csv.lineno, csv.line]
2001
+ # end
2002
+ # end
2003
+ # Output:
2004
+ # [1, "foo,0\n"]
2005
+ # [2, "bar,1\n"]
2006
+ # [3, "baz,2\n"]
1328
2007
  def line
1329
2008
  parser.line
1330
2009
  end
@@ -1400,13 +2079,56 @@ class CSV
1400
2079
 
1401
2080
  ### End Delegation ###
1402
2081
 
2082
+ # :call-seq:
2083
+ # csv.<< row
1403
2084
  #
1404
- # The primary write method for wrapped Strings and IOs, +row+ (an Array or
1405
- # CSV::Row) is converted to CSV and appended to the data source. When a
1406
- # CSV::Row is passed, only the row's fields() are appended to the output.
2085
+ # Appends a row to +self+.
1407
2086
  #
1408
- # The data source must be open for writing.
2087
+ # - Argument +row+ must be an \Array object or a CSV::Row object.
2088
+ # - The output stream must be open for writing.
2089
+ #
2090
+ # ---
1409
2091
  #
2092
+ # Append Arrays:
2093
+ # CSV.generate do |csv|
2094
+ # csv << ['foo', 0]
2095
+ # csv << ['bar', 1]
2096
+ # csv << ['baz', 2]
2097
+ # end # => "foo,0\nbar,1\nbaz,2\n"
2098
+ #
2099
+ # Append CSV::Rows:
2100
+ # headers = []
2101
+ # CSV.generate do |csv|
2102
+ # csv << CSV::Row.new(headers, ['foo', 0])
2103
+ # csv << CSV::Row.new(headers, ['bar', 1])
2104
+ # csv << CSV::Row.new(headers, ['baz', 2])
2105
+ # end # => "foo,0\nbar,1\nbaz,2\n"
2106
+ #
2107
+ # Headers in CSV::Row objects are not appended:
2108
+ # headers = ['Name', 'Count']
2109
+ # CSV.generate do |csv|
2110
+ # csv << CSV::Row.new(headers, ['foo', 0])
2111
+ # csv << CSV::Row.new(headers, ['bar', 1])
2112
+ # csv << CSV::Row.new(headers, ['baz', 2])
2113
+ # end # => "foo,0\nbar,1\nbaz,2\n"
2114
+ #
2115
+ # ---
2116
+ #
2117
+ # Raises an exception if +row+ is not an \Array or \CSV::Row:
2118
+ # CSV.generate do |csv|
2119
+ # # Raises NoMethodError (undefined method `collect' for :foo:Symbol)
2120
+ # csv << :foo
2121
+ # end
2122
+ #
2123
+ # Raises an exception if the output stream is not open for writing:
2124
+ # path = 't.csv'
2125
+ # File.write(path, '')
2126
+ # File.open(path) do |file|
2127
+ # CSV.open(file) do |csv|
2128
+ # # Raises IOError (not opened for writing)
2129
+ # csv << ['foo', 0]
2130
+ # end
2131
+ # end
1410
2132
  def <<(row)
1411
2133
  writer << row
1412
2134
  self
@@ -1414,36 +2136,136 @@ class CSV
1414
2136
  alias_method :add_row, :<<
1415
2137
  alias_method :puts, :<<
1416
2138
 
1417
- #
1418
2139
  # :call-seq:
1419
- # convert( name )
1420
- # convert { |field| ... }
1421
- # convert { |field, field_info| ... }
2140
+ # convert(converter_name) -> array_of_procs
2141
+ # convert {|field, field_info| ... } -> array_of_procs
1422
2142
  #
1423
- # You can use this method to install a CSV::Converters built-in, or provide a
1424
- # block that handles a custom conversion.
2143
+ # - With no block, installs a field converter (a \Proc).
2144
+ # - With a block, defines and installs a custom field converter.
2145
+ # - Returns the \Array of installed field converters.
2146
+ #
2147
+ # - Argument +converter_name+, if given, should be the name
2148
+ # of an existing field converter.
2149
+ #
2150
+ # See {Field Converters}[#class-CSV-label-Field+Converters].
2151
+ # ---
1425
2152
  #
1426
- # If you provide a block that takes one argument, it will be passed the field
1427
- # and is expected to return the converted value or the field itself. If your
1428
- # block takes two arguments, it will also be passed a CSV::FieldInfo Struct,
1429
- # containing details about the field. Again, the block should return a
1430
- # converted field or the field itself.
2153
+ # With no block, installs a field converter:
2154
+ # csv = CSV.new('')
2155
+ # csv.convert(:integer)
2156
+ # csv.convert(:float)
2157
+ # csv.convert(:date)
2158
+ # csv.converters # => [:integer, :float, :date]
1431
2159
  #
2160
+ # ---
2161
+ #
2162
+ # The block, if given, is called for each field:
2163
+ # - Argument +field+ is the field value.
2164
+ # - Argument +field_info+ is a CSV::FieldInfo object
2165
+ # containing details about the field.
2166
+ #
2167
+ # The examples here assume the prior execution of:
2168
+ # string = "foo,0\nbar,1\nbaz,2\n"
2169
+ # path = 't.csv'
2170
+ # File.write(path, string)
2171
+ #
2172
+ # Example giving a block:
2173
+ # csv = CSV.open(path)
2174
+ # csv.convert {|field, field_info| p [field, field_info]; field.upcase }
2175
+ # csv.read # => [["FOO", "0"], ["BAR", "1"], ["BAZ", "2"]]
2176
+ #
2177
+ # Output:
2178
+ # ["foo", #<struct CSV::FieldInfo index=0, line=1, header=nil>]
2179
+ # ["0", #<struct CSV::FieldInfo index=1, line=1, header=nil>]
2180
+ # ["bar", #<struct CSV::FieldInfo index=0, line=2, header=nil>]
2181
+ # ["1", #<struct CSV::FieldInfo index=1, line=2, header=nil>]
2182
+ # ["baz", #<struct CSV::FieldInfo index=0, line=3, header=nil>]
2183
+ # ["2", #<struct CSV::FieldInfo index=1, line=3, header=nil>]
2184
+ #
2185
+ # The block need not return a \String object:
2186
+ # csv = CSV.open(path)
2187
+ # csv.convert {|field, field_info| field.to_sym }
2188
+ # csv.read # => [[:foo, :"0"], [:bar, :"1"], [:baz, :"2"]]
2189
+ #
2190
+ # If +converter_name+ is given, the block is not called:
2191
+ # csv = CSV.open(path)
2192
+ # csv.convert(:integer) {|field, field_info| fail 'Cannot happen' }
2193
+ # csv.read # => [["foo", 0], ["bar", 1], ["baz", 2]]
2194
+ #
2195
+ # ---
2196
+ #
2197
+ # Raises a parse-time exception if +converter_name+ is not the name of a built-in
2198
+ # field converter:
2199
+ # csv = CSV.open(path)
2200
+ # csv.convert(:nosuch) => [nil]
2201
+ # # Raises NoMethodError (undefined method `arity' for nil:NilClass)
2202
+ # csv.read
1432
2203
  def convert(name = nil, &converter)
1433
2204
  parser_fields_converter.add_converter(name, &converter)
1434
2205
  end
1435
2206
 
1436
- #
1437
2207
  # :call-seq:
1438
- # header_convert( name )
1439
- # header_convert { |field| ... }
1440
- # header_convert { |field, field_info| ... }
2208
+ # header_convert(converter_name) -> array_of_procs
2209
+ # header_convert {|header, field_info| ... } -> array_of_procs
2210
+ #
2211
+ # - With no block, installs a header converter (a \Proc).
2212
+ # - With a block, defines and installs a custom header converter.
2213
+ # - Returns the \Array of installed header converters.
1441
2214
  #
1442
- # Identical to CSV#convert(), but for header rows.
2215
+ # - Argument +converter_name+, if given, should be the name
2216
+ # of an existing header converter.
1443
2217
  #
1444
- # Note that this method must be called before header rows are read to have any
1445
- # effect.
2218
+ # See {Header Converters}[#class-CSV-label-Header+Converters].
2219
+ # ---
2220
+ #
2221
+ # With no block, installs a header converter:
2222
+ # csv = CSV.new('')
2223
+ # csv.header_convert(:symbol)
2224
+ # csv.header_convert(:downcase)
2225
+ # csv.header_converters # => [:symbol, :downcase]
2226
+ #
2227
+ # ---
1446
2228
  #
2229
+ # The block, if given, is called for each header:
2230
+ # - Argument +header+ is the header value.
2231
+ # - Argument +field_info+ is a CSV::FieldInfo object
2232
+ # containing details about the header.
2233
+ #
2234
+ # The examples here assume the prior execution of:
2235
+ # string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
2236
+ # path = 't.csv'
2237
+ # File.write(path, string)
2238
+ #
2239
+ # Example giving a block:
2240
+ # csv = CSV.open(path, headers: true)
2241
+ # csv.header_convert {|header, field_info| p [header, field_info]; header.upcase }
2242
+ # table = csv.read
2243
+ # table # => #<CSV::Table mode:col_or_row row_count:4>
2244
+ # table.headers # => ["NAME", "VALUE"]
2245
+ #
2246
+ # Output:
2247
+ # ["Name", #<struct CSV::FieldInfo index=0, line=1, header=nil>]
2248
+ # ["Value", #<struct CSV::FieldInfo index=1, line=1, header=nil>]
2249
+
2250
+ # The block need not return a \String object:
2251
+ # csv = CSV.open(path, headers: true)
2252
+ # csv.header_convert {|header, field_info| header.to_sym }
2253
+ # table = csv.read
2254
+ # table.headers # => [:Name, :Value]
2255
+ #
2256
+ # If +converter_name+ is given, the block is not called:
2257
+ # csv = CSV.open(path, headers: true)
2258
+ # csv.header_convert(:downcase) {|header, field_info| fail 'Cannot happen' }
2259
+ # table = csv.read
2260
+ # table.headers # => ["name", "value"]
2261
+ # ---
2262
+ #
2263
+ # Raises a parse-time exception if +converter_name+ is not the name of a built-in
2264
+ # field converter:
2265
+ # csv = CSV.open(path, headers: true)
2266
+ # csv.header_convert(:nosuch)
2267
+ # # Raises NoMethodError (undefined method `arity' for nil:NilClass)
2268
+ # csv.read
1447
2269
  def header_convert(name = nil, &converter)
1448
2270
  header_fields_converter.add_converter(name, &converter)
1449
2271
  end
@@ -1461,11 +2283,28 @@ class CSV
1461
2283
  parser_enumerator.each(&block)
1462
2284
  end
1463
2285
 
2286
+ # :call-seq:
2287
+ # read
1464
2288
  #
1465
- # Slurps the remaining rows and returns an Array of Arrays.
2289
+ # Forms the remaining rows from +self+ into:
2290
+ # - A CSV::Table object, if headers are in use.
2291
+ # - An Array of Arrays, otherwise.
1466
2292
  #
1467
2293
  # The data source must be open for reading.
1468
2294
  #
2295
+ # Without headers:
2296
+ # string = "foo,0\nbar,1\nbaz,2\n"
2297
+ # path = 't.csv'
2298
+ # File.write(path, string)
2299
+ # csv = CSV.open(path)
2300
+ # csv.read # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
2301
+ #
2302
+ # With headers:
2303
+ # string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
2304
+ # path = 't.csv'
2305
+ # File.write(path, string)
2306
+ # csv = CSV.open(path, headers: true)
2307
+ # csv.read # => #<CSV::Table mode:col_or_row row_count:4>
1469
2308
  def read
1470
2309
  rows = to_a
1471
2310
  if parser.use_headers?