csv 3.2.2 → 3.3.5

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8682072d16c079d3d25b3f22ca9f06cae36210998194ae3f3de627c74c062453
4
- data.tar.gz: 755bddbed0b08dd681939a76c5f6a80f2c536a0e72edcf6e8c770be860e5fcae
3
+ metadata.gz: f77fe04292e17f436f9c5838bb3cbd6aa4297b807478c127321323fc4ad27c28
4
+ data.tar.gz: 63ecf6ce80dcfa3b7eb24d0f3947455eb223d1c44a32b58b4d084b29efad8961
5
5
  SHA512:
6
- metadata.gz: 28e191df9cb41c6ca04a9969eace28deac9217de9f2677b7edec8803531c28b4c47e4866d00fd6edbc5ea0b21f10a4f59b376473475a8c96317949b84b53f49a
7
- data.tar.gz: 4c747ddbdb78e4e6e8dc725199b2f35aea7949b7eb5b49929c2e818d15cbebfaa07825f57a5ee092a5da7f5c75fc2ea3c035ff204f1a95a12283cea85720e31c
6
+ metadata.gz: f9ffbf24700b4ab0eb35a2cb8086e82e36825558c14b646ae00374cb3e80f7195ebb3c9ac08d11b011ffa0cc10ae607a79e24d68b793b54c50d2dd1e8bd5ec16
7
+ data.tar.gz: 628a0b0c0963d69686845172d84fbbdf1cebb9fc6839e052054f9e7c112bbcb96743a63e8cf5d1a6df8a9299f03ab3b8d81a9b814fb6d0f222e444b9f0282a5d
data/NEWS.md CHANGED
@@ -1,5 +1,329 @@
1
1
  # News
2
2
 
