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 +4 -4
- data/NEWS.md +324 -5
- data/README.md +2 -2
- data/doc/csv/options/generating/write_headers.rdoc +1 -1
- data/doc/csv/options/parsing/liberal_parsing.rdoc +21 -2
- data/doc/csv/recipes/filtering.rdoc +85 -17
- data/doc/csv/recipes/generating.rdoc +2 -2
- data/doc/csv/recipes/parsing.rdoc +14 -5
- data/lib/csv/core_ext/array.rb +1 -1
- data/lib/csv/core_ext/string.rb +1 -1
- data/lib/csv/fields_converter.rb +10 -2
- data/lib/csv/input_record_separator.rb +1 -14
- data/lib/csv/parser.rb +238 -108
- data/lib/csv/row.rb +1 -1
- data/lib/csv/table.rb +15 -6
- data/lib/csv/version.rb +1 -1
- data/lib/csv/writer.rb +4 -5
- data/lib/csv.rb +256 -44
- metadata +7 -67
- data/lib/csv/delete_suffix.rb +0 -18
- data/lib/csv/match_p.rb +0 -20
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f77fe04292e17f436f9c5838bb3cbd6aa4297b807478c127321323fc4ad27c28
|
|
4
|
+
data.tar.gz: 63ecf6ce80dcfa3b7eb24d0f3947455eb223d1c44a32b58b4d084b29efad8961
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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
|
|
34
|
-
- [Recipes](https://ruby
|
|
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
|
|
|
@@ -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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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[
|
|
43
|
-
row[
|
|
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
|
|
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[
|
|
70
|
-
row[
|
|
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
|
|
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
|
|
131
|
+
File.open(path) do |in_io|
|
|
100
132
|
CSV.filter(in_io, out_string, headers: true) do |row|
|
|
101
|
-
row[
|
|
102
|
-
row[
|
|
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
|
|
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[
|
|
137
|
-
row[
|
|
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
|
|
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://
|
|
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
|
-
|
|
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
|
|
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://
|
|
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 # => [["
|
|
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>
|
data/lib/csv/core_ext/array.rb
CHANGED
data/lib/csv/core_ext/string.rb
CHANGED