csv 3.2.0 → 3.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c48c0d15454e002ff10270a9c56cf4311ce635a8a9dfb527f7a7541f29f801b2
4
- data.tar.gz: 505d1d0dbb4cff0a544b2e00925cb1101ed71642a584d534f443405fba8bd820
3
+ metadata.gz: 6aee33c500a979f9f1a9afdbc394545932700ca3442c1b4326b417e59b654ef4
4
+ data.tar.gz: 6622e0c4f190f10aa6d3a49b023a6c24540b1133da4d0ef91c07016ba224073f
5
5
  SHA512:
6
- metadata.gz: 1c9ecd18d5b9a4f663c0676694ffc133a4657e2f7a07cafe2f0a5d9ddd2d7846f505bc62c21698fcf1117126efc6978b7aa1b497d2fef8d532a8a4246c58bff2
7
- data.tar.gz: e4fe05b49f92c68c011060d1dcd39ead1785d886eabbd3689a12884df9eb30124694417314e39bcf656cd05d6d0dea6a80a701dd5fe6cac42efc33c67be54926
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
@@ -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
- @builtin_converters = options[:builtin_converters]
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 = @builtin_converters[name]
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
- @@string_scanner_scan_accept_string = false
483
+ STRING_SCANNER_SCAN_ACCEPT_STRING = false
483
484
  else
484
- @@string_scanner_scan_accept_string = true
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 @@string_scanner_scan_accept_string
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
- @cr_or_lf = Regexp.new("[\r\n]".encode(@encoding))
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 = $INPUT_RECORD_SEPARATOR if separator == :auto
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: Integer(chunk_size, 10))
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(@cr_or_lf))
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(@cr_or_lf))
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(@cr_or_lf)
1094
+ @scanner.scan_all(@line_end)
1093
1095
  @lineno += 1
1094
1096
  end
1095
1097
 
data/lib/csv/version.rb CHANGED
@@ -2,5 +2,5 @@
2
2
 
3
3
  class CSV
4
4
  # The version of the installed library.
5
- VERSION = "3.2.0"
5
+ VERSION = "3.2.1"
6
6
  end
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 = $INPUT_RECORD_SEPARATOR.encode(@encoding)
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::Info object shows:
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: $INPUT_RECORD_SEPARATOR}
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>$INPUT_RECORD_SEPARATOR</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: $INPUT_RECORD_SEPARATOR}.merge(options)
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
- builtin_converters: Converters,
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
- builtin_converters: HeaderConverters,
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.0
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-06-05 00:00:00.000000000 Z
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.3
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.3
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