From caf27c813e4119b387e17b16aaf7df9f113b715a Mon Sep 17 00:00:00 2001 From: Marcelo Pereira Date: Sat, 4 May 2024 13:27:17 +0200 Subject: [PATCH 01/16] Allow CSV.foreach with StringIO argument --- lib/csv.rb | 43 ++++++++++++++++++++++----------- test/csv/interface/test_read.rb | 39 ++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 14 deletions(-) diff --git a/lib/csv.rb b/lib/csv.rb index 0cf49eb2..3adc4ed6 100644 --- a/lib/csv.rb +++ b/lib/csv.rb @@ -1508,10 +1508,8 @@ def generate_lines(rows, **options) # # :call-seq: - # open(file_path, mode = "rb", **options ) -> new_csv - # open(io, mode = "rb", **options ) -> new_csv - # open(file_path, mode = "rb", **options ) { |csv| ... } -> object - # open(io, mode = "rb", **options ) { |csv| ... } -> object + # open(path_or_io, mode = "rb", **options ) -> new_csv + # open(path_or_io, mode = "rb", **options ) { |csv| ... } -> object # # possible options elements: # keyword form: @@ -1520,7 +1518,7 @@ def generate_lines(rows, **options) # :undef => :replace # replace undefined conversion # :replace => string # replacement string ("?" or "\uFFFD" if not specified) # - # * Argument +path+, if given, must be the path to a file. + # * Argument +path_or_io+, must be a file path or an \IO stream. # :include: ../doc/csv/arguments/io.rdoc # * Argument +mode+, if given, must be a \File mode. # See {Access Modes}[https://docs.ruby-lang.org/en/master/File.html#class-File-label-Access+Modes]. @@ -1544,6 +1542,10 @@ def generate_lines(rows, **options) # path = 't.csv' # File.write(path, string) # + # string_io = StringIO.new + # string_io << "foo,0\nbar,1\nbaz,2\n" + # string_io.rewind + # # --- # # With no block given, returns a new \CSV object. @@ -1556,6 +1558,9 @@ def generate_lines(rows, **options) # csv = CSV.open(File.open(path)) # csv # => # # + # Create a \CSV object using a \StringIO: + # csv = CSV.open(string_io) + # csv # => # # --- # # With a block given, calls the block with the created \CSV object; @@ -1573,12 +1578,17 @@ def generate_lines(rows, **options) # Output: # # # + # Using a \StringIO: + # csv = CSV.open(string_io) {|csv| p csv} + # csv # => # + # Output: + # # # --- # # Raises an exception if the argument is not a \String object or \IO object: # # Raises TypeError (no implicit conversion of Symbol into String) # CSV.open(:foo) - def open(filename, mode="r", **options) + def open(filename_or_io, mode="r", **options) # wrap a File opened with the remaining +args+ with no newline # decorator file_opts = {} @@ -1592,14 +1602,19 @@ def open(filename, mode="r", **options) options.delete(:replace) options.delete_if {|k, _| /newline\z/.match?(k)} - begin - f = File.open(filename, mode, **file_opts) - rescue ArgumentError => e - raise unless /needs binmode/.match?(e.message) and mode == "r" - mode = "rb" - file_opts = {encoding: Encoding.default_external}.merge(file_opts) - retry + if filename_or_io.is_a?(StringIO) + f = filename_or_io + else + begin + f = File.open(filename_or_io, mode, **file_opts) + rescue ArgumentError => e + raise unless /needs binmode/.match?(e.message) and mode == "r" + mode = "rb" + file_opts = {encoding: Encoding.default_external}.merge(file_opts) + retry + end end + begin csv = new(f, **options) rescue Exception @@ -1612,7 +1627,7 @@ def open(filename, mode="r", **options) begin yield csv ensure - csv.close + csv.close unless f.is_a?(StringIO) end else csv diff --git a/test/csv/interface/test_read.rb b/test/csv/interface/test_read.rb index b0e1e24e..1ff8df33 100644 --- a/test/csv/interface/test_read.rb +++ b/test/csv/interface/test_read.rb @@ -32,6 +32,18 @@ def test_foreach assert_equal(@rows, rows) end + def test_foreach_stringio + s = StringIO.new + s << @data + s.rewind + + rows = [] + CSV.foreach(s, col_sep: "\t", row_sep: "\r\n") do |row| + rows << row + end + assert_equal(@rows, rows) + end + if respond_to?(:ractor) ractor def test_foreach_in_ractor @@ -48,6 +60,25 @@ def test_foreach_in_ractor ] assert_equal(rows, ractor.take) end + + def test_foreach_stringio_in_ractor + s = StringIO.new + s << @data + s.rewind + + ractor = Ractor.new(s) do |string_io| + rows = [] + CSV.foreach(string_io, col_sep: "\t", row_sep: "\r\n") do |row| + rows << row + end + rows + end + rows = [ + ["1", "2", "3"], + ["4", "5"], + ] + assert_equal(rows, ractor.take) + end end def test_foreach_mode @@ -63,6 +94,14 @@ def test_foreach_enumerator assert_equal(@rows, rows) end + def test_foreach_enumerator_stringio + s = StringIO.new + s << @data + s.rewind + rows = CSV.foreach(s, col_sep: "\t", row_sep: "\r\n").to_a + assert_equal(@rows, rows) + end + def test_closed? csv = CSV.open(@input.path, "r+", col_sep: "\t", row_sep: "\r\n") assert_not_predicate(csv, :closed?) From fb8740c36c373c6441c3a3733eaabd66d59ca5fb Mon Sep 17 00:00:00 2001 From: Marcelo Pereira Date: Sun, 5 May 2024 11:00:38 +0200 Subject: [PATCH 02/16] When a StringIO is passed as argument to CSV.open, create a new one instead of reusing it --- lib/csv.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/csv.rb b/lib/csv.rb index 3adc4ed6..099f026c 100644 --- a/lib/csv.rb +++ b/lib/csv.rb @@ -1603,7 +1603,9 @@ def open(filename_or_io, mode="r", **options) options.delete_if {|k, _| /newline\z/.match?(k)} if filename_or_io.is_a?(StringIO) - f = filename_or_io + pos = filename_or_io.pos + f = StringIO.new(filename_or_io.read) + filename_or_io.seek(pos) else begin f = File.open(filename_or_io, mode, **file_opts) From 374788f00fdeaf74c4a80a5114d01da212cc1c43 Mon Sep 17 00:00:00 2001 From: Marcelo Date: Fri, 17 May 2024 22:05:52 +0200 Subject: [PATCH 03/16] Declares test that uses ractor Co-authored-by: Sutou Kouhei --- test/csv/interface/test_read.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/test/csv/interface/test_read.rb b/test/csv/interface/test_read.rb index 1ff8df33..b9a2fcf1 100644 --- a/test/csv/interface/test_read.rb +++ b/test/csv/interface/test_read.rb @@ -61,6 +61,7 @@ def test_foreach_in_ractor assert_equal(rows, ractor.take) end + ractor def test_foreach_stringio_in_ractor s = StringIO.new s << @data From b5bcbb0e3b100859f24da2b7f55dbb791bb403df Mon Sep 17 00:00:00 2001 From: Marcelo Pereira Date: Fri, 24 May 2024 15:16:23 +0200 Subject: [PATCH 04/16] Add test for StringIO with non-zero pos --- test/csv/interface/test_read.rb | 25 +++---------------------- 1 file changed, 3 insertions(+), 22 deletions(-) diff --git a/test/csv/interface/test_read.rb b/test/csv/interface/test_read.rb index b9a2fcf1..7fd9aadc 100644 --- a/test/csv/interface/test_read.rb +++ b/test/csv/interface/test_read.rb @@ -60,26 +60,6 @@ def test_foreach_in_ractor ] assert_equal(rows, ractor.take) end - - ractor - def test_foreach_stringio_in_ractor - s = StringIO.new - s << @data - s.rewind - - ractor = Ractor.new(s) do |string_io| - rows = [] - CSV.foreach(string_io, col_sep: "\t", row_sep: "\r\n") do |row| - rows << row - end - rows - end - rows = [ - ["1", "2", "3"], - ["4", "5"], - ] - assert_equal(rows, ractor.take) - end end def test_foreach_mode @@ -95,10 +75,11 @@ def test_foreach_enumerator assert_equal(@rows, rows) end - def test_foreach_enumerator_stringio + def test_foreach_seeked_stringio s = StringIO.new + s << "012" s << @data - s.rewind + s.seek(3) rows = CSV.foreach(s, col_sep: "\t", row_sep: "\r\n").to_a assert_equal(@rows, rows) end From 7a0d386ff8cc0e20f0863acc6d38987977bec257 Mon Sep 17 00:00:00 2001 From: Marcelo Pereira Date: Sat, 25 May 2024 11:13:08 +0200 Subject: [PATCH 05/16] Read full StringIO content in CSV.open, handle BOM by default --- lib/csv.rb | 5 +---- test/csv/interface/test_read.rb | 18 ++++++++---------- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/lib/csv.rb b/lib/csv.rb index 099f026c..ae0b3658 100644 --- a/lib/csv.rb +++ b/lib/csv.rb @@ -1544,7 +1544,6 @@ def generate_lines(rows, **options) # # string_io = StringIO.new # string_io << "foo,0\nbar,1\nbaz,2\n" - # string_io.rewind # # --- # @@ -1603,9 +1602,7 @@ def open(filename_or_io, mode="r", **options) options.delete_if {|k, _| /newline\z/.match?(k)} if filename_or_io.is_a?(StringIO) - pos = filename_or_io.pos - f = StringIO.new(filename_or_io.read) - filename_or_io.seek(pos) + f = StringIO.new(filename_or_io.string, **file_opts) else begin f = File.open(filename_or_io, mode, **file_opts) diff --git a/test/csv/interface/test_read.rb b/test/csv/interface/test_read.rb index 7fd9aadc..bc70bc16 100644 --- a/test/csv/interface/test_read.rb +++ b/test/csv/interface/test_read.rb @@ -35,7 +35,6 @@ def test_foreach def test_foreach_stringio s = StringIO.new s << @data - s.rewind rows = [] CSV.foreach(s, col_sep: "\t", row_sep: "\r\n") do |row| @@ -44,6 +43,14 @@ def test_foreach_stringio assert_equal(@rows, rows) end + def test_foreach_stringio_with_bom + s = StringIO.new + s << "\ufeff" # U+FEFF ZERO WIDTH NO-BREAK SPACE + s << @data + rows = CSV.foreach(s, col_sep: "\t", row_sep: "\r\n").to_a + assert_equal(@rows, rows) + end + if respond_to?(:ractor) ractor def test_foreach_in_ractor @@ -75,15 +82,6 @@ def test_foreach_enumerator assert_equal(@rows, rows) end - def test_foreach_seeked_stringio - s = StringIO.new - s << "012" - s << @data - s.seek(3) - rows = CSV.foreach(s, col_sep: "\t", row_sep: "\r\n").to_a - assert_equal(@rows, rows) - end - def test_closed? csv = CSV.open(@input.path, "r+", col_sep: "\t", row_sep: "\r\n") assert_not_predicate(csv, :closed?) From 88d1c77e2b55c0f6e439be5a5e62156c585488d3 Mon Sep 17 00:00:00 2001 From: Marcelo Pereira Date: Sun, 26 May 2024 11:41:06 +0200 Subject: [PATCH 06/16] Simplify tests and use more descriptive variable names --- test/csv/interface/test_read.rb | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/test/csv/interface/test_read.rb b/test/csv/interface/test_read.rb index bc70bc16..2db417ed 100644 --- a/test/csv/interface/test_read.rb +++ b/test/csv/interface/test_read.rb @@ -33,21 +33,18 @@ def test_foreach end def test_foreach_stringio - s = StringIO.new - s << @data + string_io = StringIO.new(@data) rows = [] - CSV.foreach(s, col_sep: "\t", row_sep: "\r\n") do |row| + CSV.foreach(string_io, col_sep: "\t", row_sep: "\r\n") do |row| rows << row end assert_equal(@rows, rows) end def test_foreach_stringio_with_bom - s = StringIO.new - s << "\ufeff" # U+FEFF ZERO WIDTH NO-BREAK SPACE - s << @data - rows = CSV.foreach(s, col_sep: "\t", row_sep: "\r\n").to_a + string_io = StringIO.new("\ufeff#{@data}") # U+FEFF ZERO WIDTH NO-BREAK SPACE + rows = CSV.foreach(string_io, col_sep: "\t", row_sep: "\r\n").to_a assert_equal(@rows, rows) end From dbc6e3519dea64ff77cb4109178b4ad2fe712450 Mon Sep 17 00:00:00 2001 From: Marcelo Pereira Date: Tue, 4 Jun 2024 21:47:54 +0200 Subject: [PATCH 07/16] Simplify foreach test --- test/csv/interface/test_read.rb | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/test/csv/interface/test_read.rb b/test/csv/interface/test_read.rb index 2db417ed..7a746e7e 100644 --- a/test/csv/interface/test_read.rb +++ b/test/csv/interface/test_read.rb @@ -36,9 +36,7 @@ def test_foreach_stringio string_io = StringIO.new(@data) rows = [] - CSV.foreach(string_io, col_sep: "\t", row_sep: "\r\n") do |row| - rows << row - end + rows = CSV.foreach(string_io, col_sep: "\t", row_sep: "\r\n").to_a assert_equal(@rows, rows) end From 1157cf3ee639d2f1a5ea2b3a8f00dba7821d8931 Mon Sep 17 00:00:00 2001 From: Sutou Kouhei Date: Wed, 5 Jun 2024 06:10:32 +0900 Subject: [PATCH 08/16] Remove garbage --- test/csv/interface/test_read.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/csv/interface/test_read.rb b/test/csv/interface/test_read.rb index 7a746e7e..183e4c28 100644 --- a/test/csv/interface/test_read.rb +++ b/test/csv/interface/test_read.rb @@ -34,8 +34,6 @@ def test_foreach def test_foreach_stringio string_io = StringIO.new(@data) - - rows = [] rows = CSV.foreach(string_io, col_sep: "\t", row_sep: "\r\n").to_a assert_equal(@rows, rows) end From f17e72dbc74312e2da5d17e7ea43fe6f0096d7b7 Mon Sep 17 00:00:00 2001 From: Marcelo Pereira Date: Fri, 14 Jun 2024 11:53:19 +0200 Subject: [PATCH 09/16] Remove unnecesary StringIO check when closing CSV in CSV#open This check had been added before we started copying the StringIO argument passed to `#open`, as part of instantiating CSV. Right now we can call `csv.close` even if the underlying IO is a StringIO, without any unexpected side effect. --- lib/csv.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/csv.rb b/lib/csv.rb index ae0b3658..7511cedb 100644 --- a/lib/csv.rb +++ b/lib/csv.rb @@ -1626,7 +1626,7 @@ def open(filename_or_io, mode="r", **options) begin yield csv ensure - csv.close unless f.is_a?(StringIO) + csv.close end else csv From ad3fcd45d48e5b478ac7077ce005ae27d3d04ed6 Mon Sep 17 00:00:00 2001 From: Marcelo Pereira Date: Mon, 17 Jun 2024 18:38:56 +0200 Subject: [PATCH 10/16] Skip Windows BOM bypass if opening a StringIO --- lib/csv.rb | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/lib/csv.rb b/lib/csv.rb index 7511cedb..0c652efe 100644 --- a/lib/csv.rb +++ b/lib/csv.rb @@ -1591,7 +1591,10 @@ def open(filename_or_io, mode="r", **options) # wrap a File opened with the remaining +args+ with no newline # decorator file_opts = {} - may_enable_bom_deletection_automatically(mode, options, file_opts) + may_enable_bom_detection_automatically(filename_or_io, + mode, + options, + file_opts) file_opts.merge!(options) unless file_opts.key?(:newline) file_opts[:universal_newline] ||= false @@ -1900,10 +1903,15 @@ def table(path, **options) private_constant :ON_WINDOWS private - def may_enable_bom_deletection_automatically(mode, options, file_opts) - # "bom|utf-8" may be buggy on Windows: - # https://bugs.ruby-lang.org/issues/20526 - return if ON_WINDOWS + def may_enable_bom_detection_automatically(filename_or_io, + mode, + options, + file_opts) + unless filename_or_io.is_a?(StringIO) + # "bom|utf-8" may be buggy on Windows: + # https://bugs.ruby-lang.org/issues/20526 + return if ON_WINDOWS + end return unless Encoding.default_external == Encoding::UTF_8 return if options.key?(:encoding) return if options.key?(:external_encoding) From e089151795274c429ede10bf9fe17e65f31e85bd Mon Sep 17 00:00:00 2001 From: Marcelo Pereira Date: Thu, 1 Aug 2024 17:48:25 +0200 Subject: [PATCH 11/16] Don't run StringIO tests in Ruby versions < 2.7 --- test/csv/interface/test_read.rb | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/test/csv/interface/test_read.rb b/test/csv/interface/test_read.rb index 183e4c28..ed96c72f 100644 --- a/test/csv/interface/test_read.rb +++ b/test/csv/interface/test_read.rb @@ -32,16 +32,20 @@ def test_foreach assert_equal(@rows, rows) end - def test_foreach_stringio - string_io = StringIO.new(@data) - rows = CSV.foreach(string_io, col_sep: "\t", row_sep: "\r\n").to_a - assert_equal(@rows, rows) - end + if RUBY_VERSION >= "2.7" + # Support to StringIO was dropped for Ruby 2.6 and earlier: + # https://github.com/ruby/stringio/pull/47 + def test_foreach_stringio + string_io = StringIO.new(@data) + rows = CSV.foreach(string_io, col_sep: "\t", row_sep: "\r\n").to_a + assert_equal(@rows, rows) + end - def test_foreach_stringio_with_bom - string_io = StringIO.new("\ufeff#{@data}") # U+FEFF ZERO WIDTH NO-BREAK SPACE - rows = CSV.foreach(string_io, col_sep: "\t", row_sep: "\r\n").to_a - assert_equal(@rows, rows) + def test_foreach_stringio_with_bom + string_io = StringIO.new("\ufeff#{@data}") # U+FEFF ZERO WIDTH NO-BREAK SPACE + rows = CSV.foreach(string_io, col_sep: "\t", row_sep: "\r\n").to_a + assert_equal(@rows, rows) + end end if respond_to?(:ractor) From e499e6c15f033ddad6ad32d0879310c3925105df Mon Sep 17 00:00:00 2001 From: Marcelo Pereira Date: Sat, 3 Aug 2024 15:14:40 +0200 Subject: [PATCH 12/16] Use StringIO options only in Ruby >= 2.7 --- lib/csv.rb | 6 +++++- test/csv/interface/test_read.rb | 26 ++++++++++++++------------ 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/lib/csv.rb b/lib/csv.rb index 0c652efe..5f75894e 100644 --- a/lib/csv.rb +++ b/lib/csv.rb @@ -1605,7 +1605,11 @@ def open(filename_or_io, mode="r", **options) options.delete_if {|k, _| /newline\z/.match?(k)} if filename_or_io.is_a?(StringIO) - f = StringIO.new(filename_or_io.string, **file_opts) + f = if RUBY_VERSION >= "2.7" + StringIO.new(filename_or_io.string, **file_opts) + else + StringIO.new(filename_or_io.string) + end else begin f = File.open(filename_or_io, mode, **file_opts) diff --git a/test/csv/interface/test_read.rb b/test/csv/interface/test_read.rb index ed96c72f..7537c76e 100644 --- a/test/csv/interface/test_read.rb +++ b/test/csv/interface/test_read.rb @@ -32,20 +32,22 @@ def test_foreach assert_equal(@rows, rows) end - if RUBY_VERSION >= "2.7" - # Support to StringIO was dropped for Ruby 2.6 and earlier: - # https://github.com/ruby/stringio/pull/47 - def test_foreach_stringio - string_io = StringIO.new(@data) - rows = CSV.foreach(string_io, col_sep: "\t", row_sep: "\r\n").to_a - assert_equal(@rows, rows) - end + def test_foreach_stringio + string_io = StringIO.new(@data) + rows = CSV.foreach(string_io, col_sep: "\t", row_sep: "\r\n").to_a + assert_equal(@rows, rows) + end - def test_foreach_stringio_with_bom - string_io = StringIO.new("\ufeff#{@data}") # U+FEFF ZERO WIDTH NO-BREAK SPACE - rows = CSV.foreach(string_io, col_sep: "\t", row_sep: "\r\n").to_a - assert_equal(@rows, rows) + def test_foreach_stringio_with_bom + if RUBY_VERSION < "2.7" + # Support to StringIO was dropped for Ruby 2.6 and earlier without BOM support: + # https://github.com/ruby/stringio/pull/47 + omit("StringIO's BOM support isn't available with Ruby < 2.7") end + + string_io = StringIO.new("\ufeff#{@data}") # U+FEFF ZERO WIDTH NO-BREAK SPACE + rows = CSV.foreach(string_io, col_sep: "\t", row_sep: "\r\n").to_a + assert_equal(@rows, rows) end if respond_to?(:ractor) From f2d5b92cd0f7018ce4e59486300ac048727bb7c2 Mon Sep 17 00:00:00 2001 From: Marcelo Pereira Date: Sun, 4 Aug 2024 13:02:31 +0200 Subject: [PATCH 13/16] Raise error when unsupported options are given to open a StringIO --- lib/csv.rb | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/lib/csv.rb b/lib/csv.rb index 5f75894e..403ba75e 100644 --- a/lib/csv.rb +++ b/lib/csv.rb @@ -1605,11 +1605,8 @@ def open(filename_or_io, mode="r", **options) options.delete_if {|k, _| /newline\z/.match?(k)} if filename_or_io.is_a?(StringIO) - f = if RUBY_VERSION >= "2.7" - StringIO.new(filename_or_io.string, **file_opts) - else - StringIO.new(filename_or_io.string) - end + filter_supported_stringio_open_opts!(file_opts) + f = StringIO.new(filename_or_io.string, **file_opts) else begin f = File.open(filename_or_io, mode, **file_opts) @@ -1911,7 +1908,11 @@ def may_enable_bom_detection_automatically(filename_or_io, mode, options, file_opts) - unless filename_or_io.is_a?(StringIO) + if filename_or_io.is_a?(StringIO) + # Support to StringIO was dropped for Ruby 2.6 and earlier without BOM support: + # https://github.com/ruby/stringio/pull/47 + return if RUBY_VERSION < "2.7" + else # "bom|utf-8" may be buggy on Windows: # https://bugs.ruby-lang.org/issues/20526 return if ON_WINDOWS @@ -1922,6 +1923,16 @@ def may_enable_bom_detection_automatically(filename_or_io, return if mode.include?(":") file_opts[:encoding] = "bom|utf-8" end + + if RUBY_VERSION < "2.7" + def filter_supported_stringio_open_opts!(opts) + opts.reject! { |k, _| k == :universal_newline || DEFAULT_OPTIONS.key?(k) } + raise ArgumentError, "Unsupported options parsing StringIO: #{opts.keys}" unless opts.empty? + end + else + def filter_supported_stringio_open_opts!(opts) + end + end end # :call-seq: From 74a9e0d78525e46d108f457ca92d6dcf81b7ae23 Mon Sep 17 00:00:00 2001 From: Marcelo Pereira Date: Sun, 4 Aug 2024 14:11:18 +0200 Subject: [PATCH 14/16] Initialize StringIO without options in Ruby < 2.7 --- lib/csv.rb | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/csv.rb b/lib/csv.rb index 403ba75e..3a317cb3 100644 --- a/lib/csv.rb +++ b/lib/csv.rb @@ -1605,8 +1605,7 @@ def open(filename_or_io, mode="r", **options) options.delete_if {|k, _| /newline\z/.match?(k)} if filename_or_io.is_a?(StringIO) - filter_supported_stringio_open_opts!(file_opts) - f = StringIO.new(filename_or_io.string, **file_opts) + f = init_stringio!(filename_or_io.string, mode, **file_opts) else begin f = File.open(filename_or_io, mode, **file_opts) @@ -1925,12 +1924,14 @@ def may_enable_bom_detection_automatically(filename_or_io, end if RUBY_VERSION < "2.7" - def filter_supported_stringio_open_opts!(opts) + def init_stringio!(str, mode, opts) opts.reject! { |k, _| k == :universal_newline || DEFAULT_OPTIONS.key?(k) } raise ArgumentError, "Unsupported options parsing StringIO: #{opts.keys}" unless opts.empty? + StringIO.new(str) end else - def filter_supported_stringio_open_opts!(opts) + def init_stringio!(str, mode, opts) + StringIO.new(str, mode, **opts) end end end From 3f94fb4c371fecf5c7611aa947ab98156d0eca56 Mon Sep 17 00:00:00 2001 From: Marcelo Pereira Date: Mon, 5 Aug 2024 06:55:29 +0200 Subject: [PATCH 15/16] Adhere to existing code conventions --- lib/csv.rb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/csv.rb b/lib/csv.rb index 3a317cb3..d5cf0d7d 100644 --- a/lib/csv.rb +++ b/lib/csv.rb @@ -1605,7 +1605,7 @@ def open(filename_or_io, mode="r", **options) options.delete_if {|k, _| /newline\z/.match?(k)} if filename_or_io.is_a?(StringIO) - f = init_stringio!(filename_or_io.string, mode, **file_opts) + f = create_stringio(filename_or_io.string, mode, **file_opts) else begin f = File.open(filename_or_io, mode, **file_opts) @@ -1924,13 +1924,13 @@ def may_enable_bom_detection_automatically(filename_or_io, end if RUBY_VERSION < "2.7" - def init_stringio!(str, mode, opts) - opts.reject! { |k, _| k == :universal_newline || DEFAULT_OPTIONS.key?(k) } + def create_stringio(str, mode, opts) + opts.delete_if { |k, _| k == :universal_newline or DEFAULT_OPTIONS.key?(k) } raise ArgumentError, "Unsupported options parsing StringIO: #{opts.keys}" unless opts.empty? - StringIO.new(str) + StringIO.new(str, mode) end else - def init_stringio!(str, mode, opts) + def create_stringio(str, mode, opts) StringIO.new(str, mode, **opts) end end From 5bab5e2c00bf6b6f687d45c199ded05ac5395882 Mon Sep 17 00:00:00 2001 From: Sutou Kouhei Date: Mon, 5 Aug 2024 14:10:31 +0900 Subject: [PATCH 16/16] Adjust style --- lib/csv.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/csv.rb b/lib/csv.rb index d5cf0d7d..41667006 100644 --- a/lib/csv.rb +++ b/lib/csv.rb @@ -1925,7 +1925,7 @@ def may_enable_bom_detection_automatically(filename_or_io, if RUBY_VERSION < "2.7" def create_stringio(str, mode, opts) - opts.delete_if { |k, _| k == :universal_newline or DEFAULT_OPTIONS.key?(k) } + opts.delete_if {|k, _| k == :universal_newline or DEFAULT_OPTIONS.key?(k)} raise ArgumentError, "Unsupported options parsing StringIO: #{opts.keys}" unless opts.empty? StringIO.new(str, mode) end