csv 3.1.2 → 3.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,29 @@
1
+ ====== Option +write_headers+
2
+
3
+ Specifies the boolean that determines whether a header row is included in the output;
4
+ ignored if there are no headers.
5
+
6
+ Default value:
7
+ CSV::DEFAULT_OPTIONS.fetch(:write_headers) # => nil
8
+
9
+ Without +write_headers+:
10
+ file_path = 't.csv'
11
+ CSV.open(file_path,'w',
12
+ :headers => ['Name','Value']
13
+ ) do |csv|
14
+ csv << ['foo', '0']
15
+ end
16
+ CSV.open(file_path) do |csv|
17
+ csv.shift
18
+ end # => ["foo", "0"]
19
+
20
+ With +write_headers+":
21
+ CSV.open(file_path,'w',
22
+ :write_headers=> true,
23
+ :headers => ['Name','Value']
24
+ ) do |csv|
25
+ csv << ['foo', '0']
26
+ end
27
+ CSV.open(file_path) do |csv|
28
+ csv.shift
29
+ end # => ["Name", "Value"]
@@ -0,0 +1,14 @@
1
+ ====== Option +write_nil_value+
2
+
3
+ Specifies the object that is to be substituted for each +nil+-valued field.
4
+
5
+ Default value:
6
+ CSV::DEFAULT_OPTIONS.fetch(:write_nil_value) # => nil
7
+
8
+ Without the option:
9
+ str = CSV.generate_line(['a', nil, 'c', nil])
10
+ str # => "a,,c,\n"
11
+
12
+ With the option:
13
+ str = CSV.generate_line(['a', nil, 'c', nil], write_nil_value: "x")
14
+ str # => "a,x,c,x\n"
@@ -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,13 @@
1
+ ====== Option +empty_value+
2
+
3
+ Specifies the object that is to be substituted
4
+ for each field that has an empty \String.
5
+
6
+ Default value:
7
+ CSV::DEFAULT_OPTIONS.fetch(:empty_value) # => "" (empty string)
8
+
9
+ With the default, <tt>""</tt>:
10
+ CSV.parse_line('a,"",b,"",c') # => ["a", "", "b", "", "c"]
11
+
12
+ With a different object:
13
+ CSV.parse_line('a,"",b,"",c', empty_value: 'x') # => ["a", "x", "b", "x", "c"]
@@ -0,0 +1,39 @@
1
+ ====== Option +field_size_limit+
2
+
3
+ Specifies the \Integer field size limit.
4
+
5
+ Default value:
6
+ CSV::DEFAULT_OPTIONS.fetch(:field_size_limit) # => nil
7
+
8
+ This is a maximum size CSV will read ahead looking for the closing quote for a field.
9
+ (In truth, it reads to the first line ending beyond this size.)
10
+ If a quote cannot be found within the limit CSV will raise a MalformedCSVError,
11
+ assuming the data is faulty.
12
+ You can use this limit to prevent what are effectively DoS attacks on the parser.
13
+ However, this limit can cause a legitimate parse to fail;
14
+ therefore the default value is +nil+ (no limit).
15
+
16
+ For the examples in this section:
17
+ str = <<~EOT
18
+ "a","b"
19
+ "
20
+ 2345
21
+ ",""
22
+ EOT
23
+ str # => "\"a\",\"b\"\n\"\n2345\n\",\"\"\n"
24
+
25
+ Using the default +nil+:
26
+ ary = CSV.parse(str)
27
+ ary # => [["a", "b"], ["\n2345\n", ""]]
28
+
29
+ Using <tt>50</tt>:
30
+ field_size_limit = 50
31
+ ary = CSV.parse(str, field_size_limit: field_size_limit)
32
+ ary # => [["a", "b"], ["\n2345\n", ""]]
33
+
34
+ ---
35
+
36
+ Raises an exception if a field is too long:
37
+ big_str = "123456789\n" * 1024
38
+ # Raises CSV::MalformedCSVError (Field size exceeded in line 1.)
39
+ CSV.parse('valid,fields,"' + big_str + '"', field_size_limit: 2048)
@@ -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
+
@@ -0,0 +1,63 @@
1
+ ====== Option +headers+
2
+
3
+ Specifies a boolean, \Symbol, \Array, or \String to be used
4
+ to define column headers.
5
+
6
+ Default value:
7
+ CSV::DEFAULT_OPTIONS.fetch(:headers) # => false
8
+
9
+ ---
10
+
11
+ Without +headers+:
12
+ str = <<-EOT
13
+ Name,Count
14
+ foo,0
15
+ bar,1
16
+ bax,2
17
+ EOT
18
+ csv = CSV.new(str)
19
+ csv # => #<CSV io_type:StringIO encoding:UTF-8 lineno:0 col_sep:"," row_sep:"\n" quote_char:"\"">
20
+ csv.headers # => nil
21
+ csv.shift # => ["Name", "Count"]
22
+
23
+ ---
24
+
25
+ If set to +true+ or the \Symbol +:first_row+,
26
+ the first row of the data is treated as a row of headers:
27
+ str = <<-EOT
28
+ Name,Count
29
+ foo,0
30
+ bar,1
31
+ bax,2
32
+ EOT
33
+ csv = CSV.new(str, headers: true)
34
+ csv # => #<CSV io_type:StringIO encoding:UTF-8 lineno:2 col_sep:"," row_sep:"\n" quote_char:"\"" headers:["Name", "Count"]>
35
+ csv.headers # => ["Name", "Count"]
36
+ csv.shift # => #<CSV::Row "Name":"bar" "Count":"1">
37
+
38
+ ---
39
+
40
+ If set to an \Array, the \Array elements are treated as headers:
41
+ str = <<-EOT
42
+ foo,0
43
+ bar,1
44
+ bax,2
45
+ EOT
46
+ csv = CSV.new(str, headers: ['Name', 'Count'])
47
+ csv
48
+ csv.headers # => ["Name", "Count"]
49
+ csv.shift # => #<CSV::Row "Name":"bar" "Count":"1">
50
+
51
+ ---
52
+
53
+ If set to a \String +str+, method <tt>CSV::parse_line(str, options)</tt> is called
54
+ with the current +options+, and the returned \Array is treated as headers:
55
+ str = <<-EOT
56
+ foo,0
57
+ bar,1
58
+ bax,2
59
+ EOT
60
+ csv = CSV.new(str, headers: 'Name,Count')
61
+ csv
62
+ csv.headers # => ["Name", "Count"]
63
+ csv.shift # => #<CSV::Row "Name":"bar" "Count":"1">
@@ -0,0 +1,19 @@
1
+ ====== Option +liberal_parsing+
2
+
3
+ Specifies the boolean value that determines whether
4
+ CSV will attempt to parse input not conformant with RFC 4180,
5
+ such as double quotes in unquoted fields.
6
+
7
+ Default value:
8
+ CSV::DEFAULT_OPTIONS.fetch(:liberal_parsing) # => false
9
+
10
+ For examples in this section:
11
+ str = 'is,this "three, or four",fields'
12
+
13
+ Without +liberal_parsing+:
14
+ # Raises CSV::MalformedCSVError (Illegal quoting in str 1.)
15
+ CSV.parse_line(str)
16
+
17
+ With +liberal_parsing+:
18
+ ary = CSV.parse_line(str, liberal_parsing: true)
19
+ ary # => ["is", "this \"three", " or four\"", "fields"]
@@ -0,0 +1,12 @@
1
+ ====== Option +nil_value+
2
+
3
+ Specifies the object that is to be substituted for each null (no-text) field.
4
+
5
+ Default value:
6
+ CSV::DEFAULT_OPTIONS.fetch(:nil_value) # => nil
7
+
8
+ With the default, +nil+:
9
+ CSV.parse_line('a,,b,,c') # => ["a", nil, "b", nil, "c"]
10
+
11
+ With a different object:
12
+ CSV.parse_line('a,,b,,c', nil_value: 0) # => ["a", 0, "b", 0, "c"]
@@ -0,0 +1,22 @@
1
+ ====== Option +return_headers+
2
+
3
+ Specifies the boolean that determines whether method #shift
4
+ returns or ignores the header row.
5
+
6
+ Default value:
7
+ CSV::DEFAULT_OPTIONS.fetch(:return_headers) # => false
8
+
9
+ Examples:
10
+ str = <<-EOT
11
+ Name,Count
12
+ foo,0
13
+ bar,1
14
+ bax,2
15
+ EOT
16
+ # Without return_headers first row is str.
17
+ csv = CSV.new(str, headers: true)
18
+ csv.shift # => #<CSV::Row "Name":"foo" "Count":"0">
19
+ # With return_headers first row is headers.
20
+ csv = CSV.new(str, headers: true, return_headers: true)
21
+ csv.shift # => #<CSV::Row "Name":"Name" "Count":"Count">
22
+
@@ -0,0 +1,31 @@
1
+ ====== Option +skip_blanks+
2
+
3
+ Specifies a boolean that determines whether blank lines in the input will be ignored;
4
+ a line that contains a column separator is not considered to be blank.
5
+
6
+ Default value:
7
+ CSV::DEFAULT_OPTIONS.fetch(:skip_blanks) # => false
8
+
9
+ See also option {skiplines}[#class-CSV-label-Option+skip_lines].
10
+
11
+ For examples in this section:
12
+ str = <<-EOT
13
+ foo,0
14
+
15
+ bar,1
16
+ baz,2
17
+
18
+ ,
19
+ EOT
20
+
21
+ Using the default, +false+:
22
+ ary = CSV.parse(str)
23
+ ary # => [["foo", "0"], [], ["bar", "1"], ["baz", "2"], [], [nil, nil]]
24
+
25
+ Using +true+:
26
+ ary = CSV.parse(str, skip_blanks: true)
27
+ ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"], [nil, nil]]
28
+
29
+ Using a truthy value:
30
+ ary = CSV.parse(str, skip_blanks: :foo)
31
+ ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"], [nil, nil]]
@@ -0,0 +1,37 @@
1
+ ====== Option +skip_lines+
2
+
3
+ Specifies an object to use in identifying comment lines in the input that are to be ignored:
4
+ * If a \Regexp, ignores lines that match it.
5
+ * If a \String, converts it to a \Regexp, ignores lines that match it.
6
+ * If +nil+, no lines are considered to be comments.
7
+
8
+ Default value:
9
+ CSV::DEFAULT_OPTIONS.fetch(:skip_lines) # => nil
10
+
11
+ For examples in this section:
12
+ str = <<-EOT
13
+ # Comment
14
+ foo,0
15
+ bar,1
16
+ baz,2
17
+ # Another comment
18
+ EOT
19
+ str # => "# Comment\nfoo,0\nbar,1\nbaz,2\n# Another comment\n"
20
+
21
+ Using the default, +nil+:
22
+ ary = CSV.parse(str)
23
+ ary # => [["# Comment"], ["foo", "0"], ["bar", "1"], ["baz", "2"], ["# Another comment"]]
24
+
25
+ Using a \Regexp:
26
+ ary = CSV.parse(str, skip_lines: /^#/)
27
+ ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
28
+
29
+ Using a \String:
30
+ ary = CSV.parse(str, skip_lines: '#')
31
+ ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
32
+
33
+ ---
34
+
35
+ Raises an exception if given an object that is not a \Regexp, a \String, or +nil+:
36
+ # Raises ArgumentError (:skip_lines has to respond to #match: 0)
37
+ CSV.parse(str, skip_lines: 0)
@@ -0,0 +1,15 @@
1
+ ====== Option +strip+
2
+
3
+ Specifies the boolean value that determines whether
4
+ whitespace is stripped from each input field.
5
+
6
+ Default value:
7
+ CSV::DEFAULT_OPTIONS.fetch(:strip) # => false
8
+
9
+ With default value +false+:
10
+ ary = CSV.parse_line(' a , b ')
11
+ ary # => [" a ", " b "]
12
+
13
+ With value +true+:
14
+ ary = CSV.parse_line(' a , b ', strip: true)
15
+ ary # => ["a", "b"]
@@ -0,0 +1,27 @@
1
+ ====== Option +unconverted_fields+
2
+
3
+ Specifies the boolean that determines whether unconverted field values are to be available.
4
+
5
+ Default value:
6
+ CSV::DEFAULT_OPTIONS.fetch(:unconverted_fields) # => nil
7
+
8
+ The unconverted field values are those found in the source data,
9
+ prior to any conversions performed via option +converters+.
10
+
11
+ When option +unconverted_fields+ is +true+,
12
+ each returned row (\Array or \CSV::Row) has an added method,
13
+ +unconverted_fields+, that returns the unconverted field values:
14
+ str = <<-EOT
15
+ foo,0
16
+ bar,1
17
+ baz,2
18
+ EOT
19
+ # Without unconverted_fields
20
+ csv = CSV.parse(str, converters: :integer)
21
+ csv # => [["foo", 0], ["bar", 1], ["baz", 2]]
22
+ csv.first.respond_to?(:unconverted_fields) # => false
23
+ # With unconverted_fields
24
+ csv = CSV.parse(str, converters: :integer, unconverted_fields: true)
25
+ csv # => [["foo", 0], ["bar", 1], ["baz", 2]]
26
+ csv.first.respond_to?(:unconverted_fields) # => true
27
+ csv.first.unconverted_fields # => ["foo", "0"]
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,85 +103,322 @@ require_relative "csv/writer"
103
103
 
104
104
  using CSV::MatchP if CSV.const_defined?(:MatchP)
105
105
 
106
+ # == \CSV
107
+ # \CSV (comma-separated values) 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>.
106
112
  #
107
- # This class provides a complete interface to CSV files and data. It offers
108
- # tools to enable you to read and write to and from Strings or IO objects, as
109
- # needed.
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"
110
117
  #
111
- # The most generic interface of the library is:
118
+ # Despite the name \CSV, a \CSV representation can use different separators.
112
119
  #
113
- # csv = CSV.new(string_or_io, **options)
120
+ # == \Class \CSV
114
121
  #
115
- # # Reading: IO object should be open for read
116
- # csv.read # => array of rows
117
- # # or
118
- # csv.each do |row|
119
- # # ...
120
- # end
121
- # # or
122
- # row = csv.shift
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.
123
125
  #
124
- # # Writing: IO object should be open for write
125
- # csv << row
126
+ # To make \CSV available:
127
+ # require 'csv'
126
128
  #
127
- # There are several specialized class methods for one-statement reading or writing,
128
- # described in the Specialized Methods section.
129
+ # All examples here assume that this has been done.
129
130
  #
130
- # If a String is passed into ::new, it is internally wrapped into a StringIO object.
131
+ # == Keeping It Simple
131
132
  #
132
- # +options+ can be used for specifying the particular CSV flavor (column
133
- # separators, row separators, value quoting and so on), and for data conversion,
134
- # see Data Conversion section for the description of the latter.
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.
135
136
  #
136
- # == Specialized Methods
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.
137
141
  #
138
- # === Reading
142
+ # === Simple Parsing
139
143
  #
140
- # # From a file: all at once
141
- # arr_of_rows = CSV.read("path/to/file.csv", **options)
142
- # # iterator-style:
143
- # CSV.foreach("path/to/file.csv", **options) do |row|
144
- # # ...
145
- # 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].
146
151
  #
147
- # # From a string
148
- # arr_of_rows = CSV.parse("CSV,data,String", **options)
149
- # # or
150
- # CSV.parse("CSV,data,String", **options) do |row|
151
- # # ...
152
- # end
152
+ # ==== Parsing a \String
153
+ #
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"]]
153
202
  #
154
- # === Writing
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"]
155
207
  #
156
- # # To a file
157
- # CSV.open("path/to/file.csv", "wb") do |csv|
158
- # csv << ["row", "of", "CSV", "data"]
159
- # csv << ["another", "row"]
160
- # # ...
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
161
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]
233
+ # end
234
+ # output_string # => "foo,0\nbar,1\nbaz,2\n"
235
+ #
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"
239
+ #
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"
243
+ #
244
+ # === "Filtering" \CSV
162
245
  #
163
- # # To a String
164
- # csv_string = CSV.generate do |csv|
165
- # csv << ["row", "of", "CSV", "data"]
166
- # csv << ["another", "row"]
167
- # # ...
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
168
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
309
+ #
310
+ # The default values for options are:
311
+ # DEFAULT_OPTIONS = {
312
+ # # For both parsing and generating.
313
+ # col_sep: ",",
314
+ # row_sep: :auto,
315
+ # quote_char: '"',
316
+ # # For parsing.
317
+ # field_size_limit: nil,
318
+ # converters: nil,
319
+ # unconverted_fields: nil,
320
+ # headers: false,
321
+ # return_headers: false,
322
+ # header_converters: nil,
323
+ # skip_blanks: false,
324
+ # skip_lines: nil,
325
+ # liberal_parsing: false,
326
+ # nil_value: nil,
327
+ # empty_value: "",
328
+ # # For generating.
329
+ # write_headers: nil,
330
+ # quote_empty: true,
331
+ # force_quotes: false,
332
+ # write_converters: nil,
333
+ # write_nil_value: nil,
334
+ # write_empty_value: "",
335
+ # strip: false,
336
+ # }
337
+ #
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.
359
+ #
360
+ # :include: ../doc/csv/options/common/row_sep.rdoc
361
+ #
362
+ # :include: ../doc/csv/options/common/col_sep.rdoc
363
+ #
364
+ # :include: ../doc/csv/options/common/quote_char.rdoc
365
+ #
366
+ # :include: ../doc/csv/options/parsing/field_size_limit.rdoc
367
+ #
368
+ # :include: ../doc/csv/options/parsing/converters.rdoc
369
+ #
370
+ # :include: ../doc/csv/options/parsing/unconverted_fields.rdoc
371
+ #
372
+ # :include: ../doc/csv/options/parsing/headers.rdoc
373
+ #
374
+ # :include: ../doc/csv/options/parsing/return_headers.rdoc
375
+ #
376
+ # :include: ../doc/csv/options/parsing/header_converters.rdoc
377
+ #
378
+ # :include: ../doc/csv/options/parsing/skip_blanks.rdoc
379
+ #
380
+ # :include: ../doc/csv/options/parsing/skip_lines.rdoc
381
+ #
382
+ # :include: ../doc/csv/options/parsing/strip.rdoc
383
+ #
384
+ # :include: ../doc/csv/options/parsing/liberal_parsing.rdoc
385
+ #
386
+ # :include: ../doc/csv/options/parsing/nil_value.rdoc
387
+ #
388
+ # :include: ../doc/csv/options/parsing/empty_value.rdoc
389
+ #
390
+ # ==== Options for Generating
391
+ #
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.
402
+ #
403
+ # :include: ../doc/csv/options/common/row_sep.rdoc
404
+ #
405
+ # :include: ../doc/csv/options/common/col_sep.rdoc
406
+ #
407
+ # :include: ../doc/csv/options/common/quote_char.rdoc
169
408
  #
170
- # === Shortcuts
409
+ # :include: ../doc/csv/options/generating/write_headers.rdoc
171
410
  #
172
- # # Core extensions for converting one line
173
- # csv_string = ["CSV", "data"].to_csv # to CSV
174
- # csv_array = "CSV,String".parse_csv # from CSV
411
+ # :include: ../doc/csv/options/generating/force_quotes.rdoc
175
412
  #
176
- # # CSV() method
177
- # CSV { |csv_out| csv_out << %w{my data here} } # to $stdout
178
- # CSV(csv = "") { |csv_str| csv_str << %w{my data here} } # to a String
179
- # CSV($stderr) { |csv_err| csv_err << %w{my data here} } # to $stderr
180
- # CSV($stdin) { |csv_in| csv_in.each { |row| p row } } # from $stdin
413
+ # :include: ../doc/csv/options/generating/quote_empty.rdoc
181
414
  #
182
- # == Data Conversion
415
+ # :include: ../doc/csv/options/generating/write_converters.rdoc
183
416
  #
184
- # === CSV with headers
417
+ # :include: ../doc/csv/options/generating/write_nil_value.rdoc
418
+ #
419
+ # :include: ../doc/csv/options/generating/write_empty_value.rdoc
420
+ #
421
+ # === \CSV with Headers
185
422
  #
186
423
  # CSV allows to specify column names of CSV file, whether they are in data, or
187
424
  # provided separately. If headers are specified, reading methods return an instance
@@ -203,24 +440,337 @@ using CSV::MatchP if CSV.const_defined?(:MatchP)
203
440
  # data = CSV.parse('Bob,Engineering,1000', headers: %i[name department salary])
204
441
  # data.first #=> #<CSV::Row name:"Bob" department:"Engineering" salary:"1000">
205
442
  #
206
- # === Typed data reading
207
- #
208
- # CSV allows to provide a set of data _converters_ e.g. transformations to try on input
209
- # data. Converter could be a symbol from CSV::Converters constant's keys, or lambda.
210
- #
211
- # # Without any converters:
212
- # CSV.parse('Bob,2018-03-01,100')
213
- # #=> [["Bob", "2018-03-01", "100"]]
214
- #
215
- # # With built-in converters:
216
- # CSV.parse('Bob,2018-03-01,100', converters: %i[numeric date])
217
- # #=> [["Bob", #<Date: 2018-03-01>, 100]]
218
- #
219
- # # With custom converters:
220
- # CSV.parse('Bob,2018-03-01,100', converters: [->(v) { Time.parse(v) rescue v }])
221
- # #=> [["Bob", 2018-03-01 00:00:00 +0200, "100"]]
222
- #
223
- # == CSV and Character Encodings (M17n or Multilingualization)
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.
565
+ # A converter might, for example, convert an integer embedded in a \String
566
+ # into a true \Integer.
567
+ # (In fact, that's what built-in field converter +:integer+ does.)
568
+ #
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"]
589
+ # # Add a converter.
590
+ # csv.convert(:integer)
591
+ # csv.converters # => [:integer]
592
+ # csv.read # => [["bar", 1], ["baz", 2]]
593
+ #
594
+ # There are additional built-in \converters, and custom \converters are also supported.
595
+ #
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:
625
+ # data = '0,1,2,x'
626
+ # # Without the converter
627
+ # csv = CSV.parse_line(data)
628
+ # csv # => ["0", "1", "2", "x"]
629
+ # # With the converter
630
+ # csv = CSV.parse_line(data, converters: :integer)
631
+ # csv # => [0, 1, 2, "x"]
632
+ #
633
+ # Converter +:float+ converts each field that Float() accepts:
634
+ # data = '1.0,3.14159,x'
635
+ # # Without the converter
636
+ # csv = CSV.parse_line(data)
637
+ # csv # => ["1.0", "3.14159", "x"]
638
+ # # With the converter
639
+ # csv = CSV.parse_line(data, converters: :float)
640
+ # csv # => [1.0, 3.14159, "x"]
641
+ #
642
+ # Converter +:numeric+ converts with both +:integer+ and +:float+..
643
+ #
644
+ # Converter +:date+ converts each field that Date::parse accepts:
645
+ # data = '2001-02-03,x'
646
+ # # Without the converter
647
+ # csv = CSV.parse_line(data)
648
+ # csv # => ["2001-02-03", "x"]
649
+ # # With the converter
650
+ # csv = CSV.parse_line(data, converters: :date)
651
+ # csv # => [#<Date: 2001-02-03 ((2451944j,0s,0n),+0s,2299161j)>, "x"]
652
+ #
653
+ # Converter +:date_time+ converts each field that DateTime::parse accepts:
654
+ # data = '2020-05-07T14:59:00-05:00,x'
655
+ # # Without the converter
656
+ # csv = CSV.parse_line(data)
657
+ # csv # => ["2020-05-07T14:59:00-05:00", "x"]
658
+ # # With the converter
659
+ # csv = CSV.parse_line(data, converters: :date_time)
660
+ # csv # => [#<DateTime: 2020-05-07T14:59:00-05:00 ((2458977j,71940s,0n),-18000s,2299161j)>, "x"]
661
+ #
662
+ # Converter +:numeric+ converts with both +:date_time+ and +:numeric+..
663
+ #
664
+ # As seen above, method #convert adds \converters to a \CSV instance,
665
+ # and method #converters returns an \Array of the \converters in effect:
666
+ # csv = CSV.new('0,1,2')
667
+ # csv.converters # => []
668
+ # csv.convert(:integer)
669
+ # csv.converters # => [:integer]
670
+ # csv.convert(:date)
671
+ # csv.converters # => [:integer, :date]
672
+ #
673
+ # ===== Custom Field \Converters
674
+ #
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"]]
683
+ #
684
+ # ==== Header \Converters
685
+ #
686
+ # Header converters operate only on headers (and not on other rows).
687
+ #
688
+ # There are three ways to use header \converters;
689
+ # these examples use built-in header converter +:dowhcase+,
690
+ # which downcases each parsed header.
691
+ #
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:
717
+ # CSV::HeaderConverters.keys # => [:downcase, :symbol]
718
+ #
719
+ # Converter +:downcase+ converts each header by downcasing it:
720
+ # string = "Name,Count\nFoo,0\n,Bar,1\nBaz,2"
721
+ # tbl = CSV.parse(string, headers: true, header_converters: :downcase)
722
+ # tbl.class # => CSV::Table
723
+ # tbl.headers # => ["name", "count"]
724
+ #
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)
728
+ # tbl.headers # => [:name, :count]
729
+ # Details:
730
+ # - Strips leading and trailing whitespace.
731
+ # - Downcases the header.
732
+ # - Replaces embedded spaces with underscores.
733
+ # - Removes non-word characters.
734
+ # - Makes the string into a \Symbol.
735
+ #
736
+ # ===== Custom Header \Converters
737
+ #
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"]
747
+ #
748
+ # ===== Write \Converters
749
+ #
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)
224
774
  #
