diff --git a/lib/csv.rb b/lib/csv.rb
index 20cfda4b41..170ab04c24 100644
--- a/lib/csv.rb
+++ b/lib/csv.rb
@@ -1465,6 +1465,46 @@ class CSV
(new(str, **options) << row).string
end
+ # :call-seq:
+ # CSV.generate_lines(rows)
+ # CSV.generate_lines(rows, **options)
+ #
+ # Returns the \String created by generating \CSV from
+ # using the specified +options+.
+ #
+ # Argument +rows+ must be an \Array of row. Row is \Array of \String or \CSV::Row.
+ #
+ # Special options:
+ # * Option :row_sep defaults to "\n" on Ruby 3.0 or later
+ # and $INPUT_RECORD_SEPARATOR ($/) otherwise.:
+ # $INPUT_RECORD_SEPARATOR # => "\n"
+ # * This method accepts an additional option, :encoding, which sets the base
+ # Encoding for the output. This method will try to guess your Encoding from
+ # the first non-+nil+ field in +row+, if possible, but you may need to use
+ # this parameter as a backup plan.
+ #
+ # For other +options+,
+ # see {Options for Generating}[#class-CSV-label-Options+for+Generating].
+ #
+ # ---
+ #
+ # Returns the \String generated from an
+ # CSV.generate_lines(['foo', '0'], ['bar', '1'], ['baz', '2']) # => "foo,0\nbar,1\nbaz.2\n"
+ #
+ # ---
+ #
+ # Raises an exception
+ # # Raises NoMethodError (undefined method `find' for :foo:Symbol)
+ # CSV.generate_lines(:foo)
+ #
+ def generate_lines(rows, **options)
+ self.generate(**options) do |csv|
+ rows.each do |row|
+ csv << row
+ end
+ end
+ end
+
#
# :call-seq:
# open(file_path, mode = "rb", **options ) -> new_csv
diff --git a/lib/csv/version.rb b/lib/csv/version.rb
index eaddde9a23..ca16064a89 100644
--- a/lib/csv/version.rb
+++ b/lib/csv/version.rb
@@ -2,5 +2,5 @@
class CSV
# The version of the installed library.
- VERSION = "3.2.4"
+ VERSION = "3.2.5"
end
diff --git a/test/csv/interface/test_write.rb b/test/csv/interface/test_write.rb
index 02c2c5c5ce..0cd39a7663 100644
--- a/test/csv/interface/test_write.rb
+++ b/test/csv/interface/test_write.rb
@@ -85,6 +85,15 @@ testrow
LINE
end
+ def test_generate_lines
+ lines = CSV.generate_lines([["foo", "bar"], [1, 2], [3, 4]])
+ assert_equal(<<-LINES, lines)
+foo,bar
+1,2
+3,4
+ LINES
+ end
+
def test_headers_detection
headers = ["a", "b", "c"]
CSV.open(@output.path, "w", headers: true) do |csv|
diff --git a/test/csv/parse/test_convert.rb b/test/csv/parse/test_convert.rb
index 2ac255695e..c9195c71d9 100644
--- a/test/csv/parse/test_convert.rb
+++ b/test/csv/parse/test_convert.rb
@@ -15,6 +15,22 @@ class TestCSVParseConvert < Test::Unit::TestCase
@time = Time.utc(2018, 12, 30, 6, 41, 29)
@windows_safe_time_data = @time.strftime("%a %b %d %H:%M:%S %Y")
+
+ @preserving_converter = lambda do |field, info|
+ f = field.encode(CSV::ConverterEncoding)
+ return f if info.quoted?
+ begin
+ Integer(f, 10)
+ rescue
+ f
+ end
+ end
+
+ @quoted_header_converter = lambda do |field, info|
+ f = field.encode(CSV::ConverterEncoding)
+ return f if info.quoted?
+ f.to_sym
+ end
end
def test_integer
@@ -108,62 +124,42 @@ class TestCSVParseConvert < Test::Unit::TestCase
CSV.parse_line(',"",a', empty_value: "empty"))
end
- sub_test_case("#quoted?") do
- def setup
- @preserving_converter = lambda do |field, info|
- f = field.encode(CSV::ConverterEncoding)
- return f if info.quoted?
- begin
- Integer(f, 10)
- rescue
- f
- end
- end
+ def test_quoted_parse_line
+ row = CSV.parse_line('1,"2",3', converters: @preserving_converter)
+ assert_equal([1, "2", 3], row)
+ end
- @quoted_header_converter = lambda do |field, info|
- f = field.encode(CSV::ConverterEncoding)
- return f if info.quoted?
- f.to_sym
- end
- end
+ def test_quoted_parse
+ expected = [["quoted", "unquoted"], ["109", 1], ["10A", 2]]
+ rows = CSV.parse(<<~CSV, converters: @preserving_converter)
+ "quoted",unquoted
+ "109",1
+ "10A",2
+ CSV
+ assert_equal(expected, rows)
+ end
- def test_parse_line
- row = CSV.parse_line('1,"2",3', converters: @preserving_converter)
- assert_equal([1, "2", 3], row)
- end
+ def test_quoted_alternating_quote
+ row = CSV.parse_line('"1",2,"3"', converters: @preserving_converter)
+ assert_equal(['1', 2, '3'], row)
+ end
- def test_parse
- expected = [["quoted", "unquoted"], ["109", 1], ["10A", 2]]
- rows = CSV.parse(<<~CSV, converters: @preserving_converter)
- "quoted",unquoted
- "109",1
- "10A",2
- CSV
- assert_equal(expected, rows)
- end
+ def test_quoted_parse_headers
+ expected = [["quoted", :unquoted], ["109", "1"], ["10A", "2"]]
+ table = CSV.parse(<<~CSV, headers: true, header_converters: @quoted_header_converter)
+ "quoted",unquoted
+ "109",1
+ "10A",2
+ CSV
+ assert_equal(expected, table.to_a)
+ end
- def test_alternating_quote
- row = CSV.parse_line('"1",2,"3"', converters: @preserving_converter)
- assert_equal(['1', 2, '3'], row)
- end
-
- def test_parse_headers
- expected = [["quoted", :unquoted], ["109", "1"], ["10A", "2"]]
- table = CSV.parse(<<~CSV, headers: true, header_converters: @quoted_header_converter)
- "quoted",unquoted
- "109",1
- "10A",2
- CSV
- assert_equal(expected, table.to_a)
- end
-
- def test_parse_with_string_headers
- expected = [["quoted", :unquoted], %w[109 1], %w[10A 2]]
- table = CSV.parse(<<~CSV, headers: '"quoted",unquoted', header_converters: @quoted_header_converter)
- "109",1
- "10A",2
- CSV
- assert_equal(expected, table.to_a)
- end
+ def test_quoted_parse_with_string_headers
+ expected = [["quoted", :unquoted], %w[109 1], %w[10A 2]]
+ table = CSV.parse(<<~CSV, headers: '"quoted",unquoted', header_converters: @quoted_header_converter)
+ "109",1
+ "10A",2
+ CSV
+ assert_equal(expected, table.to_a)
end
end