3
+ ## 3.3.5 - 2025-06-01
4
+
5
+ ### Improvements
6
+
7
+ * docs: Fixed `StringScanner` document URL.
8
+ * GH-343
9
+ * Patch by Petrik de Heus
10
+
11
+ ### Thanks
12
+
13
+ * Petrik de Heus
14
+
15
+ ## 3.3.4 - 2025-04-13
16
+
17
+ ### Improvements
18
+
19
+ * `csv-filter`: Removed an experimental command line tool.
20
+ * GH-341
21
+
22
+ ## 3.3.3 - 2025-03-20
23
+
24
+ ### Improvements
25
+
26
+ * `csv-filter`: Added an experimental command line tool to filter a CSV.
27
+ * Patch by Burdette Lamar
28
+
29
+ ### Fixes
30
+
31
+ * Fixed wrong EOF detection for `ARGF`
32
+ * GH-328
33
+ * Reported by Takeshi Nishimatsu
34
+
35
+ * Fixed a regression bug that `CSV.open` rejects integer mode.
36
+ * GH-336
37
+ * Reported by Dave Burgess
38
+
39
+ ### Thanks
40
+
41
+ * Takeshi Nishimatsu
42
+
43
+ * Burdette Lamar
44
+
45
+ * Dave Burgess
46
+
47
+ ## 3.3.2 - 2024-12-21
48
+
49
+ ### Fixes
50
+
51
+ * Fixed a parse bug with a quoted line with `col_sep` and an empty
52
+ line. This was introduced in 3.3.1.
53
+ * GH-324
54
+ * Reported by stoodfarback
55
+
56
+ ### Thanks
57
+
58
+ * stoodfarback
59
+
60
+ ## 3.3.1 - 2024-12-15
61
+
62
+ ### Improvements
63
+
64
+ * `CSV.open`: Changed to detect BOM by default. Note that this isn't
65
+ enabled on Windows because Ruby may have a bug. See also:
66
+ https://bugs.ruby-lang.org/issues/20526
67
+ * GH-301
68
+ * Reported by Junichi Ito
69
+
70
+ * Improved performance.
71
+ * GH-311
72
+ * GH-312
73
+ * Patch by Vladimir Kochnev
74
+
75
+ * `CSV.open`: Added support for `StringIO` as an input.
76
+ * GH-300
77
+ * GH-302
78
+ * Patch by Marcelo
79
+
80
+ * Added a built-in time converter. You can use it by `converters:
81
+ :time`.
82
+ * GH-313
83
+ * Patch by Bart de Water
84
+
85
+ * Added `CSV::TSV` for tab-separated values.
86
+ * GH-272
87
+ * GH-319
88
+ * Reported by kojix2
89
+ * Patch by Jas
90
+
91
+ ### Thanks
92
+
93
+ * Junichi Ito
94
+
95
+ * Vladimir Kochnev
96
+
97
+ * Marcelo
98
+
99
+ * Bart de Water
100
+
101
+ * kojix2
102
+
103
+ * Jas
104
+
105
+ ## 3.3.0 - 2024-03-22
106
+
107
+ ### Fixes
108
+
109
+ * Fixed a regression parse bug in 3.2.9 that parsing with
110
+ `:skip_lines` may cause wrong result.
111
+
112
+ ## 3.2.9 - 2024-03-22
113
+
114
+ ### Fixes
115
+
116
+ * Fixed a parse bug that wrong result may be happen when:
117
+
118
+ * `:skip_lines` is used
119
+ * `:row_separator` is `"\r\n"`
120
+ * There is a line that includes `\n` as a column value
121
+
122
+ Reported by Ryo Tsukamoto.
123
+
124
+ GH-296
125
+
126
+ ### Thanks
127
+
128
+ * Ryo Tsukamoto
129
+
130
+ ## 3.2.8 - 2023-11-08
131
+
132
+ ### Improvements
133
+
134
+ * Added `CSV::InvalidEncodingError`.
135
+
136
+ Patch by Kosuke Shibata.
137
+
138
+ GH-287
139
+
140
+ ### Thanks
141
+
142
+ * Kosuke Shibata
143
+
144
+ ## 3.2.7 - 2023-06-26
145
+
146
+ ### Improvements
147
+
148
+ * Removed an unused internal variable.
149
+ [GH-273](https://github.com/ruby/csv/issues/273)
150
+ [Patch by Mau Magnaguagno]
151
+
152
+ * Changed to use `https://` instead of `http://` in documents.
153
+ [GH-274](https://github.com/ruby/csv/issues/274)
154
+ [Patch by Vivek Bharath Akupatni]
155
+
156
+ * Added prefix to a helper module in test.
157
+ [GH-278](https://github.com/ruby/csv/issues/278)
158
+ [Patch by Luke Gruber]
159
+
160
+ * Added a documentation for `liberal_parsing: {backslash_quotes: true}`.
161
+ [GH-280](https://github.com/ruby/csv/issues/280)
162
+ [Patch by Mark Schneider]
163
+
164
+ ### Fixes
165
+
166
+ * Fixed a wrong execution result in documents.
167
+ [GH-276](https://github.com/ruby/csv/issues/276)
168
+ [Patch by Yuki Tsujimoto]
169
+
170
+ * Fixed a bug that the same line is used multiple times.
171
+ [GH-279](https://github.com/ruby/csv/issues/279)
172
+ [Reported by Gabriel Nagy]
173
+
174
+ ### Thanks
175
+
176
+ * Mau Magnaguagno
177
+
178
+ * Vivek Bharath Akupatni
179
+
180
+ * Yuki Tsujimoto
181
+
182
+ * Luke Gruber
183
+
184
+ * Mark Schneider
185
+
186
+ * Gabriel Nagy
187
+
188
+ ## 3.2.6 - 2022-12-08
189
+
190
+ ### Improvements
191
+
192
+ * `CSV#read` consumes the same lines with other methods like
193
+ `CSV#shift`.
194
+ [[GitHub#258](https://github.com/ruby/csv/issues/258)]
195
+ [Reported by Lhoussaine Ghallou]
196
+
197
+ * All `Enumerable` based methods consume the same lines with other
198
+ methods. This may have a performance penalty.
199
+ [[GitHub#260](https://github.com/ruby/csv/issues/260)]
200
+ [Reported by Lhoussaine Ghallou]
201
+
202
+ * Simplify some implementations.
203
+ [[GitHub#262](https://github.com/ruby/csv/pull/262)]
204
+ [[GitHub#263](https://github.com/ruby/csv/pull/263)]
205
+ [Patch by Mau Magnaguagno]
206
+
207
+ ### Fixes
208
+
209
+ * Fixed `CSV.generate_lines` document.
210
+ [[GitHub#257](https://github.com/ruby/csv/pull/257)]
211
+ [Patch by Sampat Badhe]
212
+
213
+ ### Thanks
214
+
215
+ * Sampat Badhe
216
+
217
+ * Lhoussaine Ghallou
218
+
219
+ * Mau Magnaguagno
220
+
221
+ ## 3.2.5 - 2022-08-26
222
+
223
+ ### Improvements
224
+
225
+ * Added `CSV.generate_lines`.
226
+ [[GitHub#255](https://github.com/ruby/csv/issues/255)]
227
+ [Reported by OKURA Masafumi]
228
+ [[GitHub#256](https://github.com/ruby/csv/pull/256)]
229
+ [Patch by Eriko Sugiyama]
230
+
231
+ ### Thanks
232
+
233
+ * OKURA Masafumi
234
+
235
+ * Eriko Sugiyama
236
+
237
+ ## 3.2.4 - 2022-08-22
238
+
239
+ ### Improvements
240
+
241
+ * Cleaned up internal implementations.
242
+ [[GitHub#249](https://github.com/ruby/csv/pull/249)]
243
+ [[GitHub#250](https://github.com/ruby/csv/pull/250)]
244
+ [[GitHub#251](https://github.com/ruby/csv/pull/251)]
245
+ [Patch by Mau Magnaguagno]
246
+
247
+ * Added support for RFC 3339 style time.
248
+ [[GitHub#248](https://github.com/ruby/csv/pull/248)]
249
+ [Patch by Thierry Lambert]
250
+
251
+ * Added support for transcoding String CSV. Syntax is
252
+ `from-encoding:to-encoding`.
253
+ [[GitHub#254](https://github.com/ruby/csv/issues/254)]
254
+ [Reported by Richard Stueven]
255
+
256
+ * Added quoted information to `CSV::FieldInfo`.
257
+ [[GitHub#254](https://github.com/ruby/csv/pull/253)]
258
+ [Reported by Hirokazu SUZUKI]
259
+
260
+ ### Fixes
261
+
262
+ * Fixed a link in documents.
263
+ [[GitHub#244](https://github.com/ruby/csv/pull/244)]
264
+ [Patch by Peter Zhu]
265
+
266
+ ### Thanks
267
+
268
+ * Peter Zhu
269
+
270
+ * Mau Magnaguagno
271
+
272
+ * Thierry Lambert
273
+
274
+ * Richard Stueven
275
+
276
+ * Hirokazu SUZUKI
277
+
278
+ ## 3.2.3 - 2022-04-09
279
+
280
+ ### Improvements
281
+
282
+ * Added contents summary to `CSV::Table#inspect`.
283
+ [GitHub#229][Patch by Eriko Sugiyama]
284
+ [GitHub#235][Patch by Sampat Badhe]
285
+
286
+ * Suppressed `$INPUT_RECORD_SEPARATOR` deprecation warning by
287
+ `Warning.warn`.
288
+ [GitHub#233][Reported by Jean byroot Boussier]
289
+
290
+ * Improved error message for liberal parsing with quoted values.
291
+ [GitHub#231][Patch by Nikolay Rys]
292
+
293
+ * Fixed typos in documentation.
294
+ [GitHub#236][Patch by Sampat Badhe]
295
+
296
+ * Added `:max_field_size` option and deprecated `:field_size_limit` option.
297
+ [GitHub#238][Reported by Dan Buettner]
298
+
299
+ * Added `:symbol_raw` to built-in header converters.
300
+ [GitHub#237][Reported by taki]
301
+ [GitHub#239][Patch by Eriko Sugiyama]
302
+
303
+ ### Fixes
304
+
305
+ * Fixed a bug that some texts may be dropped unexpectedly.
306
+ [Bug #18245][ruby-core:105587][Reported by Hassan Abdul Rehman]
307
+
308
+ * Fixed a bug that `:field_size_limit` doesn't work with not complex row.
309
+ [GitHub#238][Reported by Dan Buettner]
310
+
311
+ ### Thanks
312
+
313
+ * Hassan Abdul Rehman
314
+
315
+ * Eriko Sugiyama
316
+
317
+ * Jean byroot Boussier
318
+
319
+ * Nikolay Rys
320
+
321
+ * Sampat Badhe
322
+
323
+ * Dan Buettner
324
+
325
+ * taki
326
+
3
327
  ## 3.2.2 - 2021-12-24
4
328
 
5
329
  ### Improvements
@@ -15,9 +339,6 @@
15
339
  * Fixed a bug that all of `ARGF` contents may not be consumed.
16
340
  [GitHub#228][Reported by Rafael Navaza]
17
341
 
18
- * Fixed a bug that some texts may be dropped unexpectedly.
19
- [Bug #18245][ruby-core:105587][Reported by Hassan Abdul Rehman]
20
-
21
342
  ### Thanks
22
343
 
23
344
  * adamroyjones
@@ -26,8 +347,6 @@
26
347
 
27
348
  * Rafael Navaza
28
349
 
29
- * Hassan Abdul Rehman
30
-
31
350
  ## 3.2.1 - 2021-10-23
32
351
 
33
352
  ### Improvements
data/README.md CHANGED
@@ -30,8 +30,8 @@ end
30
30
 
31
31
  ## Documentation
32
32
 
33
- - [API](https://ruby-doc.org/stdlib/libdoc/csv/rdoc/CSV.html): all classes, methods, and constants.
34
- - [Recipes](https://ruby-doc.org/core/doc/csv/recipes/recipes_rdoc.html): specific code for specific tasks.
33
+ - [API](https://ruby.github.io/csv/): all classes, methods, and constants.
34
+ - [Recipes](https://ruby.github.io/csv/doc/csv/recipes/recipes_rdoc.html): specific code for specific tasks.
35
35
 
36
36
  ## Development
37
37
 
@@ -19,7 +19,7 @@ Without +write_headers+:
19
19
 
20
20
  With +write_headers+":
21
21
  CSV.open(file_path,'w',
22
- :write_headers=> true,
22
+ :write_headers => true,
23
23
  :headers => ['Name','Value']
24
24
  ) do |csv|
25
25
  csv << ['foo', '0']
@@ -1,13 +1,13 @@
1
1
  ====== Option +liberal_parsing+
2
2
 
3
- Specifies the boolean value that determines whether
3
+ Specifies the boolean or hash value that determines whether
4
4
  CSV will attempt to parse input not conformant with RFC 4180,
5
5
  such as double quotes in unquoted fields.
6
6
 
7
7
  Default value:
8
8
  CSV::DEFAULT_OPTIONS.fetch(:liberal_parsing) # => false
9
9
 
10
- For examples in this section:
10
+ For the next two examples:
11
11
  str = 'is,this "three, or four",fields'
12
12
 
13
13
  Without +liberal_parsing+:
@@ -17,3 +17,22 @@ Without +liberal_parsing+:
17
17
  With +liberal_parsing+:
18
18
  ary = CSV.parse_line(str, liberal_parsing: true)
19
19
  ary # => ["is", "this \"three", " or four\"", "fields"]
20
+
21
+ Use the +backslash_quote+ sub-option to parse values that use
22
+ a backslash to escape a double-quote character. This
23
+ causes the parser to treat <code>\"</code> as if it were
24
+ <code>""</code>.
25
+
26
+ For the next two examples:
27
+ str = 'Show,"Harry \"Handcuff\" Houdini, the one and only","Tampa Theater"'
28
+
29
+ With +liberal_parsing+, but without the +backslash_quote+ sub-option:
30
+ # Incorrect interpretation of backslash; incorrectly interprets the quoted comma as a field separator.
31
+ ary = CSV.parse_line(str, liberal_parsing: true)
32
+ ary # => ["Show", "\"Harry \\\"Handcuff\\\" Houdini", " the one and only\"", "Tampa Theater"]
33
+ puts ary[1] # => "Harry \"Handcuff\" Houdini
34
+
35
+ With +liberal_parsing+ and its +backslash_quote+ sub-option:
36
+ ary = CSV.parse_line(str, liberal_parsing: { backslash_quote: true })
37
+ ary # => ["Show", "Harry \"Handcuff\" Houdini, the one and only", "Tampa Theater"]
38
+ puts ary[1] # => Harry "Handcuff" Houdini, the one and only
@@ -11,16 +11,20 @@ All code snippets on this page assume that the following has been executed:
11
11
 
12
12
  - {Source and Output Formats}[#label-Source+and+Output+Formats]
13
13
  - {Filtering String to String}[#label-Filtering+String+to+String]
14
- - {Recipe: Filter String to String with Headers}[#label-Recipe-3A+Filter+String+to+String+with+Headers]
14
+ - {Recipe: Filter String to String parsing Headers}[#label-Recipe-3A+Filter+String+to+String+parsing+Headers]
15
+ - {Recipe: Filter String to String parsing and writing Headers}[#label-Recipe-3A+Filter+String+to+String+parsing+and+writing+Headers]
15
16
  - {Recipe: Filter String to String Without Headers}[#label-Recipe-3A+Filter+String+to+String+Without+Headers]
16
17
  - {Filtering String to IO Stream}[#label-Filtering+String+to+IO+Stream]
17
- - {Recipe: Filter String to IO Stream with Headers}[#label-Recipe-3A+Filter+String+to+IO+Stream+with+Headers]
18
+ - {Recipe: Filter String to IO Stream parsing Headers}[#label-Recipe-3A+Filter+String+to+IO+Stream+parsing+Headers]
19
+ - {Recipe: Filter String to IO Stream parsing and writing Headers}[#label-Recipe-3A+Filter+String+to+IO+Stream+parsing+and+writing+Headers]
18
20
  - {Recipe: Filter String to IO Stream Without Headers}[#label-Recipe-3A+Filter+String+to+IO+Stream+Without+Headers]
19
21
  - {Filtering IO Stream to String}[#label-Filtering+IO+Stream+to+String]
20
- - {Recipe: Filter IO Stream to String with Headers}[#label-Recipe-3A+Filter+IO+Stream+to+String+with+Headers]
22
+ - {Recipe: Filter IO Stream to String parsing Headers}[#label-Recipe-3A+Filter+IO+Stream+to+String+parsing+Headers]
23
+ - {Recipe: Filter IO Stream to String parsing and writing Headers}[#label-Recipe-3A+Filter+IO+Stream+to+String+parsing+and+writing+Headers]
21
24
  - {Recipe: Filter IO Stream to String Without Headers}[#label-Recipe-3A+Filter+IO+Stream+to+String+Without+Headers]
22
25
  - {Filtering IO Stream to IO Stream}[#label-Filtering+IO+Stream+to+IO+Stream]
23
- - {Recipe: Filter IO Stream to IO Stream with Headers}[#label-Recipe-3A+Filter+IO+Stream+to+IO+Stream+with+Headers]
26
+ - {Recipe: Filter IO Stream to IO Stream parsing Headers}[#label-Recipe-3A+Filter+IO+Stream+to+IO+Stream+parsing+Headers]
27
+ - {Recipe: Filter IO Stream to IO Stream parsing and writing Headers}[#label-Recipe-3A+Filter+IO+Stream+to+IO+Stream+parsing+and+writing+Headers]
24
28
  - {Recipe: Filter IO Stream to IO Stream Without Headers}[#label-Recipe-3A+Filter+IO+Stream+to+IO+Stream+Without+Headers]
25
29
 
26
30
  === Source and Output Formats
@@ -33,14 +37,27 @@ The input and output \CSV data may be any mixture of \Strings and \IO streams.
33
37
 
34
38
  You can filter one \String to another, with or without headers.
35
39
 
36
- ===== Recipe: Filter \String to \String with Headers
40
+ ===== Recipe: Filter \String to \String parsing Headers
37
41
 
38
42
  Use class method CSV.filter with option +headers+ to filter a \String to another \String:
39
43
  in_string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
40
44
  out_string = ''
41
45
  CSV.filter(in_string, out_string, headers: true) do |row|
42
- row[0] = row[0].upcase
43
- row[1] *= 4
46
+ row['Name'] = row['Name'].upcase
47
+ row['Value'] *= 4
48
+ end
49
+ out_string # => "FOO,0000\nBAR,1111\nBAZ,2222\n"
50
+
51
+ ===== Recipe: Filter \String to \String parsing and writing Headers
52
+
53
+ Use class method CSV.filter with option +headers+ and +out_write_headers+ to filter a \String to another \String including header row:
54
+ in_string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
55
+ out_string = ''
56
+ CSV.filter(in_string, out_string, headers: true, out_write_headers: true) do |row|
57
+ unless row.is_a?(Array)
58
+ row['Name'] = row['Name'].upcase
59
+ row['Value'] *= 4
60
+ end
44
61
  end
45
62
  out_string # => "Name,Value\nFOO,0000\nBAR,1111\nBAZ,2222\n"
46
63
 
@@ -59,15 +76,30 @@ Use class method CSV.filter without option +headers+ to filter a \String to anot
59
76
 
60
77
  You can filter a \String to an \IO stream, with or without headers.
61
78
 
62
- ===== Recipe: Filter \String to \IO Stream with Headers
79
+ ===== Recipe: Filter \String to \IO Stream parsing Headers
63
80
 
64
81
  Use class method CSV.filter with option +headers+ to filter a \String to an \IO stream:
65
82
  in_string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
66
83
  path = 't.csv'
67
84
  File.open(path, 'w') do |out_io|
68
85
  CSV.filter(in_string, out_io, headers: true) do |row|
69
- row[0] = row[0].upcase
70
- row[1] *= 4
86
+ row['Name'] = row['Name'].upcase
87
+ row['Value'] *= 4
88
+ end
89
+ end
90
+ p File.read(path) # => "FOO,0000\nBAR,1111\nBAZ,2222\n"
91
+
92
+ ===== Recipe: Filter \String to \IO Stream parsing and writing Headers
93
+
94
+ Use class method CSV.filter with option +headers+ and +out_write_headers+ to filter a \String to an \IO stream including header row:
95
+ in_string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
96
+ path = 't.csv'
97
+ File.open(path, 'w') do |out_io|
98
+ CSV.filter(in_string, out_io, headers: true, out_write_headers: true ) do |row|
99
+ unless row.is_a?(Array)
100
+ row['Name'] = row['Name'].upcase
101
+ row['Value'] *= 4
102
+ end
71
103
  end
72
104
  end
73
105
  p File.read(path) # => "Name,Value\nFOO,0000\nBAR,1111\nBAZ,2222\n"
@@ -89,17 +121,34 @@ Use class method CSV.filter without option +headers+ to filter a \String to an \
89
121
 
90
122
  You can filter an \IO stream to a \String, with or without headers.
91
123
 
92
- ===== Recipe: Filter \IO Stream to \String with Headers
124
+ ===== Recipe: Filter \IO Stream to \String parsing Headers
93
125
 
94
126
  Use class method CSV.filter with option +headers+ to filter an \IO stream to a \String:
95
127
  in_string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
96
128
  path = 't.csv'
97
129
  File.write(path, in_string)
98
130
  out_string = ''
99
- File.open(path, headers: true) do |in_io|
131
+ File.open(path) do |in_io|
100
132
  CSV.filter(in_io, out_string, headers: true) do |row|
101
- row[0] = row[0].upcase
102
- row[1] *= 4
133
+ row['Name'] = row['Name'].upcase
134
+ row['Value'] *= 4
135
+ end
136
+ end
137
+ out_string # => "FOO,0000\nBAR,1111\nBAZ,2222\n"
138
+
139
+ ===== Recipe: Filter \IO Stream to \String parsing and writing Headers
140
+
141
+ Use class method CSV.filter with option +headers+ and +out_write_headers+ to filter an \IO stream to a \String including header row:
142
+ in_string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
143
+ path = 't.csv'
144
+ File.write(path, in_string)
145
+ out_string = ''
146
+ File.open(path) do |in_io|
147
+ CSV.filter(in_io, out_string, headers: true, out_write_headers: true) do |row|
148
+ unless row.is_a?(Array)
149
+ row['Name'] = row['Name'].upcase
150
+ row['Value'] *= 4
151
+ end
103
152
  end
104
153
  end
105
154
  out_string # => "Name,Value\nFOO,0000\nBAR,1111\nBAZ,2222\n"
@@ -123,7 +172,7 @@ Use class method CSV.filter without option +headers+ to filter an \IO stream to
123
172
 
124
173
  You can filter an \IO stream to another \IO stream, with or without headers.
125
174
 
126
- ===== Recipe: Filter \IO Stream to \IO Stream with Headers
175
+ ===== Recipe: Filter \IO Stream to \IO Stream parsing Headers
127
176
 
128
177
  Use class method CSV.filter with option +headers+ to filter an \IO stream to another \IO stream:
129
178
  in_path = 't.csv'
@@ -133,8 +182,27 @@ Use class method CSV.filter with option +headers+ to filter an \IO stream to ano
133
182
  File.open(in_path) do |in_io|
134
183
  File.open(out_path, 'w') do |out_io|
135
184
  CSV.filter(in_io, out_io, headers: true) do |row|
136
- row[0] = row[0].upcase
137
- row[1] *= 4
185
+ row['Name'] = row['Name'].upcase
186
+ row['Value'] *= 4
187
+ end
188
+ end
189
+ end
190
+ p File.read(out_path) # => "FOO,0000\nBAR,1111\nBAZ,2222\n"
191
+
192
+ ===== Recipe: Filter \IO Stream to \IO Stream parsing and writing Headers
193
+
194
+ Use class method CSV.filter with option +headers+ and +out_write_headers+ to filter an \IO stream to another \IO stream including header row:
195
+ in_path = 't.csv'
196
+ in_string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
197
+ File.write(in_path, in_string)
198
+ out_path = 'u.csv'
199
+ File.open(in_path) do |in_io|
200
+ File.open(out_path, 'w') do |out_io|
201
+ CSV.filter(in_io, out_io, headers: true, out_write_headers: true) do |row|
202
+ unless row.is_a?(Array)
203
+ row['Name'] = row['Name'].upcase
204
+ row['Value'] *= 4
205
+ end
138
206
  end
139
207
  end
140
208
  end
@@ -148,7 +148,7 @@ This example defines and uses a custom write converter to strip whitespace from
148
148
 
149
149
  ==== Recipe: Specify Multiple Write Converters
150
150
 
151
- Use option <tt>:write_converters</tt> and multiple custom coverters
151
+ Use option <tt>:write_converters</tt> and multiple custom converters
152
152
  to convert field values when generating \CSV.
153
153
 
154
154
  This example defines and uses two custom write converters to strip and upcase generated fields:
@@ -165,7 +165,7 @@ This example defines and uses two custom write converters to strip and upcase ge
165
165
  === RFC 4180 Compliance
166
166
 
167
167
  By default, \CSV generates data that is compliant with
168
- {RFC 4180}[https://tools.ietf.org/html/rfc4180]
168
+ {RFC 4180}[https://www.rfc-editor.org/rfc/rfc4180]
169
169
  with respect to:
170
170
  - Column separator.
171
171
  - Quote character.
@@ -45,6 +45,7 @@ All code snippets on this page assume that the following has been executed:
45
45
  - {Recipe: Convert Fields to Numerics}[#label-Recipe-3A+Convert+Fields+to+Numerics]
46
46
  - {Recipe: Convert Fields to Dates}[#label-Recipe-3A+Convert+Fields+to+Dates]
47
47
  - {Recipe: Convert Fields to DateTimes}[#label-Recipe-3A+Convert+Fields+to+DateTimes]
48
+ - {Recipe: Convert Fields to Times}[#label-Recipe-3A+Convert+Fields+to+Times]
48
49
  - {Recipe: Convert Assorted Fields to Objects}[#label-Recipe-3A+Convert+Assorted+Fields+to+Objects]
49
50
  - {Recipe: Convert Fields to Other Objects}[#label-Recipe-3A+Convert+Fields+to+Other+Objects]
50
51
  - {Recipe: Filter Field Strings}[#label-Recipe-3A+Filter+Field+Strings]
@@ -83,7 +84,7 @@ Use instance method CSV#each with option +headers+ to read a source \String one
83
84
  CSV.new(string, headers: true).each do |row|
84
85
  p row
85
86
  end
86
- Ouput:
87
+ Output:
87
88
  #<CSV::Row "Name":"foo" "Value":"0">
88
89
  #<CSV::Row "Name":"bar" "Value":"1">
89
90
  #<CSV::Row "Name":"baz" "Value":"2">
@@ -110,7 +111,7 @@ You can parse \CSV data from a \File, with or without headers.
110
111
 
111
112
  ===== Recipe: Parse from \File with Headers
112
113
 
113
- Use instance method CSV#read with option +headers+ to read a file all at once:
114
+ Use class method CSV.read with option +headers+ to read a file all at once:
114
115
  string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
115
116
  path = 't.csv'
116
117
  File.write(path, string)
@@ -191,7 +192,7 @@ Output:
191
192
  === RFC 4180 Compliance
192
193
 
193
194
  By default, \CSV parses data that is compliant with
194
- {RFC 4180}[https://tools.ietf.org/html/rfc4180]
195
+ {RFC 4180}[https://www.rfc-editor.org/rfc/rfc4180]
195
196
  with respect to:
196
197
  - Row separator.
197
198
  - Column separator.
@@ -339,6 +340,7 @@ There are built-in field converters for converting to objects of certain classes
339
340
  - \Integer
340
341
  - \Date
341
342
  - \DateTime
343
+ - \Time
342
344
 
343
345
  Other built-in field converters include:
344
346
  - +:numeric+: converts to \Integer and \Float.
@@ -381,6 +383,13 @@ Convert fields to \DateTime objects using built-in converter +:date_time+:
381
383
  parsed = CSV.parse(source, headers: true, converters: :date_time)
382
384
  parsed.map {|row| row['DateTime'].class} # => [DateTime, DateTime, DateTime]
383
385
 
386
+ ===== Recipe: Convert Fields to Times
387
+
388
+ Convert fields to \Time objects using built-in converter +:time+:
389
+ source = "Name,Time\nfoo,2001-02-03\nbar,2001-02-04\nbaz,2020-05-07T14:59:00-05:00\n"
390
+ parsed = CSV.parse(source, headers: true, converters: :time)
391
+ parsed.map {|row| row['Time'].class} # => [Time, Time, Time]
392
+
384
393
  ===== Recipe: Convert Assorted Fields to Objects
385
394
 
386
395
  Convert assorted fields to objects using built-in converter +:all+:
@@ -520,7 +529,7 @@ Apply multiple header converters by defining and registering a custom header con
520
529
  To capture unconverted field values, use option +:unconverted_fields+:
521
530
  source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
522
531
  parsed = CSV.parse(source, converters: :integer, unconverted_fields: true)
523
- parsed # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
532
+ parsed # => [["Name", "Value"], ["foo", 0], ["bar", 1], ["baz", 2]]
524
533
  parsed.each {|row| p row.unconverted_fields }
525
534
  Output:
526
535
  ["Name", "Value"]
@@ -542,4 +551,4 @@ Output:
542
551
  #<struct CSV::FieldInfo index=0, line=2, header=nil>
543
552
  #<struct CSV::FieldInfo index=1, line=2, header=nil>
544
553
  #<struct CSV::FieldInfo index=0, line=3, header=nil>
545
- #<struct CSV::FieldInfo index=1, line=3, header=nil>
554
+ #<struct CSV::FieldInfo index=1, line=3, header=nil>
@@ -1,4 +1,4 @@
1
- class Array # :nodoc:
1
+ class Array
2
2
  # Equivalent to CSV::generate_line(self, options)
3
3
  #
4
4
  # ["CSV", "data"].to_csv
@@ -1,4 +1,4 @@
1
- class String # :nodoc:
1
+ class String
2
2
  # Equivalent to CSV::parse_line(self, options)
3
3
  #
4
4
  # "CSV,data".parse_csv