225
775
  # This new CSV parser is m17n savvy. The parser works in the Encoding of the IO
226
776
  # or String object being read from or written to. Your data is never transcoded
@@ -301,30 +851,12 @@ class CSV
301
851
  # The encoding used by all converters.
302
852
  ConverterEncoding = Encoding.find("UTF-8")
303
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].
304
856
  #
305
- # This Hash holds the built-in converters of CSV that can be accessed by name.
306
- # You can select Converters with CSV.convert() or through the +options+ Hash
307
- # passed to CSV::new().
308
- #
309
- # <b><tt>:integer</tt></b>:: Converts any field Integer() accepts.
310
- # <b><tt>:float</tt></b>:: Converts any field Float() accepts.
311
- # <b><tt>:numeric</tt></b>:: A combination of <tt>:integer</tt>
312
- # and <tt>:float</tt>.
313
- # <b><tt>:date</tt></b>:: Converts any field Date::parse() accepts.
314
- # <b><tt>:date_time</tt></b>:: Converts any field DateTime::parse() accepts.
315
- # <b><tt>:all</tt></b>:: All built-in converters. A combination of
316
- # <tt>:date_time</tt> and <tt>:numeric</tt>.
317
- #
318
- # All built-in converters transcode field data to UTF-8 before attempting a
319
- # conversion. If your data cannot be transcoded to UTF-8 the conversion will
320
- # fail and the field will remain unchanged.
321
- #
322
- # This Hash is intentionally left unfrozen and users should feel free to add
323
- # values to it that can be accessed by all CSV objects.
324
- #
325
- # To add a combo field, the value should be an Array of names. Combo fields
326
- # can be nested with other combo fields.
327
- #
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].
328
860
  Converters = {
329
861
  integer: lambda { |f|
330
862
  Integer(f.encode(ConverterEncoding)) rescue f
@@ -352,27 +884,12 @@ class CSV
352
884
  all: [:date_time, :numeric],
353
885
  }
354
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].
355
889
  #
