csv 3.0.0 → 3.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
[![Build Status](https://travis-ci.org/ruby/csv.svg?branch=master)](https://travis-ci.org/ruby/csv)
|
4
|
+
[![Test Coverage](https://api.codeclimate.com/v1/badges/321fa39e510a0abd0369/test_coverage)](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
|