csv 3.0.0 → 3.0.1
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/README.md +1 -0
- data/lib/csv.rb +66 -63
- data/lib/csv/row.rb +5 -0
- data/lib/csv/table.rb +26 -7
- data/lib/csv/version.rb +1 -1
- data/news.md +51 -0
- metadata +17 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f6ad673a6db13541d439c4798f677ae19e118fb031411b8434ec4534bafc47a9
|
4
|
+
data.tar.gz: 427070352e63b901d410a70eba6f7073103bc6cbe8e57f7e161e01003ae1598c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3d2c69c8b784d79149dfd5999d2c937e037f83ccc806bd4fe5a674b913518ab4be4a13911e2ec3f5590c45dc6ebdd346eed6f85be253fad6dae40cd9eb0cb704
|
7
|
+
data.tar.gz: 25a0fee13c07fb870831c0b59ea88c9df6844ccf63810925d7ed437000c220b83a212781d5d615529ef487bd3ffdbd90a13b293475e8a4074a2feb249258b156
|
data/README.md
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# CSV
|
2
2
|
|
3
3
|
[](https://travis-ci.org/ruby/csv)
|
4
|
+
[](https://codeclimate.com/github/ruby/csv/test_coverage)
|
4
5
|
|
5
6
|
This library provides a complete interface to CSV files and data. It offers tools to enable you to read and write to and from Strings or IO objects, as needed.
|
6
7
|
|
data/lib/csv.rb
CHANGED
@@ -141,7 +141,7 @@ end
|
|
141
141
|
# There are several specialized class methods for one-statement reading or writing,
|
142
142
|
# described in the Specialized Methods section.
|
143
143
|
#
|
144
|
-
# If a String passed into ::new, it is internally wrapped into a StringIO object.
|
144
|
+
# If a String is passed into ::new, it is internally wrapped into a StringIO object.
|
145
145
|
#
|
146
146
|
# +options+ can be used for specifying the particular CSV flavor (column
|
147
147
|
# separators, row separators, value quoting and so on), and for data conversion,
|
@@ -890,8 +890,12 @@ class CSV
|
|
890
890
|
# attempt to parse input not conformant
|
891
891
|
# with RFC 4180, such as double quotes
|
892
892
|
# in unquoted fields.
|
893
|
-
# <b><tt>:nil_value</tt></b>::
|
894
|
-
#
|
893
|
+
# <b><tt>:nil_value</tt></b>:: When set an object, any values of an
|
894
|
+
# empty field are replaced by the set
|
895
|
+
# object, not nil.
|
896
|
+
# <b><tt>:empty_value</tt></b>:: When set an object, any values of a
|
897
|
+
# blank string field is replaced by
|
898
|
+
# the set object.
|
895
899
|
#
|
896
900
|
# See CSV::DEFAULT_OPTIONS for the default settings.
|
897
901
|
#
|
@@ -908,6 +912,7 @@ class CSV
|
|
908
912
|
|
909
913
|
# create the IO object we will read from
|
910
914
|
@io = data.is_a?(String) ? StringIO.new(data) : data
|
915
|
+
@prefix_io = nil # cache for input data possibly read by init_separators
|
911
916
|
@encoding = determine_encoding(encoding, internal_encoding)
|
912
917
|
#
|
913
918
|
# prepare for building safe regular expressions in the target encoding,
|
@@ -1156,7 +1161,7 @@ class CSV
|
|
1156
1161
|
def read
|
1157
1162
|
rows = to_a
|
1158
1163
|
if @use_headers
|
1159
|
-
Table.new(rows)
|
1164
|
+
Table.new(rows, headers: @headers)
|
1160
1165
|
else
|
1161
1166
|
rows
|
1162
1167
|
end
|
@@ -1200,8 +1205,14 @@ class CSV
|
|
1200
1205
|
|
1201
1206
|
loop do
|
1202
1207
|
# add another read to the line
|
1203
|
-
|
1204
|
-
|
1208
|
+
if @prefix_io
|
1209
|
+
parse = @prefix_io.gets(@row_sep)
|
1210
|
+
if @prefix_io.eof?
|
1211
|
+
parse << (@io.gets(@row_sep) || "") unless parse.end_with?(@row_sep)
|
1212
|
+
@prefix_io = nil # avoid having to test @prefix_io.eof? in main code path
|
1213
|
+
end
|
1214
|
+
else
|
1215
|
+
return nil unless parse = @io.gets(@row_sep)
|
1205
1216
|
end
|
1206
1217
|
|
1207
1218
|
if in_extended_col
|
@@ -1311,7 +1322,7 @@ class CSV
|
|
1311
1322
|
|
1312
1323
|
if in_extended_col
|
1313
1324
|
# if we're at eof?(), a quoted field wasn't closed...
|
1314
|
-
if @io.eof?
|
1325
|
+
if @io.eof? and !@prefix_io
|
1315
1326
|
raise MalformedCSVError.new("Unclosed quoted field",
|
1316
1327
|
lineno + 1)
|
1317
1328
|
elsif @field_size_limit and csv.last.size >= @field_size_limit
|
@@ -1433,68 +1444,62 @@ class CSV
|
|
1433
1444
|
# (not fully encoding safe)
|
1434
1445
|
#
|
1435
1446
|
if @row_sep == :auto
|
1436
|
-
|
1437
|
-
|
1438
|
-
@row_sep
|
1439
|
-
else
|
1440
|
-
begin
|
1447
|
+
saved_prefix = [] # sample chunks to be reprocessed later
|
1448
|
+
begin
|
1449
|
+
while @row_sep == :auto && @io.respond_to?(:gets)
|
1441
1450
|
#
|
1442
|
-
#
|
1443
|
-
#
|
1451
|
+
# if we run out of data, it's probably a single line
|
1452
|
+
# (ensure will set default value)
|
1444
1453
|
#
|
1445
|
-
|
1446
|
-
|
1447
|
-
|
1448
|
-
|
1449
|
-
|
1450
|
-
|
1451
|
-
|
1452
|
-
|
1453
|
-
cr = encode_str("\r")
|
1454
|
-
lf = encode_str("\n")
|
1455
|
-
# extend sample if we're unsure of the line ending
|
1456
|
-
if sample.end_with?(cr)
|
1457
|
-
sample << (@io.gets(nil, 1) || "")
|
1458
|
-
end
|
1454
|
+
break unless sample = @io.gets(nil, 1024)
|
1455
|
+
|
1456
|
+
cr = encode_str("\r")
|
1457
|
+
lf = encode_str("\n")
|
1458
|
+
# extend sample if we're unsure of the line ending
|
1459
|
+
if sample.end_with?(cr)
|
1460
|
+
sample << (@io.gets(nil, 1) || "")
|
1461
|
+
end
|
1459
1462
|
|
1460
|
-
|
1461
|
-
|
1462
|
-
|
1463
|
-
|
1464
|
-
|
1465
|
-
|
1466
|
-
|
1467
|
-
|
1468
|
-
|
1469
|
-
|
1470
|
-
|
1471
|
-
@row_sep =
|
1472
|
-
break
|
1463
|
+
saved_prefix << sample
|
1464
|
+
|
1465
|
+
# try to find a standard separator
|
1466
|
+
last_char = nil
|
1467
|
+
sample.each_char.each_cons(2) do |char, next_char|
|
1468
|
+
last_char = next_char
|
1469
|
+
case char
|
1470
|
+
when cr
|
1471
|
+
if next_char == lf
|
1472
|
+
@row_sep = encode_str("\r\n")
|
1473
|
+
else
|
1474
|
+
@row_sep = cr
|
1473
1475
|
end
|
1476
|
+
break
|
1477
|
+
when lf
|
1478
|
+
@row_sep = lf
|
1479
|
+
break
|
1474
1480
|
end
|
1475
1481
|
end
|
1476
|
-
|
1477
|
-
|
1478
|
-
|
1479
|
-
|
1480
|
-
|
1481
|
-
|
1482
|
-
|
1482
|
+
if @row_sep == :auto
|
1483
|
+
case last_char
|
1484
|
+
when cr
|
1485
|
+
@row_sep = cr
|
1486
|
+
when lf
|
1487
|
+
@row_sep = lf
|
1488
|
+
end
|
1483
1489
|
end
|
1484
|
-
@io.read(saved_pos) if saved_pos.nonzero?
|
1485
|
-
rescue IOError # not opened for reading
|
1486
|
-
# do nothing: ensure will set default
|
1487
|
-
rescue NoMethodError # Zlib::GzipWriter doesn't have some IO methods
|
1488
|
-
# do nothing: ensure will set default
|
1489
|
-
rescue SystemCallError # pipe
|
1490
|
-
# do nothing: ensure will set default
|
1491
|
-
ensure
|
1492
|
-
#
|
1493
|
-
# set default if we failed to detect
|
1494
|
-
# (stream not opened for reading, a pipe, or a single line of data)
|
1495
|
-
#
|
1496
|
-
@row_sep = $INPUT_RECORD_SEPARATOR if @row_sep == :auto
|
1497
1490
|
end
|
1491
|
+
rescue IOError
|
1492
|
+
# do nothing: ensure will set default
|
1493
|
+
ensure
|
1494
|
+
#
|
1495
|
+
# set default if we failed to detect
|
1496
|
+
# (stream not opened for reading or a single line of data)
|
1497
|
+
#
|
1498
|
+
@row_sep = $INPUT_RECORD_SEPARATOR if @row_sep == :auto
|
1499
|
+
|
1500
|
+
# save sampled input for later parsing (but only if there is some!)
|
1501
|
+
saved_prefix = saved_prefix.join('')
|
1502
|
+
@prefix_io = StringIO.new(saved_prefix) unless saved_prefix.empty?
|
1498
1503
|
end
|
1499
1504
|
end
|
1500
1505
|
@row_sep = @row_sep.to_s.encode(@encoding)
|
@@ -1743,8 +1748,6 @@ class CSV
|
|
1743
1748
|
def raw_encoding(default = Encoding::ASCII_8BIT)
|
1744
1749
|
if @io.respond_to? :internal_encoding
|
1745
1750
|
@io.internal_encoding || @io.external_encoding
|
1746
|
-
elsif @io.is_a? StringIO
|
1747
|
-
@io.string.encoding
|
1748
1751
|
elsif @io.respond_to? :encoding
|
1749
1752
|
@io.encoding
|
1750
1753
|
else
|
data/lib/csv/row.rb
CHANGED
data/lib/csv/table.rb
CHANGED
@@ -16,6 +16,11 @@ class CSV
|
|
16
16
|
# Construct a new CSV::Table from +array_of_rows+, which are expected
|
17
17
|
# to be CSV::Row objects. All rows are assumed to have the same headers.
|
18
18
|
#
|
19
|
+
# The optional +headers+ parameter can be set to Array of headers.
|
20
|
+
# If headers aren't set, headers are fetched from CSV::Row objects.
|
21
|
+
# Otherwise, headers() method will return headers being set in
|
22
|
+
# headers arugument.
|
23
|
+
#
|
19
24
|
# A CSV::Table object supports the following Array methods through
|
20
25
|
# delegation:
|
21
26
|
#
|
@@ -23,8 +28,17 @@ class CSV
|
|
23
28
|
# * length()
|
24
29
|
# * size()
|
25
30
|
#
|
26
|
-
def initialize(array_of_rows)
|
31
|
+
def initialize(array_of_rows, headers: nil)
|
27
32
|
@table = array_of_rows
|
33
|
+
@headers = headers
|
34
|
+
unless @headers
|
35
|
+
if @table.empty?
|
36
|
+
@headers = []
|
37
|
+
else
|
38
|
+
@headers = @table.first.headers
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
28
42
|
@mode = :col_or_row
|
29
43
|
end
|
30
44
|
|
@@ -122,11 +136,7 @@ class CSV
|
|
122
136
|
# other rows). An empty Array is returned for empty tables.
|
123
137
|
#
|
124
138
|
def headers
|
125
|
-
|
126
|
-
Array.new
|
127
|
-
else
|
128
|
-
@table.first.headers
|
129
|
-
end
|
139
|
+
@headers.dup
|
130
140
|
end
|
131
141
|
|
132
142
|
#
|
@@ -171,6 +181,10 @@ class CSV
|
|
171
181
|
@table[index_or_header] = value
|
172
182
|
end
|
173
183
|
else # set column
|
184
|
+
unless index_or_header.is_a? Integer
|
185
|
+
index = @headers.index(index_or_header) || @headers.size
|
186
|
+
@headers[index] = index_or_header
|
187
|
+
end
|
174
188
|
if value.is_a? Array # multiple values
|
175
189
|
@table.each_with_index do |row, i|
|
176
190
|
if row.header_row?
|
@@ -258,6 +272,11 @@ class CSV
|
|
258
272
|
(@mode == :col_or_row and index_or_header.is_a? Integer)
|
259
273
|
@table.delete_at(index_or_header)
|
260
274
|
else # by header
|
275
|
+
if index_or_header.is_a? Integer
|
276
|
+
@headers.delete_at(index_or_header)
|
277
|
+
else
|
278
|
+
@headers.delete(index_or_header)
|
279
|
+
end
|
261
280
|
@table.map { |row| row.delete(index_or_header).last }
|
262
281
|
end
|
263
282
|
end
|
@@ -375,4 +394,4 @@ class CSV
|
|
375
394
|
"#<#{self.class} mode:#{@mode} row_count:#{to_a.size}>".encode("US-ASCII")
|
376
395
|
end
|
377
396
|
end
|
378
|
-
end
|
397
|
+
end
|
data/lib/csv/version.rb
CHANGED
data/news.md
CHANGED
@@ -1,5 +1,56 @@
|
|
1
1
|
# News
|
2
2
|
|
3
|
+
## 3.0.1 - 2018-12-07
|
4
|
+
|
5
|
+
### Improvements
|
6
|
+
|
7
|
+
* Added a test.
|
8
|
+
[GitHub#38][Patch by 284km]
|
9
|
+
|
10
|
+
* `CSV::Row#dup`: Changed to duplicate internal data.
|
11
|
+
[GitHub#39][Reported by André Guimarães Sakata]
|
12
|
+
|
13
|
+
* Documented `:nil_value` and `:empty_value` options.
|
14
|
+
[GitHub#41][Patch by OwlWorks]
|
15
|
+
|
16
|
+
* Added support for separator detection for non-seekable inputs.
|
17
|
+
[GitHub#45][Patch by Ilmari Karonen]
|
18
|
+
|
19
|
+
* Removed needless code.
|
20
|
+
[GitHub#48][Patch by Espartaco Palma]
|
21
|
+
|
22
|
+
* Added support for parsing header only CSV with `headers: true`.
|
23
|
+
[GitHub#47][Patch by Kazuma Shibasaka]
|
24
|
+
|
25
|
+
* Added support for coverage report in CI.
|
26
|
+
[GitHub#48][Patch by Espartaco Palma]
|
27
|
+
|
28
|
+
* Improved auto CR row separator detection.
|
29
|
+
[GitHub#51][Reported by Yuki Kurihara]
|
30
|
+
|
31
|
+
### Fixes
|
32
|
+
|
33
|
+
* Fixed a typo in document.
|
34
|
+
[GitHub#40][Patch by Marcus Stollsteimer]
|
35
|
+
|
36
|
+
### Thanks
|
37
|
+
|
38
|
+
* 284km
|
39
|
+
|
40
|
+
* André Guimarães Sakata
|
41
|
+
|
42
|
+
* Marcus Stollsteimer
|
43
|
+
|
44
|
+
* OwlWorks
|
45
|
+
|
46
|
+
* Ilmari Karonen
|
47
|
+
|
48
|
+
* Espartaco Palma
|
49
|
+
|
50
|
+
* Kazuma Shibasaka
|
51
|
+
|
52
|
+
* Yuki Kurihara
|
53
|
+
|
3
54
|
## 3.0.0 - 2018-06-06
|
4
55
|
|
5
56
|
### Fixes
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: csv
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.0.
|
4
|
+
version: 3.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- James Edward Gray II
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2018-
|
12
|
+
date: 2018-12-07 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|
@@ -53,6 +53,20 @@ dependencies:
|
|
53
53
|
- - ">="
|
54
54
|
- !ruby/object:Gem::Version
|
55
55
|
version: '0'
|
56
|
+
- !ruby/object:Gem::Dependency
|
57
|
+
name: simplecov
|
58
|
+
requirement: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '0'
|
63
|
+
type: :development
|
64
|
+
prerelease: false
|
65
|
+
version_requirements: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - ">="
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
56
70
|
description: The CSV library provides a complete interface to CSV files and data.
|
57
71
|
It offers tools to enable you to read and write to and from Strings or IO objects,
|
58
72
|
as needed.
|
@@ -92,7 +106,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
92
106
|
version: '0'
|
93
107
|
requirements: []
|
94
108
|
rubyforge_project:
|
95
|
-
rubygems_version: 3.0.0.
|
109
|
+
rubygems_version: 3.0.0.beta3
|
96
110
|
signing_key:
|
97
111
|
specification_version: 4
|
98
112
|
summary: CSV Reading and Writing
|