356
- # This Hash holds the built-in header converters of CSV that can be accessed
357
- # by name. You can select HeaderConverters with CSV.header_convert() or
358
- # through the +options+ Hash passed to CSV::new().
359
- #
360
- # <b><tt>:downcase</tt></b>:: Calls downcase() on the header String.
361
- # <b><tt>:symbol</tt></b>:: Leading/trailing spaces are dropped, string is
362
- # downcased, remaining spaces are replaced with
363
- # underscores, non-word characters are dropped,
364
- # and finally to_sym() is called.
365
- #
366
- # All built-in header converters transcode header data to UTF-8 before
367
- # attempting a conversion. If your data cannot be transcoded to UTF-8 the
368
- # conversion will fail and the header will remain unchanged.
369
- #
370
- # This Hash is intentionally left unfrozen and users should feel free to add
371
- # values to it that can be accessed by all CSV objects.
372
- #
373
- # To add a combo field, the value should be an Array of names. Combo fields
374
- # can be nested with other combo fields.
375
- #
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].
376
893
  HeaderConverters = {
377
894
  downcase: lambda { |h| h.encode(ConverterEncoding).downcase },
378
895
  symbol: lambda { |h|
@@ -380,29 +897,13 @@ class CSV
380
897
  gsub(/\s+/, "_").to_sym
381
898
  }
382
899
  }
