csv 3.2.0 → 3.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/NEWS.md +27 -0
- data/lib/csv/fields_converter.rb +6 -2
- data/lib/csv/input_record_separator.rb +31 -0
- data/lib/csv/parser.rb +12 -10
- data/lib/csv/version.rb +1 -1
- data/lib/csv/writer.rb +2 -1
- data/lib/csv.rb +29 -8
- metadata +5 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6aee33c500a979f9f1a9afdbc394545932700ca3442c1b4326b417e59b654ef4
|
4
|
+
data.tar.gz: 6622e0c4f190f10aa6d3a49b023a6c24540b1133da4d0ef91c07016ba224073f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7ba35310fd8dc9ffd4075ca31d786b7458fefefaee4c5a00fc326063fb13d020d1959d9970dcf17c222dd5d2422e3d20b9ddcd503caf5a4aad04e0b93159ff60
|
7
|
+
data.tar.gz: 9d1971baae109ad7396124cfa6bda15bc6db635ff09c6166a750dc22633b552679e5d589b15a57724f7b4aef3ae33c2ccd2fcfcfb1084e71df7f3734347e9926
|
data/NEWS.md
CHANGED
@@ -1,5 +1,32 @@
|
|
1
1
|
# News
|
2
2
|
|
3
|
+
## 3.2.1 - 2021-10-23
|
4
|
+
|
5
|
+
### Improvements
|
6
|
+
|
7
|
+
* doc: Fixed wrong class name.
|
8
|
+
[GitHub#217][Patch by Vince]
|
9
|
+
|
10
|
+
* Changed to always use `"\n"` for the default row separator on Ruby
|
11
|
+
3.0 or later because `$INPUT_RECORD_SEPARATOR` was deprecated
|
12
|
+
since Ruby 3.0.
|
13
|
+
|
14
|
+
* Added support for Ractor.
|
15
|
+
[GitHub#218][Patch by rm155]
|
16
|
+
|
17
|
+
* Users who want to use the built-in converters in non-main
|
18
|
+
Ractors need to call `Ractor.make_shareable(CSV::Converters)`
|
19
|
+
and/or `Ractor.make_shareable(CSV::HeaderConverters)` before
|
20
|
+
creating non-main Ractors.
|
21
|
+
|
22
|
+
### Thanks
|
23
|
+
|
24
|
+
* Vince
|
25
|
+
|
26
|
+
* Joakim Antman
|
27
|
+
|
28
|
+
* rm155
|
29
|
+
|
3
30
|
## 3.2.0 - 2021-06-06
|
4
31
|
|
5
32
|
### Improvements
|
data/lib/csv/fields_converter.rb
CHANGED
@@ -16,7 +16,7 @@ class CSV
|
|
16
16
|
@empty_value = options[:empty_value]
|
17
17
|
@empty_value_is_empty_string = (@empty_value == "")
|
18
18
|
@accept_nil = options[:accept_nil]
|
19
|
-
@
|
19
|
+
@builtin_converters_name = options[:builtin_converters_name]
|
20
20
|
@need_static_convert = need_static_convert?
|
21
21
|
end
|
22
22
|
|
@@ -24,7 +24,7 @@ class CSV
|
|
24
24
|
if name.nil? # custom converter
|
25
25
|
@converters << converter
|
26
26
|
else # named converter
|
27
|
-
combo =
|
27
|
+
combo = builtin_converters[name]
|
28
28
|
case combo
|
29
29
|
when Array # combo converter
|
30
30
|
combo.each do |sub_name|
|
@@ -80,5 +80,9 @@ class CSV
|
|
80
80
|
@need_static_convert or
|
81
81
|
(not @converters.empty?)
|
82
82
|
end
|
83
|
+
|
84
|
+
def builtin_converters
|
85
|
+
@builtin_converters ||= ::CSV.const_get(@builtin_converters_name)
|
86
|
+
end
|
83
87
|
end
|
84
88
|
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require "English"
|
2
|
+
require "stringio"
|
3
|
+
|
4
|
+
class CSV
|
5
|
+
module InputRecordSeparator
|
6
|
+
class << self
|
7
|
+
is_input_record_separator_deprecated = false
|
8
|
+
verbose, $VERBOSE = $VERBOSE, true
|
9
|
+
stderr, $stderr = $stderr, StringIO.new
|
10
|
+
input_record_separator = $INPUT_RECORD_SEPARATOR
|
11
|
+
begin
|
12
|
+
$INPUT_RECORD_SEPARATOR = "\r\n"
|
13
|
+
is_input_record_separator_deprecated = (not $stderr.string.empty?)
|
14
|
+
ensure
|
15
|
+
$INPUT_RECORD_SEPARATOR = input_record_separator
|
16
|
+
$stderr = stderr
|
17
|
+
$VERBOSE = verbose
|
18
|
+
end
|
19
|
+
|
20
|
+
if is_input_record_separator_deprecated
|
21
|
+
def value
|
22
|
+
"\n"
|
23
|
+
end
|
24
|
+
else
|
25
|
+
def value
|
26
|
+
$INPUT_RECORD_SEPARATOR
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/lib/csv/parser.rb
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
require "strscan"
|
4
4
|
|
5
5
|
require_relative "delete_suffix"
|
6
|
+
require_relative "input_record_separator"
|
6
7
|
require_relative "match_p"
|
7
8
|
require_relative "row"
|
8
9
|
require_relative "table"
|
@@ -479,9 +480,9 @@ class CSV
|
|
479
480
|
begin
|
480
481
|
StringScanner.new("x").scan("x")
|
481
482
|
rescue TypeError
|
482
|
-
|
483
|
+
STRING_SCANNER_SCAN_ACCEPT_STRING = false
|
483
484
|
else
|
484
|
-
|
485
|
+
STRING_SCANNER_SCAN_ACCEPT_STRING = true
|
485
486
|
end
|
486
487
|
|
487
488
|
def prepare_separators
|
@@ -505,7 +506,7 @@ class CSV
|
|
505
506
|
@first_column_separators = Regexp.new(@escaped_first_column_separator +
|
506
507
|
"+".encode(@encoding))
|
507
508
|
else
|
508
|
-
if
|
509
|
+
if STRING_SCANNER_SCAN_ACCEPT_STRING
|
509
510
|
@column_end = @column_separator
|
510
511
|
else
|
511
512
|
@column_end = Regexp.new(@escaped_column_separator)
|
@@ -526,7 +527,7 @@ class CSV
|
|
526
527
|
|
527
528
|
@cr = "\r".encode(@encoding)
|
528
529
|
@lf = "\n".encode(@encoding)
|
529
|
-
@
|
530
|
+
@line_end = Regexp.new("\r\n|\n|\r".encode(@encoding))
|
530
531
|
@not_line_end = Regexp.new("[^\r\n]+".encode(@encoding))
|
531
532
|
end
|
532
533
|
|
@@ -605,7 +606,7 @@ class CSV
|
|
605
606
|
# do nothing: ensure will set default
|
606
607
|
end
|
607
608
|
end
|
608
|
-
separator =
|
609
|
+
separator = InputRecordSeparator.value if separator == :auto
|
609
610
|
end
|
610
611
|
separator.to_s.encode(@encoding)
|
611
612
|
end
|
@@ -724,6 +725,8 @@ class CSV
|
|
724
725
|
end
|
725
726
|
end
|
726
727
|
|
728
|
+
SCANNER_TEST_CHUNK_SIZE =
|
729
|
+
Integer((ENV["CSV_PARSER_SCANNER_TEST_CHUNK_SIZE"] || "1"), 10)
|
727
730
|
def build_scanner
|
728
731
|
inputs = @samples.collect do |sample|
|
729
732
|
UnoptimizedStringIO.new(sample)
|
@@ -733,10 +736,9 @@ class CSV
|
|
733
736
|
else
|
734
737
|
inputs << @input
|
735
738
|
end
|
736
|
-
chunk_size = ENV["CSV_PARSER_SCANNER_TEST_CHUNK_SIZE"] || "1"
|
737
739
|
InputsScanner.new(inputs,
|
738
740
|
@encoding,
|
739
|
-
chunk_size:
|
741
|
+
chunk_size: SCANNER_TEST_CHUNK_SIZE)
|
740
742
|
end
|
741
743
|
else
|
742
744
|
def build_scanner
|
@@ -914,7 +916,7 @@ class CSV
|
|
914
916
|
message = "Any value after quoted field isn't allowed"
|
915
917
|
raise MalformedCSVError.new(message, @lineno)
|
916
918
|
elsif @unquoted_column_value and
|
917
|
-
(new_line = @scanner.scan(@
|
919
|
+
(new_line = @scanner.scan(@line_end))
|
918
920
|
ignore_broken_line
|
919
921
|
message = "Unquoted fields do not allow new line " +
|
920
922
|
"<#{new_line.inspect}>"
|
@@ -923,7 +925,7 @@ class CSV
|
|
923
925
|
ignore_broken_line
|
924
926
|
message = "Illegal quoting"
|
925
927
|
raise MalformedCSVError.new(message, @lineno)
|
926
|
-
elsif (new_line = @scanner.scan(@
|
928
|
+
elsif (new_line = @scanner.scan(@line_end))
|
927
929
|
ignore_broken_line
|
928
930
|
message = "New line must be <#{@row_separator.inspect}> " +
|
929
931
|
"not <#{new_line.inspect}>"
|
@@ -1089,7 +1091,7 @@ class CSV
|
|
1089
1091
|
|
1090
1092
|
def ignore_broken_line
|
1091
1093
|
@scanner.scan_all(@not_line_end)
|
1092
|
-
@scanner.scan_all(@
|
1094
|
+
@scanner.scan_all(@line_end)
|
1093
1095
|
@lineno += 1
|
1094
1096
|
end
|
1095
1097
|
|
data/lib/csv/version.rb
CHANGED
data/lib/csv/writer.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative "input_record_separator"
|
3
4
|
require_relative "match_p"
|
4
5
|
require_relative "row"
|
5
6
|
|
@@ -133,7 +134,7 @@ class CSV
|
|
133
134
|
@column_separator = @options[:column_separator].to_s.encode(@encoding)
|
134
135
|
row_separator = @options[:row_separator]
|
135
136
|
if row_separator == :auto
|
136
|
-
@row_separator =
|
137
|
+
@row_separator = InputRecordSeparator.value.encode(@encoding)
|
137
138
|
else
|
138
139
|
@row_separator = row_separator.to_s.encode(@encoding)
|
139
140
|
end
|
data/lib/csv.rb
CHANGED
@@ -90,11 +90,11 @@
|
|
90
90
|
# with any questions.
|
91
91
|
|
92
92
|
require "forwardable"
|
93
|
-
require "English"
|
94
93
|
require "date"
|
95
94
|
require "stringio"
|
96
95
|
|
97
96
|
require_relative "csv/fields_converter"
|
97
|
+
require_relative "csv/input_record_separator"
|
98
98
|
require_relative "csv/match_p"
|
99
99
|
require_relative "csv/parser"
|
100
100
|
require_relative "csv/row"
|
@@ -513,7 +513,7 @@ using CSV::MatchP if CSV.const_defined?(:MatchP)
|
|
513
513
|
# [" 1 ", #<struct CSV::FieldInfo index=1, line=2, header=nil>]
|
514
514
|
# [" baz ", #<struct CSV::FieldInfo index=0, line=3, header=nil>]
|
515
515
|
# [" 2 ", #<struct CSV::FieldInfo index=1, line=3, header=nil>]
|
516
|
-
# Each CSV::
|
516
|
+
# Each CSV::FieldInfo object shows:
|
517
517
|
# - The 0-based field index.
|
518
518
|
# - The 1-based line index.
|
519
519
|
# - The field header, if any.
|
@@ -547,6 +547,14 @@ using CSV::MatchP if CSV.const_defined?(:MatchP)
|
|
547
547
|
#
|
548
548
|
# There is no such storage structure for write headers.
|
549
549
|
#
|
550
|
+
# In order for the parsing methods to access stored converters in non-main-Ractors, the
|
551
|
+
# storage structure must be made shareable first.
|
552
|
+
# Therefore, <tt>Ractor.make_shareable(CSV::Converters)</tt> and
|
553
|
+
# <tt>Ractor.make_shareable(CSV::HeaderConverters)</tt> must be called before the creation
|
554
|
+
# of Ractors that use the converters stored in these structures. (Since making the storage
|
555
|
+
# structures shareable involves freezing them, any custom converters that are to be used
|
556
|
+
# must be added first.)
|
557
|
+
#
|
550
558
|
# ===== Converter Lists
|
551
559
|
#
|
552
560
|
# A _converter_ _list_ is an \Array that may include any assortment of:
|
@@ -919,6 +927,7 @@ class CSV
|
|
919
927
|
gsub(/\s+/, "_").to_sym
|
920
928
|
}
|
921
929
|
}
|
930
|
+
|
922
931
|
# Default values for method options.
|
923
932
|
DEFAULT_OPTIONS = {
|
924
933
|
# For both parsing and generating.
|
@@ -957,6 +966,8 @@ class CSV
|
|
957
966
|
# Creates or retrieves cached \CSV objects.
|
958
967
|
# For arguments and options, see CSV.new.
|
959
968
|
#
|
969
|
+
# This API is not Ractor-safe.
|
970
|
+
#
|
960
971
|
# ---
|
961
972
|
#
|
962
973
|
# With no block given, returns a \CSV object.
|
@@ -1187,7 +1198,7 @@ class CSV
|
|
1187
1198
|
# See {Options for Parsing}[#class-CSV-label-Options+for+Parsing].
|
1188
1199
|
def filter(input=nil, output=nil, **options)
|
1189
1200
|
# parse options for input, output, or both
|
1190
|
-
in_options, out_options = Hash.new, {row_sep:
|
1201
|
+
in_options, out_options = Hash.new, {row_sep: InputRecordSeparator.value}
|
1191
1202
|
options.each do |key, value|
|
1192
1203
|
case key.to_s
|
1193
1204
|
when /\Ain(?:put)?_(.+)\Z/
|
@@ -1407,8 +1418,8 @@ class CSV
|
|
1407
1418
|
# Argument +ary+ must be an \Array.
|
1408
1419
|
#
|
1409
1420
|
# Special options:
|
1410
|
-
# * Option <tt>:row_sep</tt> defaults to <tt
|
1411
|
-
# (<tt>$/</tt>).:
|
1421
|
+
# * Option <tt>:row_sep</tt> defaults to <tt>"\n"> on Ruby 3.0 or later
|
1422
|
+
# and <tt>$INPUT_RECORD_SEPARATOR</tt> (<tt>$/</tt>) otherwise.:
|
1412
1423
|
# $INPUT_RECORD_SEPARATOR # => "\n"
|
1413
1424
|
# * This method accepts an additional option, <tt>:encoding</tt>, which sets the base
|
1414
1425
|
# Encoding for the output. This method will try to guess your Encoding from
|
@@ -1430,7 +1441,7 @@ class CSV
|
|
1430
1441
|
# CSV.generate_line(:foo)
|
1431
1442
|
#
|
1432
1443
|
def generate_line(row, **options)
|
1433
|
-
options = {row_sep:
|
1444
|
+
options = {row_sep: InputRecordSeparator.value}.merge(options)
|
1434
1445
|
str = +""
|
1435
1446
|
if options[:encoding]
|
1436
1447
|
str.force_encoding(options[:encoding])
|
@@ -1992,6 +2003,10 @@ class CSV
|
|
1992
2003
|
# csv.converters # => [:integer]
|
1993
2004
|
# csv.convert(proc {|x| x.to_s })
|
1994
2005
|
# csv.converters
|
2006
|
+
#
|
2007
|
+
# Notes that you need to call
|
2008
|
+
# +Ractor.make_shareable(CSV::Converters)+ on the main Ractor to use
|
2009
|
+
# this method.
|
1995
2010
|
def converters
|
1996
2011
|
parser_fields_converter.map do |converter|
|
1997
2012
|
name = Converters.rassoc(converter)
|
@@ -2054,6 +2069,10 @@ class CSV
|
|
2054
2069
|
# Returns an \Array containing header converters; used for parsing;
|
2055
2070
|
# see {Header Converters}[#class-CSV-label-Header+Converters]:
|
2056
2071
|
# CSV.new('').header_converters # => []
|
2072
|
+
#
|
2073
|
+
# Notes that you need to call
|
2074
|
+
# +Ractor.make_shareable(CSV::HeaderConverters)+ on the main Ractor
|
2075
|
+
# to use this method.
|
2057
2076
|
def header_converters
|
2058
2077
|
header_fields_converter.map do |converter|
|
2059
2078
|
name = HeaderConverters.rassoc(converter)
|
@@ -2694,7 +2713,7 @@ class CSV
|
|
2694
2713
|
|
2695
2714
|
def build_parser_fields_converter
|
2696
2715
|
specific_options = {
|
2697
|
-
|
2716
|
+
builtin_converters_name: :Converters,
|
2698
2717
|
}
|
2699
2718
|
options = @base_fields_converter_options.merge(specific_options)
|
2700
2719
|
build_fields_converter(@initial_converters, options)
|
@@ -2706,7 +2725,7 @@ class CSV
|
|
2706
2725
|
|
2707
2726
|
def build_header_fields_converter
|
2708
2727
|
specific_options = {
|
2709
|
-
|
2728
|
+
builtin_converters_name: :HeaderConverters,
|
2710
2729
|
accept_nil: true,
|
2711
2730
|
}
|
2712
2731
|
options = @base_fields_converter_options.merge(specific_options)
|
@@ -2774,6 +2793,8 @@ end
|
|
2774
2793
|
# io = StringIO.new
|
2775
2794
|
# CSV(io, col_sep: ";") { |csv| csv << ["a", "b", "c"] }
|
2776
2795
|
#
|
2796
|
+
# This API is not Ractor-safe.
|
2797
|
+
#
|
2777
2798
|
def CSV(*args, **options, &block)
|
2778
2799
|
CSV.instance(*args, **options, &block)
|
2779
2800
|
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.2.
|
4
|
+
version: 3.2.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: 2021-
|
12
|
+
date: 2021-10-22 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|
@@ -59,14 +59,14 @@ dependencies:
|
|
59
59
|
requirements:
|
60
60
|
- - ">="
|
61
61
|
- !ruby/object:Gem::Version
|
62
|
-
version: 3.4.
|
62
|
+
version: 3.4.8
|
63
63
|
type: :development
|
64
64
|
prerelease: false
|
65
65
|
version_requirements: !ruby/object:Gem::Requirement
|
66
66
|
requirements:
|
67
67
|
- - ">="
|
68
68
|
- !ruby/object:Gem::Version
|
69
|
-
version: 3.4.
|
69
|
+
version: 3.4.8
|
70
70
|
description: The CSV library provides a complete interface to CSV files and data.
|
71
71
|
It offers tools to enable you to read and write to and from Strings or IO objects,
|
72
72
|
as needed.
|
@@ -118,6 +118,7 @@ files:
|
|
118
118
|
- lib/csv/core_ext/string.rb
|
119
119
|
- lib/csv/delete_suffix.rb
|
120
120
|
- lib/csv/fields_converter.rb
|
121
|
+
- lib/csv/input_record_separator.rb
|
121
122
|
- lib/csv/match_p.rb
|
122
123
|
- lib/csv/parser.rb
|
123
124
|
- lib/csv/row.rb
|