csv 3.3.5 → 3.3.6
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 +39 -1
- data/README.md +1 -1
- data/lib/csv/parser.rb +7 -2
- data/lib/csv/row.rb +26 -2
- data/lib/csv/version.rb +1 -1
- data/lib/csv.rb +30 -58
- metadata +3 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d2a1d74b0246a143f03c2e786ea5484cb3e5aebe370453141a9d69539eae900b
|
|
4
|
+
data.tar.gz: d8bb00a2e6842e28ca6b443e416f8f03186b098dcc81fde6ba5429eed138a755
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3d26ab99eb2708d787022832ca171def6ef4647183667be03831d9a91c5320545146adac9e5471e92637e6e905c27c06499739fc5e510541c026c15388b9e316
|
|
7
|
+
data.tar.gz: f8e7b076653e2e3f04503db617e94f14c66064aa1a8ff790a342c018eb6c598eb84127b0818e0ed8f2688ec6404b163c80e6c58cbf7d3c9411583ad8cd2cd0bd
|
data/NEWS.md
CHANGED
|
@@ -1,5 +1,43 @@
|
|
|
1
1
|
# News
|
|
2
2
|
|
|
3
|
+
## 3.3.6 - 2026-07-27
|
|
4
|
+
|
|
5
|
+
### Improvements
|
|
6
|
+
|
|
7
|
+
* `CSV::Row#to_h`: Added support for block.
|
|
8
|
+
* GH-356
|
|
9
|
+
* Patch by Vlad
|
|
10
|
+
|
|
11
|
+
* Ensured using `path_or_io` for parameter name that accepts path or
|
|
12
|
+
IO.
|
|
13
|
+
* GH-358
|
|
14
|
+
* Patch by Yuto Urushima
|
|
15
|
+
|
|
16
|
+
* Changed to not using enumerator in `CSV`.
|
|
17
|
+
* GH-361
|
|
18
|
+
* GH-363
|
|
19
|
+
* Reported by Cas Donoghue
|
|
20
|
+
|
|
21
|
+
### Fixes
|
|
22
|
+
|
|
23
|
+
* Fixed a bug that `\r` in unquoted fields are rejected when row
|
|
24
|
+
separator doesn't contain `\r`
|
|
25
|
+
* GH-60
|
|
26
|
+
* GH-346
|
|
27
|
+
* Patch by Jas
|
|
28
|
+
|
|
29
|
+
* Fixed a typo in documentation.
|
|
30
|
+
* GH-350
|
|
31
|
+
* Patch by tmr111116
|
|
32
|
+
|
|
33
|
+
### Thanks
|
|
34
|
+
|
|
35
|
+
* Jas
|
|
36
|
+
* tmr111116
|
|
37
|
+
* Vlad
|
|
38
|
+
* Yuto Urushima
|
|
39
|
+
* Cas Donoghue
|
|
40
|
+
|
|
3
41
|
## 3.3.5 - 2025-06-01
|
|
4
42
|
|
|
5
43
|
### Improvements
|
|
@@ -10,7 +48,7 @@
|
|
|
10
48
|
|
|
11
49
|
### Thanks
|
|
12
50
|
|
|
13
|
-
*
|
|
51
|
+
* Petrik de Heus
|
|
14
52
|
|
|
15
53
|
## 3.3.4 - 2025-04-13
|
|
16
54
|
|
data/README.md
CHANGED
|
@@ -52,4 +52,4 @@ Please do not submit issues and PRs that aim to introduce RuboCop in this reposi
|
|
|
52
52
|
|
|
53
53
|
The gem is available as open source under the terms of the [2-Clause BSD License](https://opensource.org/licenses/BSD-2-Clause).
|
|
54
54
|
|
|
55
|
-
See LICENSE.txt for details.
|
|
55
|
+
See [LICENSE.txt](LICENSE.txt) for details.
|
data/lib/csv/parser.rb
CHANGED
|
@@ -181,7 +181,7 @@ class CSV
|
|
|
181
181
|
end
|
|
182
182
|
|
|
183
183
|
def eos?
|
|
184
|
-
@scanner.eos?
|
|
184
|
+
@last_scanner and @scanner.eos?
|
|
185
185
|
end
|
|
186
186
|
|
|
187
187
|
def keep_start
|
|
@@ -444,6 +444,11 @@ class CSV
|
|
|
444
444
|
end
|
|
445
445
|
end
|
|
446
446
|
|
|
447
|
+
def eof?
|
|
448
|
+
return false if @scanner.nil?
|
|
449
|
+
@scanner.eos?
|
|
450
|
+
end
|
|
451
|
+
|
|
447
452
|
def use_headers?
|
|
448
453
|
@use_headers
|
|
449
454
|
end
|
|
@@ -675,7 +680,7 @@ class CSV
|
|
|
675
680
|
def prepare_unquoted
|
|
676
681
|
return if @quote_character.nil?
|
|
677
682
|
|
|
678
|
-
no_unquoted_values =
|
|
683
|
+
no_unquoted_values = Regexp.escape(@row_separator).encode(@encoding)
|
|
679
684
|
no_unquoted_values << @escaped_first_column_separator
|
|
680
685
|
unless @liberal_parsing
|
|
681
686
|
no_unquoted_values << @escaped_quote_character
|
data/lib/csv/row.rb
CHANGED
|
@@ -637,6 +637,7 @@ class CSV
|
|
|
637
637
|
|
|
638
638
|
# :call-seq:
|
|
639
639
|
# row.to_h -> hash
|
|
640
|
+
# row.to_h {|key, value| ... } -> hash
|
|
640
641
|
#
|
|
641
642
|
# Returns the new \Hash formed by adding each header-value pair in +self+
|
|
642
643
|
# as a key-value pair in the \Hash.
|
|
@@ -650,11 +651,34 @@ class CSV
|
|
|
650
651
|
# table = CSV.parse(source, headers: true)
|
|
651
652
|
# row = table[0]
|
|
652
653
|
# row.to_h # => {"Name"=>"Foo"}
|
|
654
|
+
#
|
|
655
|
+
# If a block is given, will call it with (key, value) arguments and use result as a hash entry:
|
|
656
|
+
# source = "Name,Value\nfoo,1\nbar,2\nbaz,3\n"
|
|
657
|
+
# table = CSV.parse(source, headers: true)
|
|
658
|
+
# row = table[0]
|
|
659
|
+
# row.to_h { |key, value| [key, "#{key}-#{value}"] } # => {"Name"=>"Name-foo", "Value"=>"Value-1"}
|
|
653
660
|
def to_h
|
|
654
661
|
hash = {}
|
|
655
|
-
|
|
656
|
-
|
|
662
|
+
|
|
663
|
+
if block_given?
|
|
664
|
+
each do |key, _value|
|
|
665
|
+
result = yield(key, self[key])
|
|
666
|
+
result_array = Array.try_convert(result)
|
|
667
|
+
raise TypeError, "wrong element type #{result.class} (expected array)" if result_array.nil?
|
|
668
|
+
raise ArgumentError, "wrong array length (expected 2, was #{result_array.size})" unless result_array.size == 2
|
|
669
|
+
|
|
670
|
+
key, value = result_array
|
|
671
|
+
next if hash.key?(key)
|
|
672
|
+
|
|
673
|
+
key.freeze if key.is_a?(String) && !key.frozen?
|
|
674
|
+
hash[key] = value
|
|
675
|
+
end
|
|
676
|
+
else
|
|
677
|
+
each do |key, _value|
|
|
678
|
+
hash[key] = self[key] unless hash.key?(key)
|
|
679
|
+
end
|
|
657
680
|
end
|
|
681
|
+
|
|
658
682
|
hash
|
|
659
683
|
end
|
|
660
684
|
alias_method :to_hash, :to_h
|
data/lib/csv/version.rb
CHANGED
data/lib/csv.rb
CHANGED
|
@@ -1377,7 +1377,7 @@ class CSV
|
|
|
1377
1377
|
# * Arguments <tt>**options</tt> must be keyword options.
|
|
1378
1378
|
# See {Options for Parsing}[#class-CSV-label-Options+for+Parsing].
|
|
1379
1379
|
# * This method optionally accepts an additional <tt>:encoding</tt> option
|
|
1380
|
-
# that you can use to specify the Encoding of the data read from +
|
|
1380
|
+
# that you can use to specify the Encoding of the data read from +path_or_io+.
|
|
1381
1381
|
# You must provide this unless your data is in the encoding
|
|
1382
1382
|
# given by <tt>Encoding::default_external</tt>.
|
|
1383
1383
|
# Parsing will use this to determine how to parse the data.
|
|
@@ -1386,9 +1386,9 @@ class CSV
|
|
|
1386
1386
|
# encoding: 'UTF-32BE:UTF-8'
|
|
1387
1387
|
# would read +UTF-32BE+ data from the file
|
|
1388
1388
|
# but transcode it to +UTF-8+ before parsing.
|
|
1389
|
-
def foreach(
|
|
1390
|
-
return to_enum(__method__,
|
|
1391
|
-
open(
|
|
1389
|
+
def foreach(path_or_io, mode="r", **options, &block)
|
|
1390
|
+
return to_enum(__method__, path_or_io, mode, **options) unless block_given?
|
|
1391
|
+
open(path_or_io, mode, **options) do |csv|
|
|
1392
1392
|
csv.each(&block)
|
|
1393
1393
|
end
|
|
1394
1394
|
end
|
|
@@ -1582,7 +1582,7 @@ class CSV
|
|
|
1582
1582
|
# * Arguments <tt>**options</tt> must be keyword options.
|
|
1583
1583
|
# See {Options for Generating}[#class-CSV-label-Options+for+Generating].
|
|
1584
1584
|
# * This method optionally accepts an additional <tt>:encoding</tt> option
|
|
1585
|
-
# that you can use to specify the Encoding of the data read from +
|
|
1585
|
+
# that you can use to specify the Encoding of the data read from +path_or_io+.
|
|
1586
1586
|
# You must provide this unless your data is in the encoding
|
|
1587
1587
|
# given by <tt>Encoding::default_external</tt>.
|
|
1588
1588
|
# Parsing will use this to determine how to parse the data.
|
|
@@ -1644,11 +1644,11 @@ class CSV
|
|
|
1644
1644
|
# Raises an exception if the argument is not a \String object or \IO object:
|
|
1645
1645
|
# # Raises TypeError (no implicit conversion of Symbol into String)
|
|
1646
1646
|
# CSV.open(:foo)
|
|
1647
|
-
def open(
|
|
1647
|
+
def open(path_or_io, mode="r", **options)
|
|
1648
1648
|
# wrap a File opened with the remaining +args+ with no newline
|
|
1649
1649
|
# decorator
|
|
1650
1650
|
file_opts = {}
|
|
1651
|
-
may_enable_bom_detection_automatically(
|
|
1651
|
+
may_enable_bom_detection_automatically(path_or_io,
|
|
1652
1652
|
mode,
|
|
1653
1653
|
options,
|
|
1654
1654
|
file_opts)
|
|
@@ -1661,11 +1661,11 @@ class CSV
|
|
|
1661
1661
|
options.delete(:replace)
|
|
1662
1662
|
options.delete_if {|k, _| /newline\z/.match?(k)}
|
|
1663
1663
|
|
|
1664
|
-
if
|
|
1665
|
-
f = create_stringio(
|
|
1664
|
+
if path_or_io.is_a?(StringIO)
|
|
1665
|
+
f = create_stringio(path_or_io.string, mode, **file_opts)
|
|
1666
1666
|
else
|
|
1667
1667
|
begin
|
|
1668
|
-
f = File.open(
|
|
1668
|
+
f = File.open(path_or_io, mode, **file_opts)
|
|
1669
1669
|
rescue ArgumentError => e
|
|
1670
1670
|
raise unless /needs binmode/.match?(e.message) and mode == "r"
|
|
1671
1671
|
mode = "rb"
|
|
@@ -1901,10 +1901,10 @@ class CSV
|
|
|
1901
1901
|
|
|
1902
1902
|
#
|
|
1903
1903
|
# :call-seq:
|
|
1904
|
-
# read(
|
|
1905
|
-
# read(
|
|
1904
|
+
# read(path_or_io, **options) -> array_of_arrays
|
|
1905
|
+
# read(path_or_io, headers: true, **options) -> csv_table
|
|
1906
1906
|
#
|
|
1907
|
-
# Opens the given +
|
|
1907
|
+
# Opens the given +path_or_io+ with the given +options+ (see CSV.open),
|
|
1908
1908
|
# reads the source (see CSV#read), and returns the result,
|
|
1909
1909
|
# which will be either an \Array of Arrays or a CSV::Table.
|
|
1910
1910
|
#
|
|
@@ -1919,22 +1919,22 @@ class CSV
|
|
|
1919
1919
|
# path = 't.csv'
|
|
1920
1920
|
# File.write(path, string)
|
|
1921
1921
|
# CSV.read(path, headers: true) # => #<CSV::Table mode:col_or_row row_count:4>
|
|
1922
|
-
def read(
|
|
1923
|
-
open(
|
|
1922
|
+
def read(path_or_io, **options)
|
|
1923
|
+
open(path_or_io, **options) { |csv| csv.read }
|
|
1924
1924
|
end
|
|
1925
1925
|
|
|
1926
1926
|
# :call-seq:
|
|
1927
|
-
# CSV.readlines(
|
|
1927
|
+
# CSV.readlines(path_or_io, **options)
|
|
1928
1928
|
#
|
|
1929
1929
|
# Alias for CSV.read.
|
|
1930
|
-
def readlines(
|
|
1931
|
-
read(
|
|
1930
|
+
def readlines(path_or_io, **options)
|
|
1931
|
+
read(path_or_io, **options)
|
|
1932
1932
|
end
|
|
1933
1933
|
|
|
1934
1934
|
# :call-seq:
|
|
1935
|
-
# CSV.table(
|
|
1935
|
+
# CSV.table(path_or_io, **options)
|
|
1936
1936
|
#
|
|
1937
|
-
# Calls CSV.read with +
|
|
1937
|
+
# Calls CSV.read with +path_or_io+, +options+, and certain default options:
|
|
1938
1938
|
# - +headers+: +true+
|
|
1939
1939
|
# - +converters+: +:numeric+
|
|
1940
1940
|
# - +header_converters+: +:symbol+
|
|
@@ -1946,25 +1946,25 @@ class CSV
|
|
|
1946
1946
|
# path = 't.csv'
|
|
1947
1947
|
# File.write(path, string)
|
|
1948
1948
|
# CSV.table(path) # => #<CSV::Table mode:col_or_row row_count:4>
|
|
1949
|
-
def table(
|
|
1949
|
+
def table(path_or_io, **options)
|
|
1950
1950
|
default_options = {
|
|
1951
1951
|
headers: true,
|
|
1952
1952
|
converters: :numeric,
|
|
1953
1953
|
header_converters: :symbol,
|
|
1954
1954
|
}
|
|
1955
1955
|
options = default_options.merge(options)
|
|
1956
|
-
read(
|
|
1956
|
+
read(path_or_io, **options)
|
|
1957
1957
|
end
|
|
1958
1958
|
|
|
1959
1959
|
ON_WINDOWS = /mingw|mswin/.match?(RUBY_PLATFORM)
|
|
1960
1960
|
private_constant :ON_WINDOWS
|
|
1961
1961
|
|
|
1962
1962
|
private
|
|
1963
|
-
def may_enable_bom_detection_automatically(
|
|
1963
|
+
def may_enable_bom_detection_automatically(path_or_io,
|
|
1964
1964
|
mode,
|
|
1965
1965
|
options,
|
|
1966
1966
|
file_opts)
|
|
1967
|
-
if
|
|
1967
|
+
if path_or_io.is_a?(StringIO)
|
|
1968
1968
|
# Support to StringIO was dropped for Ruby 2.6 and earlier without BOM support:
|
|
1969
1969
|
# https://github.com/ruby/stringio/pull/47
|
|
1970
1970
|
return if RUBY_VERSION < "2.7"
|
|
@@ -2110,8 +2110,6 @@ class CSV
|
|
|
2110
2110
|
strip: strip,
|
|
2111
2111
|
}
|
|
2112
2112
|
@parser = nil
|
|
2113
|
-
@parser_enumerator = nil
|
|
2114
|
-
@eof_error = nil
|
|
2115
2113
|
|
|
2116
2114
|
@writer_options = {
|
|
2117
2115
|
encoding: @encoding,
|
|
@@ -2327,7 +2325,7 @@ class CSV
|
|
|
2327
2325
|
attr_reader :encoding
|
|
2328
2326
|
|
|
2329
2327
|
# :call-seq:
|
|
2330
|
-
# csv.
|
|
2328
|
+
# csv.lineno -> integer
|
|
2331
2329
|
#
|
|
2332
2330
|
# Returns the count of the rows parsed or generated.
|
|
2333
2331
|
#
|
|
@@ -2430,24 +2428,13 @@ class CSV
|
|
|
2430
2428
|
end
|
|
2431
2429
|
|
|
2432
2430
|
def eof?
|
|
2433
|
-
|
|
2434
|
-
begin
|
|
2435
|
-
parser_enumerator.peek
|
|
2436
|
-
false
|
|
2437
|
-
rescue MalformedCSVError => error
|
|
2438
|
-
@eof_error = error
|
|
2439
|
-
false
|
|
2440
|
-
rescue StopIteration
|
|
2441
|
-
true
|
|
2442
|
-
end
|
|
2431
|
+
parser.eof?
|
|
2443
2432
|
end
|
|
2444
2433
|
alias_method :eof, :eof?
|
|
2445
2434
|
|
|
2446
2435
|
# Rewinds the underlying IO object and resets CSV's lineno() counter.
|
|
2447
2436
|
def rewind
|
|
2448
2437
|
@parser = nil
|
|
2449
|
-
@parser_enumerator = nil
|
|
2450
|
-
@eof_error = nil
|
|
2451
2438
|
@writer.rewind if @writer
|
|
2452
2439
|
@io.rewind
|
|
2453
2440
|
end
|
|
@@ -2687,13 +2674,7 @@ class CSV
|
|
|
2687
2674
|
# p row
|
|
2688
2675
|
# end
|
|
2689
2676
|
def each(&block)
|
|
2690
|
-
|
|
2691
|
-
begin
|
|
2692
|
-
while true
|
|
2693
|
-
yield(parser_enumerator.next)
|
|
2694
|
-
end
|
|
2695
|
-
rescue StopIteration
|
|
2696
|
-
end
|
|
2677
|
+
parser.parse(&block)
|
|
2697
2678
|
end
|
|
2698
2679
|
|
|
2699
2680
|
# :call-seq:
|
|
@@ -2801,15 +2782,10 @@ class CSV
|
|
|
2801
2782
|
# # Raises IOError (not opened for reading)
|
|
2802
2783
|
# csv.shift
|
|
2803
2784
|
def shift
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
raise eof_error
|
|
2807
|
-
end
|
|
2808
|
-
begin
|
|
2809
|
-
parser_enumerator.next
|
|
2810
|
-
rescue StopIteration
|
|
2811
|
-
nil
|
|
2785
|
+
parser.parse do |row|
|
|
2786
|
+
return row
|
|
2812
2787
|
end
|
|
2788
|
+
nil
|
|
2813
2789
|
end
|
|
2814
2790
|
alias_method :gets, :shift
|
|
2815
2791
|
alias_method :readline, :shift
|
|
@@ -2971,10 +2947,6 @@ class CSV
|
|
|
2971
2947
|
fields_converter: parser_fields_converter)
|
|
2972
2948
|
end
|
|
2973
2949
|
|
|
2974
|
-
def parser_enumerator
|
|
2975
|
-
@parser_enumerator ||= parser.parse
|
|
2976
|
-
end
|
|
2977
|
-
|
|
2978
2950
|
def writer
|
|
2979
2951
|
@writer ||= Writer.new(@io, writer_options)
|
|
2980
2952
|
end
|
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.3.
|
|
4
|
+
version: 3.3.6
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- James Edward Gray II
|
|
@@ -71,7 +71,7 @@ licenses:
|
|
|
71
71
|
- Ruby
|
|
72
72
|
- BSD-2-Clause
|
|
73
73
|
metadata:
|
|
74
|
-
changelog_uri: https://github.com/ruby/csv/releases/tag/v3.3.
|
|
74
|
+
changelog_uri: https://github.com/ruby/csv/releases/tag/v3.3.6
|
|
75
75
|
rdoc_options:
|
|
76
76
|
- "--main"
|
|
77
77
|
- README.md
|
|
@@ -88,7 +88,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
88
88
|
- !ruby/object:Gem::Version
|
|
89
89
|
version: '0'
|
|
90
90
|
requirements: []
|
|
91
|
-
rubygems_version:
|
|
91
|
+
rubygems_version: 4.0.16
|
|
92
92
|
specification_version: 4
|
|
93
93
|
summary: CSV Reading and Writing
|
|
94
94
|
test_files: []
|