383
-
384
- #
385
- # The options used when no overrides are given by calling code. They are:
386
- #
387
- # <b><tt>:col_sep</tt></b>:: <tt>","</tt>
388
- # <b><tt>:row_sep</tt></b>:: <tt>:auto</tt>
389
- # <b><tt>:quote_char</tt></b>:: <tt>'"'</tt>
390
- # <b><tt>:field_size_limit</tt></b>:: +nil+
391
- # <b><tt>:converters</tt></b>:: +nil+
392
- # <b><tt>:unconverted_fields</tt></b>:: +nil+
393
- # <b><tt>:headers</tt></b>:: +false+
394
- # <b><tt>:return_headers</tt></b>:: +false+
395
- # <b><tt>:header_converters</tt></b>:: +nil+
396
- # <b><tt>:skip_blanks</tt></b>:: +false+
397
- # <b><tt>:force_quotes</tt></b>:: +false+
398
- # <b><tt>:skip_lines</tt></b>:: +nil+
399
- # <b><tt>:liberal_parsing</tt></b>:: +false+
400
- # <b><tt>:quote_empty</tt></b>:: +true+
401
- #
900
+ # Default values for method options.
402
901
  DEFAULT_OPTIONS = {
902
+ # For both parsing and generating.
403
903
  col_sep: ",",
404
904
  row_sep: :auto,
405
905
  quote_char: '"',
906
+ # For parsing.
406
907
  field_size_limit: nil,
407
908
  converters: nil,
408
909
  unconverted_fields: nil,
@@ -410,22 +911,62 @@ class CSV
410
911
  return_headers: false,
411
912
  header_converters: nil,
412
913
  skip_blanks: false,
413
- force_quotes: false,
414
914
  skip_lines: nil,
415
915
  liberal_parsing: false,
916
+ nil_value: nil,
917
+ empty_value: "",
918
+ # For generating.
919
+ write_headers: nil,
416
920
  quote_empty: true,
921
+ force_quotes: false,
922
+ write_converters: nil,
923
+ write_nil_value: nil,
924
+ write_empty_value: "",
925
+ strip: false,
417
926
  }.freeze
418
927
 
419
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| ... }
934
+ #
935
+ # Creates or retrieves cached \CSV objects.
936
+ # For arguments and options, see CSV.new.
937
+ #
938
+ # ---
420
939
  #
421
- # This method will return a CSV instance, just like CSV::new(), but the
422
- # instance will be cached and returned for all future calls to this method for
423
- # the same +data+ object (tested by Object#object_id()) with the same
424
- # +options+.
940
+ # With no block given, returns a \CSV object.
425
941
  #
426
- # If a block is given, the instance is passed to the block and the return
427
- # value becomes the return value of the block.
942
+ # The first call to +instance+ creates and caches a \CSV object:
943
+ # s0 = 's0'
944
+ # csv0 = CSV.instance(s0)
945
+ # csv0.class # => CSV
428
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
429
970
  def instance(data = $stdout, **options)
430
971
  # create a _signature_ for this method call, data object and options
431
972
  sig = [data.object_id] +
@@ -442,30 +983,61 @@ class CSV
442
983
  end
443
984
  end
444
985
 
445
- #
446
986
  # :call-seq:
447
- # filter( **options ) { |row| ... }
448
- # filter( input, **options ) { |row| ... }
449
- # filter( input, output, **options ) { |row| ... }
450
- #
451
- # This method is a convenience for building Unix-like filters for CSV data.
452
- # Each row is yielded to the provided block which can alter it as needed.
453
- # After the block returns, the row is appended to +output+ altered or not.
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| ... }
454
994
  #
455
- # The +input+ and +output+ arguments can be anything CSV::new() accepts
456
- # (generally String or IO objects). If not given, they default to
457
- # <tt>ARGF</tt> and <tt>$stdout</tt>.
995
+ # Reads \CSV input and writes \CSV output.
458
996
  #
459
- # The +options+ parameter is also filtered down to CSV::new() after some
460
- # clever key parsing. Any key beginning with <tt>:in_</tt> or
461
- # <tt>:input_</tt> will have that leading identifier stripped and will only
462
- # be used in the +options+ Hash for the +input+ object. Keys starting with
463
- # <tt>:out_</tt> or <tt>:output_</tt> affect only +output+. All other keys
464
- # are assigned to both objects.
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.
465
1003
  #
466
- # The <tt>:output_row_sep</tt> +option+ defaults to
467
- # <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].
468
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"
469
1041
  def filter(input=nil, output=nil, **options)
470
1042
  # parse options for input, output, or both
471
1043
  in_options, out_options = Hash.new, {row_sep: $INPUT_RECORD_SEPARATOR}
@@ -492,18 +1064,111 @@ class CSV
492
1064
  end
493
1065
 
494
1066
  #
495
- # This method is intended as the primary interface for reading CSV files. You
496
- # pass a +path+ and any +options+ you wish to set for the read. Each row of
497
- # 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/csv/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.
1134
+ #
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)
1139
+ #
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">
498
1147
  #
499
- # The +options+ parameter can be anything CSV::new() understands. This method
500
- # also understands an additional <tt>:encoding</tt> parameter that you can use
501
- # to specify the Encoding of the data in the file to be read. You must provide
502
- # this unless your data is in Encoding::default_external(). CSV will use this
503
- # to determine how to parse the data. You may provide a second Encoding to
504
- # have the data transcoded as it is read. For example,
505
- # <tt>encoding: "UTF-32BE:UTF-8"</tt> would read UTF-32BE data from the file
506
- # but transcode it to UTF-8 before CSV parses it.
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| }
507
1172
  #
508
1173
  def foreach(path, mode="r", **options, &block)
509
1174
  return to_enum(__method__, path, mode, **options) unless block_given?
@@ -514,29 +1179,71 @@ class CSV
514
1179
 
515
1180
  #
516
1181
  # :call-seq:
517
- # generate( str, **options ) { |csv| ... }
518
- # generate( **options ) { |csv| ... }
1182
+ # generate(csv_string, **options) {|csv| ... }
1183
+ # generate(**options) {|csv| ... }
1184
+ #
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].
1189
+ #
1190
+ # ---
519
1191
  #
520
- # This method wraps a String you provide, or an empty default String, in a
521
- # CSV object which is passed to the provided block. You can use the block to
522
- # append CSV rows to the String and when the block exits, the final String
523
- # will be returned.
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.
524
1195
  #
525
- # Note that a passed String *is* modified by this method. Call dup() before
526
- # passing if you need a new String.
1196
+ # Note that a passed \String *is* modified by this method.
1197
+ # Pass <tt>csv_string</tt>.dup if the \String must be preserved.
527
1198
  #
528
- # The +options+ parameter can be anything CSV::new() understands. This method
529
- # understands an additional <tt>:encoding</tt> parameter when not passed a
530
- # String to set the base Encoding for the output. CSV needs this hint if you
531
- # plan to output non-ASCII compatible data.
1199
+ # This method has one additional option: <tt>:encoding</tt>,
1200
+ # which sets the base Encoding for the output if no no +str+ is specified.
1201
+ # CSV needs this hint if you plan to output non-ASCII compatible data.
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)
532
1238
  #
533
1239
  def generate(str=nil, **options)
1240
+ encoding = options[:encoding]
534
1241
  # add a default empty String, if none was given
535
1242
  if str
536
1243
  str = StringIO.new(str)
