[ruby/csv] force_quotes: add support for specifying the target indexes or names
GitHub: fix GH-153 Reported by Aleksandr. Thanks!!! https://github.com/ruby/csv/commit/8812c58a26
This commit is contained in:
parent
d9749b4715
commit
178649e6dc
Notes:
git
2020-07-20 03:35:32 +09:00
@ -43,8 +43,10 @@ class CSV
|
|||||||
|
|
||||||
row = @fields_converter.convert(row, nil, lineno) if @fields_converter
|
row = @fields_converter.convert(row, nil, lineno) if @fields_converter
|
||||||
|
|
||||||
|
i = -1
|
||||||
converted_row = row.collect do |field|
|
converted_row = row.collect do |field|
|
||||||
quote(field)
|
i += 1
|
||||||
|
quote(field, i)
|
||||||
end
|
end
|
||||||
line = converted_row.join(@column_separator) + @row_separator
|
line = converted_row.join(@column_separator) + @row_separator
|
||||||
if @output_encoding
|
if @output_encoding
|
||||||
@ -100,6 +102,33 @@ class CSV
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def prepare_force_quotes_fields(force_quotes)
|
||||||
|
@force_quotes_fields = {}
|
||||||
|
force_quotes.each do |name_or_index|
|
||||||
|
case name_or_index
|
||||||
|
when Integer
|
||||||
|
index = name_or_index
|
||||||
|
@force_quotes_fields[index] = true
|
||||||
|
when String, Symbol
|
||||||
|
name = name_or_index.to_s
|
||||||
|
if @headers.nil?
|
||||||
|
message = ":headers is required when you use field name " +
|
||||||
|
"in :force_quotes: " +
|
||||||
|
"#{name_or_index.inspect}: #{force_quotes.inspect}"
|
||||||
|
raise ArgumentError, message
|
||||||
|
end
|
||||||
|
index = @headers.index(name)
|
||||||
|
next if index.nil?
|
||||||
|
@force_quotes_fields[index] = true
|
||||||
|
else
|
||||||
|
message = ":force_quotes element must be " +
|
||||||
|
"field index or field name: " +
|
||||||
|
"#{name_or_index.inspect}: #{force_quotes.inspect}"
|
||||||
|
raise ArgumentError, message
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def prepare_format
|
def prepare_format
|
||||||
@column_separator = @options[:column_separator].to_s.encode(@encoding)
|
@column_separator = @options[:column_separator].to_s.encode(@encoding)
|
||||||
row_separator = @options[:row_separator]
|
row_separator = @options[:row_separator]
|
||||||
@ -109,7 +138,17 @@ class CSV
|
|||||||
@row_separator = row_separator.to_s.encode(@encoding)
|
@row_separator = row_separator.to_s.encode(@encoding)
|
||||||
end
|
end
|
||||||
@quote_character = @options[:quote_character]
|
@quote_character = @options[:quote_character]
|
||||||
@force_quotes = @options[:force_quotes]
|
force_quotes = @options[:force_quotes]
|
||||||
|
if force_quotes.is_a?(Array)
|
||||||
|
prepare_force_quotes_fields(force_quotes)
|
||||||
|
@force_quotes = false
|
||||||
|
elsif force_quotes
|
||||||
|
@force_quotes_fields = nil
|
||||||
|
@force_quotes = true
|
||||||
|
else
|
||||||
|
@force_quotes_fields = nil
|
||||||
|
@force_quotes = false
|
||||||
|
end
|
||||||
unless @force_quotes
|
unless @force_quotes
|
||||||
@quotable_pattern =
|
@quotable_pattern =
|
||||||
Regexp.new("[\r\n".encode(@encoding) +
|
Regexp.new("[\r\n".encode(@encoding) +
|
||||||
@ -147,9 +186,11 @@ class CSV
|
|||||||
encoded_quote_character
|
encoded_quote_character
|
||||||
end
|
end
|
||||||
|
|
||||||
def quote(field)
|
def quote(field, i)
|
||||||
if @force_quotes
|
if @force_quotes
|
||||||
quote_field(field)
|
quote_field(field)
|
||||||
|
elsif @force_quotes_fields and @force_quotes_fields[i]
|
||||||
|
quote_field(field)
|
||||||
else
|
else
|
||||||
if field.nil? # represent +nil+ fields as empty unquoted fields
|
if field.nil? # represent +nil+ fields as empty unquoted fields
|
||||||
""
|
""
|
||||||
|
78
test/csv/write/test_force_quotes.rb
Normal file
78
test/csv/write/test_force_quotes.rb
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
# frozen_string_literal: false
|
||||||
|
|
||||||
|
require_relative "../helper"
|
||||||
|
|
||||||
|
module TestCSVWriteForceQuotes
|
||||||
|
def test_default
|
||||||
|
assert_equal(%Q[1,2,3#{$INPUT_RECORD_SEPARATOR}],
|
||||||
|
generate_line(["1", "2", "3"]))
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_true
|
||||||
|
assert_equal(%Q["1","2","3"#{$INPUT_RECORD_SEPARATOR}],
|
||||||
|
generate_line(["1", "2", "3"],
|
||||||
|
force_quotes: true))
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_false
|
||||||
|
assert_equal(%Q[1,2,3#{$INPUT_RECORD_SEPARATOR}],
|
||||||
|
generate_line(["1", "2", "3"],
|
||||||
|
force_quotes: false))
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_field_name
|
||||||
|
assert_equal(%Q["1",2,"3"#{$INPUT_RECORD_SEPARATOR}],
|
||||||
|
generate_line(["1", "2", "3"],
|
||||||
|
headers: ["a", "b", "c"],
|
||||||
|
force_quotes: ["a", :c]))
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_field_name_without_headers
|
||||||
|
force_quotes = ["a", "c"]
|
||||||
|
error = assert_raise(ArgumentError) do
|
||||||
|
generate_line(["1", "2", "3"],
|
||||||
|
force_quotes: force_quotes)
|
||||||
|
end
|
||||||
|
assert_equal(":headers is required when you use field name " +
|
||||||
|
"in :force_quotes: " +
|
||||||
|
"#{force_quotes.first.inspect}: #{force_quotes.inspect}",
|
||||||
|
error.message)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_field_index
|
||||||
|
assert_equal(%Q["1",2,"3"#{$INPUT_RECORD_SEPARATOR}],
|
||||||
|
generate_line(["1", "2", "3"],
|
||||||
|
force_quotes: [0, 2]))
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_field_unknown
|
||||||
|
force_quotes = [1.1]
|
||||||
|
error = assert_raise(ArgumentError) do
|
||||||
|
generate_line(["1", "2", "3"],
|
||||||
|
force_quotes: force_quotes)
|
||||||
|
end
|
||||||
|
assert_equal(":force_quotes element must be field index or field name: " +
|
||||||
|
"#{force_quotes.first.inspect}: #{force_quotes.inspect}",
|
||||||
|
error.message)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class TestCSVWriteForceQuotesGenerateLine < Test::Unit::TestCase
|
||||||
|
include TestCSVWriteForceQuotes
|
||||||
|
extend DifferentOFS
|
||||||
|
|
||||||
|
def generate_line(row, **kwargs)
|
||||||
|
CSV.generate_line(row, **kwargs)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class TestCSVWriteForceQuotesGenerate < Test::Unit::TestCase
|
||||||
|
include TestCSVWriteForceQuotes
|
||||||
|
extend DifferentOFS
|
||||||
|
|
||||||
|
def generate_line(row, **kwargs)
|
||||||
|
CSV.generate(**kwargs) do |csv|
|
||||||
|
csv << row
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Loading…
x
Reference in New Issue
Block a user