537
1244
  str.seek(0, IO::SEEK_END)
1245
+ str.set_encoding(encoding) if encoding
538
1246
  else
539
- encoding = options[:encoding]
540
1247
  str = +""
541
1248
  str.force_encoding(encoding) if encoding
542
1249
  end
@@ -545,97 +1252,140 @@ class CSV
545
1252
  csv.string # return final String
546
1253
  end
547
1254
 
1255
+ # :call-seq:
1256
+ # CSV.generate_line(ary)
1257
+ # CSV.generate_line(ary, **options)
548
1258
  #
549
- # This method is a shortcut for converting a single row (Array) into a CSV
550
- # String.
1259
+ # Returns the \String created by generating \CSV from +ary+
1260
+ # using the specified +options+.
551
1261
  #
552
- # The +options+ parameter can be anything CSV::new() understands. This method
553
- # understands an additional <tt>:encoding</tt> parameter to set the base
554
- # Encoding for the output. This method will try to guess your Encoding from
555
- # the first non-+nil+ field in +row+, if possible, but you may need to use
556
- # this parameter as a backup plan.
1262
+ # Argument +ary+ must be an \Array.
557
1263
  #
558
- # The <tt>:row_sep</tt> +option+ defaults to <tt>$INPUT_RECORD_SEPARATOR</tt>
559
- # (<tt>$/</tt>) when calling this method.
1264
+ # Special options:
1265
+ # * Option <tt>:row_sep</tt> defaults to <tt>$INPUT_RECORD_SEPARATOR</tt>
1266
+ # (<tt>$/</tt>).:
1267
+ # $INPUT_RECORD_SEPARATOR # => "\n"
1268
+ # * This method accepts an additional option, <tt>:encoding</tt>, which sets the base
1269
+ # Encoding for the output. This method will try to guess your Encoding from
1270
+ # the first non-+nil+ field in +row+, if possible, but you may need to use
1271
+ # this parameter as a backup plan.
1272
+ #
1273
+ # For other +options+,
1274
+ # see {Options for Generating}[#class-CSV-label-Options+for+Generating].
1275
+ #
1276
+ # ---
1277
+ #
1278
+ # Returns the \String generated from an \Array:
1279
+ # CSV.generate_line(['foo', '0']) # => "foo,0\n"
1280
+ #
1281
+ # ---
1282
+ #
1283
+ # Raises an exception if +ary+ is not an \Array:
1284
+ # # Raises NoMethodError (undefined method `find' for :foo:Symbol)
1285
+ # CSV.generate_line(:foo)
560
1286
  #
561
1287
  def generate_line(row, **options)
562
1288
  options = {row_sep: $INPUT_RECORD_SEPARATOR}.merge(options)
563
1289
  str = +""
564
1290
  if options[:encoding]
565
1291
  str.force_encoding(options[:encoding])
566
- elsif field = row.find {|f| f.is_a?(String)}
567
- 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
568
1306
  end
569
1307
  (new(str, **options) << row).string
570
1308
  end
571
1309
 
572
1310
  #
573
1311
  # :call-seq:
574
- # open( filename, mode = "rb", **options ) { |faster_csv| ... }
575
- # open( filename, **options ) { |faster_csv| ... }
576
- # open( filename, mode = "rb", **options )
577
- # open( filename, **options )
578
- #
579
- # This method opens an IO object, and wraps that with CSV. This is intended
580
- # as the primary interface for writing a CSV file.
581
- #
582
- # You must pass a +filename+ and may optionally add a +mode+ for Ruby's
583
- # open(). You may also pass an optional Hash containing any +options+
584
- # CSV::new() understands as the final argument.
585
- #
586
- # This method works like Ruby's open() call, in that it will pass a CSV object
587
- # to a provided block and close it when the block terminates, or it will
588
- # return the CSV object when no block is provided. (*Note*: This is different
589
- # from the Ruby 1.8 CSV library which passed rows to the block. Use
590
- # CSV::foreach() for that behavior.)
591
- #
592
- # You must provide a +mode+ with an embedded Encoding designator unless your
593
- # data is in Encoding::default_external(). CSV will check the Encoding of the
594
- # underlying IO object (set by the +mode+ you pass) to determine how to parse
595
- # the data. You may provide a second Encoding to have the data transcoded as
596
- # it is read just as you can with a normal call to IO::open(). For example,
597
- # <tt>"rb:UTF-32BE:UTF-8"</tt> would read UTF-32BE data from the file but
598
- # transcode it to UTF-8 before CSV parses it.
599
- #
600
- # An opened CSV object will delegate to many IO methods for convenience. You
601
- # may call:
602
- #
603
- # * binmode()
604
- # * binmode?()
605
- # * close()
606
- # * close_read()
607
- # * close_write()
608
- # * closed?()
609
- # * eof()
610
- # * eof?()
611
- # * external_encoding()
612
- # * fcntl()
613
- # * fileno()
614
- # * flock()
615
- # * flush()
616
- # * fsync()
617
- # * internal_encoding()
618
- # * ioctl()
619
- # * isatty()
620
- # * path()
621
- # * pid()
622
- # * pos()
623
- # * pos=()
624
- # * reopen()
625
- # * seek()
626
- # * stat()
627
- # * sync()
628
- # * sync=()
629
- # * tell()
630
- # * to_i()
631
- # * to_io()
632
- # * truncate()
633
- # * 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/csv/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.
634
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)
635
1382
  def open(filename, mode="r", **options)
636
1383
  # wrap a File opened with the remaining +args+ with no newline
637
1384
  # decorator
638
1385
  file_opts = {universal_newline: false}.merge(options)
1386
+ options.delete(:invalid)
1387
+ options.delete(:undef)
1388
+ options.delete(:replace)
639
1389
 
640
1390
  begin
641
1391
  f = File.open(filename, mode, **file_opts)
@@ -666,16 +1416,116 @@ class CSV
666
1416
 
667
1417
  #
668
1418
  # :call-seq:
669
- # parse( str, **options ) { |row| ... }
670
- # 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/csv/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.
671
1445
  #
672
- # This method can be used to easily parse CSV out of a String. You may either
673
- # provide a +block+ which will be called with each row of the String in turn,
674
- # or just use the returned Array of Arrays (when no +block+ is given).
1446
+ # Parse a \String:
1447
+ # a_of_a = CSV.parse(string)
1448
+ # a_of_a # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
675
1449
  #
676
- # You pass your +str+ to read from, and an optional +options+ containing
677
- # anything CSV::new() understands.
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"]]
678
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 }
1462
+ #
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
+ # ---
1488
+ #
1489
+ # With no block given, returns a CSV::Table object formed from the source.
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)
679
1529
  def parse(str, **options, &block)
680
1530
  csv = new(str, **options)
681
1531
 
@@ -689,44 +1539,117 @@ class CSV
689
1539
  end
690
1540
  end
691
1541
 
1542
+ # :call-seq:
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
1549
+ #
1550
+ # Returns the data created by parsing the first line of +string+ or +io+
1551
+ # using the specified +options+.
1552
+ #
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/csv/arguments/io.rdoc
1556
+ # - Argument +options+: see {Options for Parsing}[#class-CSV-label-Options+for+Parsing]
1557
+ #
1558
+ # ====== Without Option +headers+
1559
+ #
1560
+ # Without option +headers+, returns the first row as a new \Array.
1561
+ #
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)
1566
+ #
1567
+ # Parse the first line from a \String object:
1568
+ # CSV.parse_line(string) # => ["foo", "0"]
1569
+ #
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"]
1574
+ #
1575
+ # Returns +nil+ if the argument is an empty \String:
1576
+ # CSV.parse_line('') # => nil
692
1577
  #
693
- # This method is a shortcut for converting a single line of a CSV String into
694
- # an Array. Note that if +line+ contains multiple rows, anything beyond the
695
- # first row is ignored.
1578
+ # ====== With Option +headers+
696
1579
  #
697
- # The +options+ parameter can be anything CSV::new() understands.
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
+ #
1596
+ # ---
1597
+ #
1598
+ # Raises an exception if the argument is +nil+:
1599
+ # # Raises ArgumentError (Cannot parse nil as CSV):
1600
+ # CSV.parse_line(nil)
698
1601
  #
699
1602
  def parse_line(line, **options)
700
- new(line, **options).shift
1603
+ new(line, **options).each.first
701
1604
  end
702
1605
 
703
1606
  #
704
- # Use to slurp a CSV file into an Array of Arrays. Pass the +path+ to the
705
- # file and any +options+ CSV::new() understands. This method also understands
706
- # an additional <tt>:encoding</tt> parameter that you can use to specify the
707
- # Encoding of the data in the file to be read. You must provide this unless
708
- # your data is in Encoding::default_external(). CSV will use this to determine
709
- # how to parse the data. You may provide a second Encoding to have the data
710
- # transcoded as it is read. For example,
711
- # <tt>encoding: "UTF-32BE:UTF-8"</tt> would read UTF-32BE data from the file
712
- # but transcode it to UTF-8 before CSV parses it.
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.
713
1614
  #
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"]]
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>
714
1626
  def read(path, **options)
715
1627
  open(path, **options) { |csv| csv.read }
716
1628
  end
717
1629
 
718
- # Alias for CSV::read().
1630
+ # :call-seq:
1631
+ # CSV.readlines(source, **options)
1632
+ #
1633
+ # Alias for CSV.read.
719
1634
  def readlines(path, **options)
720
1635
  read(path, **options)
721
1636
  end
722
1637
 
1638
+ # :call-seq:
1639
+ # CSV.table(source, **options)
723
1640
  #
724
- # A shortcut for:
1641
+ # Calls CSV.read with +source+, +options+, and certain default options:
1642
+ # - +headers+: +true+
1643
+ # - +converbers+: +:numeric+
1644
+ # - +header_converters+: +:symbol+
725
1645
  #
726
- # CSV.read( path, { headers: true,
727
- # converters: :numeric,
728
- # header_converters: :symbol }.merge(options) )
1646
+ # Returns a CSV::Table object.
729
1647
  #
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>
730
1653
  def table(path, **options)
731
1654
  default_options = {
732
1655
  headers: true,
@@ -738,185 +1661,43 @@ class CSV
738
1661
  end
739
1662
  end
740
1663
 
1664
+ # :call-seq:
1665
+ # CSV.new(string)
1666
+ # CSV.new(io)
1667
+ # CSV.new(string, **options)
1668
+ # CSV.new(io, **options)
1669
+ #
1670
+ # Returns the new \CSV object created using +string+ or +io+
1671
+ # and the specified +options+.
1672
+ #
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/csv/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.
741
1681
  #
742
- # This constructor will wrap either a String or IO object passed in +data+ for
743
- # reading and/or writing. In addition to the CSV instance methods, several IO
744
- # methods are delegated. (See CSV::open() for a complete list.) If you pass
745
- # a String for +data+, you can later retrieve it (after writing to it, for
746
- # example) with CSV.string().
747
- #
748
- # Note that a wrapped String will be positioned at the beginning (for
749
- # reading). If you want it at the end (for writing), use CSV::generate().
750
- # If you want any other positioning, pass a preset StringIO object instead.
751
- #
752
- # You may set any reading and/or writing preferences in the +options+ Hash.
753
- # Available options are:
754
- #
755
- # <b><tt>:col_sep</tt></b>:: The String placed between each field.
756
- # This String will be transcoded into
757
- # the data's Encoding before parsing.
758
- # <b><tt>:row_sep</tt></b>:: The String appended to the end of each
759
- # row. This can be set to the special
760
- # <tt>:auto</tt> setting, which requests
761
- # that CSV automatically discover this
762
- # from the data. Auto-discovery reads
763
- # ahead in the data looking for the next
764
- # <tt>"\r\n"</tt>, <tt>"\n"</tt>, or
765
- # <tt>"\r"</tt> sequence. A sequence
766
- # will be selected even if it occurs in
767
- # a quoted field, assuming that you
768
- # would have the same line endings
769
- # there. If none of those sequences is
770
- # found, +data+ is <tt>ARGF</tt>,
771
- # <tt>STDIN</tt>, <tt>STDOUT</tt>, or
772
- # <tt>STDERR</tt>, or the stream is only
773
- # available for output, the default
774
- # <tt>$INPUT_RECORD_SEPARATOR</tt>
775
- # (<tt>$/</tt>) is used. Obviously,
776
- # discovery takes a little time. Set
777
- # manually if speed is important. Also
778
- # note that IO objects should be opened
779
- # in binary mode on Windows if this
780
- # feature will be used as the
781
- # line-ending translation can cause
782
- # problems with resetting the document
783
- # position to where it was before the
784
- # read ahead. This String will be
785
- # transcoded into the data's Encoding
786
- # before parsing.
787
- # <b><tt>:quote_char</tt></b>:: The character used to quote fields.
788
- # This has to be a single character
789
- # String. This is useful for
790
- # application that incorrectly use
791
- # <tt>'</tt> as the quote character
792
- # instead of the correct <tt>"</tt>.
793
- # CSV will always consider a double
794
- # sequence of this character to be an
795
- # escaped quote. This String will be
796
- # transcoded into the data's Encoding
797
- # before parsing.
798
- # <b><tt>:field_size_limit</tt></b>:: This is a maximum size CSV will read
799
- # ahead looking for the closing quote
800
- # for a field. (In truth, it reads to
801
- # the first line ending beyond this
802
- # size.) If a quote cannot be found
803
- # within the limit CSV will raise a
804
- # MalformedCSVError, assuming the data
805
- # is faulty. You can use this limit to
806
- # prevent what are effectively DoS
807
- # attacks on the parser. However, this
808
- # limit can cause a legitimate parse to
809
- # fail and thus is set to +nil+, or off,
810
- # by default.
811
- # <b><tt>:converters</tt></b>:: An Array of names from the Converters
812
- # Hash and/or lambdas that handle custom
813
- # conversion. A single converter
814
- # doesn't have to be in an Array. All
815
- # built-in converters try to transcode
816
- # fields to UTF-8 before converting.
817
- # The conversion will fail if the data
818
- # cannot be transcoded, leaving the
819
- # field unchanged.
820
- # <b><tt>:unconverted_fields</tt></b>:: If set to +true+, an
821
- # unconverted_fields() method will be
822
- # added to all returned rows (Array or
823
- # CSV::Row) that will return the fields
824
- # as they were before conversion. Note
825
- # that <tt>:headers</tt> supplied by
826
- # Array or String were not fields of the
827
- # document and thus will have an empty
828
- # Array attached.
829
- # <b><tt>:headers</tt></b>:: If set to <tt>:first_row</tt> or
830
- # +true+, the initial row of the CSV
831
- # file will be treated as a row of
832
- # headers. If set to an Array, the
833
- # contents will be used as the headers.
834
- # If set to a String, the String is run
835
- # through a call of CSV::parse_line()
836
- # with the same <tt>:col_sep</tt>,
837
- # <tt>:row_sep</tt>, and
838
- # <tt>:quote_char</tt> as this instance
839
- # to produce an Array of headers. This
840
- # setting causes CSV#shift() to return
841
- # rows as CSV::Row objects instead of
842
- # Arrays and CSV#read() to return
843
- # CSV::Table objects instead of an Array
844
- # of Arrays.
845
- # <b><tt>:return_headers</tt></b>:: When +false+, header rows are silently
846
- # swallowed. If set to +true+, header
847
- # rows are returned in a CSV::Row object
848
- # with identical headers and
849
- # fields (save that the fields do not go
850
- # through the converters).
851
- # <b><tt>:write_headers</tt></b>:: When +true+ and <tt>:headers</tt> is
852
- # set, a header row will be added to the
853
- # output.
854
- # <b><tt>:header_converters</tt></b>:: Identical in functionality to
855
- # <tt>:converters</tt> save that the
856
- # conversions are only made to header
857
- # rows. All built-in converters try to
858
- # transcode headers to UTF-8 before
859
- # converting. The conversion will fail
860
- # if the data cannot be transcoded,
861
- # leaving the header unchanged.
862
- # <b><tt>:skip_blanks</tt></b>:: When setting a +true+ value, CSV will
863
- # skip over any empty rows. Note that
864
- # this setting will not skip rows that
865
- # contain column separators, even if
866
- # the rows contain no actual data. If
867
- # you want to skip rows that contain
868
- # separators but no content, consider
869
- # using <tt>:skip_lines</tt>, or
870
- # inspecting fields.compact.empty? on
871
- # each row.
872
- # <b><tt>:force_quotes</tt></b>:: When setting a +true+ value, CSV will
873
- # quote all CSV fields it creates.
874
- # <b><tt>:skip_lines</tt></b>:: When setting an object responding to
875
- # <tt>match</tt>, every line matching
876
- # it is considered a comment and ignored
877
- # during parsing. When set to a String,
878
- # it is first converted to a Regexp.
879
- # When set to +nil+ no line is considered
880
- # a comment. If the passed object does
881
- # not respond to <tt>match</tt>,
882
- # <tt>ArgumentError</tt> is thrown.
883
- # <b><tt>:liberal_parsing</tt></b>:: When setting a +true+ value, CSV will
884
- # attempt to parse input not conformant
885
- # with RFC 4180, such as double quotes
886
- # in unquoted fields.
887
- # <b><tt>:nil_value</tt></b>:: When set an object, any values of an
888
- # empty field is replaced by the set
889
- # object, not nil.
890
- # <b><tt>:empty_value</tt></b>:: When setting an object, any values of a
891
- # blank string field is replaced by
892
- # the set object.
893
- # <b><tt>:quote_empty</tt></b>:: When setting a +true+ value, CSV will
894
- # quote empty values with double quotes.
895
- # When +false+, CSV will emit an
896
- # empty string for an empty field value.
897
- # <b><tt>:write_converters</tt></b>:: Converts values on each line with the
898
- # specified <tt>Proc</tt> object(s),
899
- # which receive a <tt>String</tt> value
900
- # and return a <tt>String</tt> or +nil+
901
- # value.
902
- # When an array is specified, each
903
- # converter will be applied in order.
904
- # <b><tt>:write_nil_value</tt></b>:: When a <tt>String</tt> value, +nil+
905
- # value(s) on each line will be replaced
906
- # with the specified value.
907
- # <b><tt>:write_empty_value</tt></b>:: When a <tt>String</tt> or +nil+ value,
908
- # empty value(s) on each line will be
909
- # replaced with the specified value.
910
- # <b><tt>:strip</tt></b>:: When setting a +true+ value, CSV will
911
- # strip "\t\r\n\f\v" around the values.
912
- # If you specify a string instead of
913
- # +true+, CSV will strip string. The
914
- # length of the string must be 1.
915
- #
916
- # See CSV::DEFAULT_OPTIONS for the default settings.
917
- #
918
- # Options cannot be overridden in the instance methods for performance reasons,
919
- # so be sure to set what you want here.
1682
+ # In addition to the \CSV instance methods, several \IO methods are delegated.
1683
+ # See {Delegated Methods}[#class-CSV-label-Delegated+Methods].
1684
+ #
1685
+ # ---
1686
+ #
1687
+ # Create a \CSV object from a \String object:
1688
+ # csv = CSV.new('foo,0')
1689
+ # csv # => #<CSV io_type:StringIO encoding:UTF-8 lineno:0 col_sep:"," row_sep:"\n" quote_char:"\"">
1690
+ #
1691
+ # Create a \CSV object from a \File object:
1692
+ # File.write('t.csv', 'foo,0')
1693
+ # csv = CSV.new(File.open('t.csv'))
1694
+ # csv # => #<CSV io_type:File io_path:"t.csv" encoding:UTF-8 lineno:0 col_sep:"," row_sep:"\n" quote_char:"\"">
1695
+ #
1696
+ # ---
1697
+ #
1698
+ # Raises an exception if the argument is +nil+:
1699
+ # # Raises ArgumentError (Cannot parse nil as CSV):
1700
+ # CSV.new(nil)
920
1701
  #
921
1702
  def initialize(data,
922
1703
  col_sep: ",",
@@ -1001,51 +1782,67 @@ class CSV
1001
1782
  writer if @writer_options[:write_headers]
1002
1783
  end
1003
1784
 
1785
+ # :call-seq:
1786
+ # csv.col_sep -> string
1004
1787
  #
1005
- # The encoded <tt>:col_sep</tt> used in parsing and writing.
1006
- # See CSV::new for details.
1007
- #
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 # => ","
1008
1791
  def col_sep
1009
1792
  parser.column_separator
1010
1793
  end
1011
1794
 
1795
+ # :call-seq:
1796
+ # csv.row_sep -> string
1012
1797
  #
1013
- # The encoded <tt>:row_sep</tt> used in parsing and writing.
1014
- # See CSV::new for details.
1015
- #
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"
1016
1801
  def row_sep
1017
1802
  parser.row_separator
1018
1803
  end
1019
1804
 
1805
+ # :call-seq:
1806
+ # csv.quote_char -> character
1020
1807
  #
1021
- # The encoded <tt>:quote_char</tt> used in parsing and writing.
1022
- # See CSV::new for details.
1023
- #
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 # => "\""
1024
1811
  def quote_char
1025
1812
  parser.quote_character
1026
1813
  end
1027
1814
 
1815
+ # :call-seq:
1816
+ # csv.field_size_limit -> integer or nil
1028
1817
  #
1029
- # The limit for field size, if any.
1030
- # See CSV::new for details.
1031
- #
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
1032
1821
  def field_size_limit
1033
1822
  parser.field_size_limit
1034
1823
  end
1035
1824
 
1825
+ # :call-seq:
1826
+ # csv.skip_lines -> regexp or nil
1036
1827
  #
1037
- # The regex marking a line as a comment.
1038
- # See CSV::new for details.
1039
- #
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
1040
1831
  def skip_lines
1041
1832
  parser.skip_lines
1042
1833
  end
1043
1834
 
1044
- #
1045
- # Returns the current list of converters in effect. See CSV::new for details.
1046
- # Built-in converters will be returned by name, while others will be returned
1047
- # as is.
1048
- #
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
1049
1846
  def converters
1050
1847
  parser_fields_converter.map do |converter|
1051
1848
  name = Converters.rassoc(converter)
@@ -1053,19 +1850,23 @@ class CSV
1053
1850
  end
1054
1851
  end
1055
1852
 
1853
+ # :call-seq:
1854
+ # csv.unconverted_fields? -> object
1056
1855
  #
1057
- # Returns +true+ if unconverted_fields() to parsed results.
1058
- # See CSV::new for details.
1059
- #
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
1060
1860
  def unconverted_fields?
1061
1861
  parser.unconverted_fields?
1062
1862
  end
1063
1863
 
1864
+ # :call-seq:
1865
+ # csv.headers -> object
1064
1866
  #
1065
- # Returns +nil+ if headers will not be used, +true+ if they will but have not
1066
- # yet been read, or the actual headers after they have been read.
1067
- # See CSV::new for details.
1068
- #
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
1069
1870
  def headers
1070
1871
  if @writer
1071
1872
  @writer.headers
@@ -1077,27 +1878,33 @@ class CSV
1077
1878
  raw_headers
1078
1879
  end
1079
1880
  end
1881
+
1882
+ # :call-seq:
1883
+ # csv.return_headers? -> true or false
1080
1884
  #
1081
- # Returns +true+ if headers will be returned as a row of results.
1082
- # See CSV::new for details.
1083
- #
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
1084
1888
  def return_headers?
1085
1889
  parser.return_headers?
1086
1890
  end
1087
1891
 
1892
+ # :call-seq:
1893
+ # csv.write_headers? -> true or false
1088
1894
  #
1089
- # Returns +true+ if headers are written in output.
1090
- # See CSV::new for details.
1091
- #
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
1092
1898
  def write_headers?
1093
1899
  @writer_options[:write_headers]
1094
1900
  end
1095
1901
 
1902
+ # :call-seq:
1903
+ # csv.header_converters -> array
1096
1904
  #
1097
- # Returns the current list of converters in effect for headers. See CSV::new
1098
- # for details. Built-in converters will be returned by name, while others
1099
- # will be returned as is.
1100
- #
1905
+ # Returns an \Array containing header converters; used for parsing;
1906
+ # see {Header Converters}[#class-CSV-label-Header+Converters]:
1907
+ # CSV.new('').header_converters # => []
1101
1908
  def header_converters
1102
1909
  header_fields_converter.map do |converter|
1103
1910
  name = HeaderConverters.rassoc(converter)
@@ -1105,34 +1912,74 @@ class CSV
1105
1912
  end
1106
1913
  end
1107
1914
 
1915
+ # :call-seq:
1916
+ # csv.skip_blanks? -> true or false
1108
1917
  #
1109
- # Returns +true+ blank lines are skipped by the parser. See CSV::new
1110
- # for details.
1111
- #
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
1112
1921
  def skip_blanks?
1113
1922
  parser.skip_blanks?
1114
1923
  end
1115
1924
 
1116
- # 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
1117
1932
  def force_quotes?
1118
1933
  @writer_options[:force_quotes]
1119
1934
  end
1120
1935
 
1121
- # 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
1122
1942
  def liberal_parsing?
1123
1943
  parser.liberal_parsing?
1124
1944
  end
1125
1945
 
1946
+ # :call-seq:
1947
+ # csv.encoding -> endcoding
1126
1948
  #
1127
- # The Encoding CSV is parsing or writing in. This will be the Encoding you
1128
- # receive parsed data in and/or the Encoding data will be written in.
1129
- #
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>
1130
1952
  attr_reader :encoding
1131
1953
 
1132
- #
1133
- # The line number of the last row read from this file. Fields with nested
1134
- # line-end characters will not affect this count.
1135
- #
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
1136
1983
  def lineno
1137
1984
  if @writer
1138
1985
  @writer.lineno
@@ -1141,9 +1988,22 @@ class CSV
1141
1988
  end
1142
1989
  end
1143
1990
 
1144
- #
1145
- # The last row read from this file.
1146
- #
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"]
1147
2007
  def line
1148
2008
  parser.line
1149
2009
  end
@@ -1219,13 +2079,56 @@ class CSV
1219
2079
 
1220
2080
  ### End Delegation ###
1221
2081
 
1222
- #
1223
- # The primary write method for wrapped Strings and IOs, +row+ (an Array or
1224
- # CSV::Row) is converted to CSV and appended to the data source. When a
1225
- # CSV::Row is passed, only the row's fields() are appended to the output.
1226
- #
1227
- # The data source must be open for writing.
1228
- #
2082
+ # :call-seq:
2083
+ # csv << row -> self
2084
+ #
2085
+ # Appends a row to +self+.
2086
+ #
2087
+ # - Argument +row+ must be an \Array object or a CSV::Row object.
2088
+ # - The output stream must be open for writing.
2089
+ #
2090
+ # ---
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 opened 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
1229
2132
  def <<(row)
1230
2133
  writer << row
1231
2134
  self
@@ -1233,58 +2136,216 @@ class CSV
1233
2136
  alias_method :add_row, :<<
1234
2137
  alias_method :puts, :<<
1235
2138
 
1236
- #
1237
2139
  # :call-seq:
1238
- # convert( name )
1239
- # convert { |field| ... }
1240
- # convert { |field, field_info| ... }
1241
- #
1242
- # You can use this method to install a CSV::Converters built-in, or provide a
1243
- # block that handles a custom conversion.
1244
- #
1245
- # If you provide a block that takes one argument, it will be passed the field
1246
- # and is expected to return the converted value or the field itself. If your
1247
- # block takes two arguments, it will also be passed a CSV::FieldInfo Struct,
1248
- # containing details about the field. Again, the block should return a
1249
- # converted field or the field itself.
1250
- #
2140
+ # convert(converter_name) -> array_of_procs
2141
+ # convert {|field, field_info| ... } -> array_of_procs
2142
+ #
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
+ # ---
2152
+ #
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]
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
1251
2203
  def convert(name = nil, &converter)
1252
2204
  parser_fields_converter.add_converter(name, &converter)
1253
2205
  end
1254
2206
 
1255
- #
1256
2207
  # :call-seq:
1257
- # header_convert( name )
1258
- # header_convert { |field| ... }
1259
- # header_convert { |field, field_info| ... }
1260
- #
1261
- # Identical to CSV#convert(), but for header rows.
1262
- #
1263
- # Note that this method must be called before header rows are read to have any
1264
- # effect.
1265
- #
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.
2214
+ #
2215
+ # - Argument +converter_name+, if given, should be the name
2216
+ # of an existing header converter.
2217
+ #
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
+ # ---
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
1266
2269
  def header_convert(name = nil, &converter)
1267
2270
  header_fields_converter.add_converter(name, &converter)
1268
2271
  end
1269
2272
 
1270
2273
  include Enumerable
1271
2274
 
1272
- #
1273
- # Yields each row of the data source in turn.
1274
- #
1275
- # Support for Enumerable.
1276
- #
1277
- # The data source must be open for reading.
1278
- #
2275
+ # :call-seq:
2276
+ # csv.each -> enumerator
2277
+ # csv.each {|row| ...}
2278
+ #
2279
+ # Calls the block with each successive row.
2280
+ # The data source must be opened for reading.
2281
+ #
2282
+ # Without headers:
2283
+ # string = "foo,0\nbar,1\nbaz,2\n"
2284
+ # csv = CSV.new(string)
2285
+ # csv.each do |row|
2286
+ # p row
2287
+ # end
2288
+ # Output:
2289
+ # ["foo", "0"]
2290
+ # ["bar", "1"]
2291
+ # ["baz", "2"]
2292
+ #
2293
+ # With headers:
2294
+ # string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
2295
+ # csv = CSV.new(string, headers: true)
2296
+ # csv.each do |row|
2297
+ # p row
2298
+ # end
2299
+ # Output:
2300
+ # <CSV::Row "Name":"foo" "Value":"0">
2301
+ # <CSV::Row "Name":"bar" "Value":"1">
2302
+ # <CSV::Row "Name":"baz" "Value":"2">
2303
+ #
2304
+ # ---
2305
+ #
2306
+ # Raises an exception if the source is not opened for reading:
2307
+ # string = "foo,0\nbar,1\nbaz,2\n"
2308
+ # csv = CSV.new(string)
2309
+ # csv.close
2310
+ # # Raises IOError (not opened for reading)
2311
+ # csv.each do |row|
2312
+ # p row
2313
+ # end
1279
2314
  def each(&block)
1280
2315
  parser_enumerator.each(&block)
1281
2316
  end
1282
2317
 
1283
- #
1284
- # Slurps the remaining rows and returns an Array of Arrays.
1285
- #
1286
- # The data source must be open for reading.
1287
- #
2318
+ # :call-seq:
2319
+ # csv.read -> array or csv_table
2320
+ #
2321
+ # Forms the remaining rows from +self+ into:
2322
+ # - A CSV::Table object, if headers are in use.
2323
+ # - An \Array of Arrays, otherwise.
2324
+ #
2325
+ # The data source must be opened for reading.
2326
+ #
2327
+ # Without headers:
2328
+ # string = "foo,0\nbar,1\nbaz,2\n"
2329
+ # path = 't.csv'
2330
+ # File.write(path, string)
2331
+ # csv = CSV.open(path)
2332
+ # csv.read # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
2333
+ #
2334
+ # With headers:
2335
+ # string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
2336
+ # path = 't.csv'
2337
+ # File.write(path, string)
2338
+ # csv = CSV.open(path, headers: true)
2339
+ # csv.read # => #<CSV::Table mode:col_or_row row_count:4>
2340
+ #
2341
+ # ---
2342
+ #
2343
+ # Raises an exception if the source is not opened for reading:
2344
+ # string = "foo,0\nbar,1\nbaz,2\n"
2345
+ # csv = CSV.new(string)
2346
+ # csv.close
2347
+ # # Raises IOError (not opened for reading)
2348
+ # csv.read
1288
2349
  def read
1289
2350
  rows = to_a
1290
2351
  if parser.use_headers?
@@ -1295,18 +2356,69 @@ class CSV
1295
2356
  end
1296
2357
  alias_method :readlines, :read
1297
2358
 
1298
- # Returns +true+ if the next row read will be a header row.
2359
+ # :call-seq:
2360
+ # csv.header_row? -> true or false
2361
+ #
2362
+ # Returns +true+ if the next row to be read is a header row\;
2363
+ # +false+ otherwise.
2364
+ #
2365
+ # Without headers:
2366
+ # string = "foo,0\nbar,1\nbaz,2\n"
2367
+ # csv = CSV.new(string)
2368
+ # csv.header_row? # => false
2369
+ #
2370
+ # With headers:
2371
+ # string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
2372
+ # csv = CSV.new(string, headers: true)
2373
+ # csv.header_row? # => true
2374
+ # csv.shift # => #<CSV::Row "Name":"foo" "Value":"0">
2375
+ # csv.header_row? # => false
2376
+ #
2377
+ # ---
2378
+ #
2379
+ # Raises an exception if the source is not opened for reading:
2380
+ # string = "foo,0\nbar,1\nbaz,2\n"
2381
+ # csv = CSV.new(string)
2382
+ # csv.close
2383
+ # # Raises IOError (not opened for reading)
2384
+ # csv.header_row?
1299
2385
  def header_row?
1300
2386
  parser.header_row?
1301
2387
  end
1302
2388
 
1303
- #
1304
- # The primary read method for wrapped Strings and IOs, a single row is pulled
1305
- # from the data source, parsed and returned as an Array of fields (if header
1306
- # rows are not used) or a CSV::Row (when header rows are used).
1307
- #
1308
- # The data source must be open for reading.
1309
- #
2389
+ # :call-seq:
2390
+ # csv.shift -> array, csv_row, or nil
2391
+ #
2392
+ # Returns the next row of data as:
2393
+ # - An \Array if no headers are used.
2394
+ # - A CSV::Row object if headers are used.
2395
+ #
2396
+ # The data source must be opened for reading.
2397
+ #
2398
+ # Without headers:
2399
+ # string = "foo,0\nbar,1\nbaz,2\n"
2400
+ # csv = CSV.new(string)
2401
+ # csv.shift # => ["foo", "0"]
2402
+ # csv.shift # => ["bar", "1"]
2403
+ # csv.shift # => ["baz", "2"]
2404
+ # csv.shift # => nil
2405
+ #
2406
+ # With headers:
2407
+ # string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
2408
+ # csv = CSV.new(string, headers: true)
2409
+ # csv.shift # => #<CSV::Row "Name":"foo" "Value":"0">
2410
+ # csv.shift # => #<CSV::Row "Name":"bar" "Value":"1">
2411
+ # csv.shift # => #<CSV::Row "Name":"baz" "Value":"2">
2412
+ # csv.shift # => nil
2413
+ #
2414
+ # ---
2415
+ #
2416
+ # Raises an exception if the source is not opened for reading:
2417
+ # string = "foo,0\nbar,1\nbaz,2\n"
2418
+ # csv = CSV.new(string)
2419
+ # csv.close
2420
+ # # Raises IOError (not opened for reading)
2421
+ # csv.shift
1310
2422
  def shift
1311
2423
  if @eof_error
1312
2424
  eof_error, @eof_error = @eof_error, nil
@@ -1321,12 +2433,16 @@ class CSV
1321
2433
  alias_method :gets, :shift
1322
2434
  alias_method :readline, :shift
1323
2435
 
2436
+ # :call-seq:
2437
+ # csv.inspect -> string
1324
2438
  #
1325
- # Returns a simplified description of the key CSV attributes in an
1326
- # ASCII compatible String.
1327
- #
2439
+ # Returns a \String showing certain properties of +self+:
2440
+ # string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
2441
+ # csv = CSV.new(string, headers: true)
2442
+ # s = csv.inspect
2443
+ # s # => "#<CSV io_type:StringIO encoding:UTF-8 lineno:0 col_sep:\",\" row_sep:\"\\n\" quote_char:\"\\\"\" headers:true>"
1328
2444
  def inspect
1329
- str = ["<#", self.class.to_s, " io_type:"]
2445
+ str = ["#<", self.class.to_s, " io_type:"]
1330
2446
  # show type of wrapped IO
1331
2447
  if @io == $stdout then str << "$stdout"
1332
2448
  elsif @io == $stdin then str << "$stdin"