Merge csv-3.0.0 from ruby/csv repository.

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@64638 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
hsbt 2018-09-05 13:33:21 +00:00
Родитель 21ce539f20
Коммит 60ebd4e26a
11 изменённых файлов: 148 добавлений и 106 удалений

Просмотреть файл

@ -141,7 +141,7 @@ end
# There are several specialized class methods for one-statement reading or writing,
# described in the Specialized Methods section.
#
# If a String passed into ::new, it is internally wrapped into a StringIO object.
# If a String is passed into ::new, it is internally wrapped into a StringIO object.
#
# +options+ can be used for specifying the particular CSV flavor (column
# separators, row separators, value quoting and so on), and for data conversion,
@ -890,8 +890,12 @@ class CSV
# attempt to parse input not conformant
# with RFC 4180, such as double quotes
# in unquoted fields.
# <b><tt>:nil_value</tt></b>:: TODO: WRITE ME.
# <b><tt>:empty_value</tt></b>:: TODO: WRITE ME.
# <b><tt>:nil_value</tt></b>:: When set an object, any values of an
# empty field are replaced by the set
# object, not nil.
# <b><tt>:empty_value</tt></b>:: When set an object, any values of a
# blank string field is replaced by
# the set object.
#
# See CSV::DEFAULT_OPTIONS for the default settings.
#
@ -1232,7 +1236,7 @@ class CSV
elsif @unconverted_fields
return add_unconverted_fields(Array.new, Array.new)
elsif @use_headers
return self.class::Row.new(Array.new, Array.new)
return self.class::Row.new(@headers, Array.new)
else
return Array.new
end

Просмотреть файл

@ -1,6 +1,10 @@
# frozen_string_literal: true
begin
require_relative "lib/csv/version"
rescue LoadError
require_relative "version"
end
Gem::Specification.new do |spec|
spec.name = "csv"
@ -13,7 +17,8 @@ Gem::Specification.new do |spec|
spec.homepage = "https://github.com/ruby/csv"
spec.license = "BSD-2-Clause"
spec.files = ["lib/csv.rb", "lib/csv/table.rb", "lib/csv/core_ext/string.rb", "lib/csv/core_ext/array.rb", "lib/csv/row.rb", "lib/csv/version.rb", "README.md", "LICENSE.txt", "news.md"]
spec.files = Dir.glob("lib/**/*.rb")
spec.files += ["README.md", "LICENSE.txt", "news.md"]
spec.require_paths = ["lib"]
spec.required_ruby_version = ">= 2.3.0"

Просмотреть файл

@ -48,6 +48,11 @@ class CSV
extend Forwardable
def_delegators :@row, :empty?, :length, :size
def initialize_copy(other)
super
@row = @row.dup
end
# Returns +true+ if this is a header row.
def header_row?
@header_row

Просмотреть файл

@ -2,5 +2,5 @@
class CSV
# The version of the installed library.
VERSION = "1.0.2"
VERSION = "3.0.1"
end

Просмотреть файл

@ -148,13 +148,13 @@ class TestCSV::Parsing < TestCSV
CSV.parse_line("1,2\r,3", row_sep: "\n")
end
bad_data = <<-END_DATA.gsub(/^ +/, "")
bad_data = <<-CSV
line,1,abc
line,2,"def\nghi"
line,4,some\rjunk
line,5,jkl
END_DATA
CSV
lines = bad_data.lines.to_a
assert_equal(6, lines.size)
assert_match(/\Aline,4/, lines.find { |l| l =~ /some\rjunk/ })
@ -172,13 +172,13 @@ class TestCSV::Parsing < TestCSV
assert_raise(CSV::MalformedCSVError) { CSV.parse_line('1,2,"3...') }
bad_data = <<-END_DATA.gsub(/^ +/, "")
bad_data = <<-CSV
line,1,abc
line,2,"def\nghi"
line,4,8'10"
line,5,jkl
END_DATA
CSV
lines = bad_data.lines.to_a
assert_equal(6, lines.size)
assert_match(/\Aline,4/, lines.find { |l| l =~ /8'10"/ })

Просмотреть файл

@ -260,10 +260,10 @@ class TestCSV::DataConverters < TestCSV
assert_equal(unconverted, row.unconverted_fields)
end
data = <<-END_CSV.gsub(/^\s+/, "")
data = <<-CSV
first,second,third
1,2,3
END_CSV
CSV
row = nil
assert_nothing_raised(Exception) do
row = CSV.parse_line( data,

Просмотреть файл

@ -37,12 +37,12 @@ class TestCSV::Features < TestCSV
def setup
super
@sample_data = <<-END_DATA.gsub(/^ +/, "")
@sample_data = <<-CSV
line,1,abc
line,2,"def\nghi"
line,4,jkl
END_DATA
CSV
@csv = CSV.new(@sample_data)
end
@ -225,12 +225,12 @@ class TestCSV::Features < TestCSV
end
# reported by Kev Jackson
def test_failing_to_escape_col_sep_bug_fix
def test_failing_to_escape_col_sep
assert_nothing_raised(Exception) { CSV.new(String.new, col_sep: "|") }
end
# reported by Chris Roos
def test_failing_to_reset_headers_in_rewind_bug_fix
def test_failing_to_reset_headers_in_rewind
csv = CSV.new("forename,surname", headers: true, return_headers: true)
csv.each {|row| assert_predicate row, :header_row?}
csv.rewind
@ -238,16 +238,16 @@ class TestCSV::Features < TestCSV
end
# reported by Dave Burt
def test_leading_empty_fields_with_multibyte_col_sep_bug_fix
data = <<-END_DATA.gsub(/^\s+/, "")
def test_leading_empty_fields_with_multibyte_col_sep
data = <<-CSV
<=><=>A<=>B<=>C
1<=>2<=>3
END_DATA
CSV
parsed = CSV.parse(data, col_sep: "<=>")
assert_equal([[nil, nil, "A", "B", "C"], ["1", "2", "3"]], parsed)
end
def test_gzip_reader_bug_fix
def test_gzip_reader
zipped = nil
assert_nothing_raised(NoMethodError) do
zipped = CSV.new(
@ -261,7 +261,7 @@ class TestCSV::Features < TestCSV
zipped.close
end if defined?(Zlib::GzipReader)
def test_gzip_writer_bug_fix
def test_gzip_writer
Tempfile.create(%w"temp .gz") {|tempfile|
tempfile.close
file = tempfile.path

Просмотреть файл

@ -13,11 +13,11 @@ class TestCSV::Headers < TestCSV
def setup
super
@data = <<-END_CSV.gsub(/^\s+/, "")
@data = <<-CSV
first,second,third
A,B,C
1,2,3
END_CSV
CSV
end
def test_first_row
@ -183,10 +183,10 @@ class TestCSV::Headers < TestCSV
def test_converters
# create test data where headers and fields look alike
data = <<-END_MATCHING_CSV.gsub(/^\s+/, "")
data = <<-CSV
1,2,3
1,2,3
END_MATCHING_CSV
CSV
# normal converters do not affect headers
csv = CSV.parse( data, headers: true,
@ -256,7 +256,7 @@ class TestCSV::Headers < TestCSV
end
def test_skip_blanks
@data = <<-END_CSV.gsub(/^ +/, "")
@data = <<-CSV
A,B,C
@ -265,7 +265,7 @@ class TestCSV::Headers < TestCSV
END_CSV
CSV
expected = [%w[1 2 3]]
CSV.parse(@data, headers: true, skip_blanks: true) do |row|
@ -292,7 +292,7 @@ class TestCSV::Headers < TestCSV
assert_equal(%w[first second third], csv.headers) # after headers are read
end
def test_blank_row_bug_fix
def test_blank_row
@data += "\n#{@data}" # add a blank row
# ensure that everything returned is a Row object
@ -300,4 +300,19 @@ class TestCSV::Headers < TestCSV
assert_instance_of(CSV::Row, row)
end
end
def test_nil_row_header
@data = <<-CSV
A
1
CSV
csv = CSV.parse(@data, headers: true)
# ensure nil row creates Row object with headers
row = csv[0]
assert_equal([["A"], [nil]],
[row.headers, row.fields])
end
end

Просмотреть файл

@ -419,4 +419,12 @@ class TestCSV::Row < TestCSV
row.dig("A", 0)
end
end
def test_dup
row = CSV::Row.new(["A"], ["foo"])
dupped_row = row.dup
dupped_row.delete("A")
assert_equal(["foo", nil],
[row["A"], dupped_row["A"]])
end
end

Просмотреть файл

@ -42,6 +42,11 @@ class TestCSV::Table < TestCSV
assert_equal(:row, rows.mode)
assert_equal(@table, rows)
col_or_row = rows.by_col_or_row
assert_equal(:row, rows.mode)
assert_equal(:col_or_row, col_or_row.mode)
assert_equal(@table, col_or_row)
# destructive mode changing calls
assert_equal(@table, @table.by_row!)
assert_equal(:row, @table.mode)
@ -148,13 +153,13 @@ class TestCSV::Table < TestCSV
@table.to_a )
# verify resulting table
assert_equal(<<-END_RESULT.gsub(/^\s+/, ""), @table.to_csv)
assert_equal(<<-CSV, @table.to_csv)
A,B,C,Type,Index
1,100,3,data,1
4,200,6,data,2
10,,12,data,3
13,,15,data,
END_RESULT
CSV
# with headers
@header_table["Type"] = "data"
@ -286,12 +291,12 @@ class TestCSV::Table < TestCSV
end
def test_to_csv
csv = <<-END_CSV.gsub(/^\s+/, "")
csv = <<-CSV
A,B,C
1,2,3
4,5,6
7,8,9
END_CSV
CSV
# normal conversion
assert_equal(csv, @table.to_csv)
@ -330,11 +335,11 @@ class TestCSV::Table < TestCSV
assert_equal(@rows.map { |row| row["A"] }, @table.delete("A"))
# verify resulting table
assert_equal(<<-END_RESULT.gsub(/^\s+/, ""), @table.to_csv)
assert_equal(<<-CSV, @table.to_csv)
B,C
2,3
8,9
END_RESULT
CSV
end
def test_delete_mixed_multiple
@ -352,11 +357,11 @@ class TestCSV::Table < TestCSV
@table.delete(1, "A"))
# verify resulting table
assert_equal(<<-END_RESULT.gsub(/^\s+/, ""), @table.to_csv)
assert_equal(<<-CSV, @table.to_csv)
B,C
2,3
8,9
END_RESULT
CSV
end
def test_delete_column
@ -369,12 +374,12 @@ class TestCSV::Table < TestCSV
assert_equal(@rows.map { |row| row["C"] }, @table.delete("C"))
# verify resulting table
assert_equal(<<-END_RESULT.gsub(/^\s+/, ""), @table.to_csv)
assert_equal(<<-CSV, @table.to_csv)
B
2
5
8
END_RESULT
CSV
end
def test_delete_row
@ -387,11 +392,11 @@ class TestCSV::Table < TestCSV
assert_raise(TypeError) { @table.delete("C") }
# verify resulting table
assert_equal(<<-END_RESULT.gsub(/^\s+/, ""), @table.to_csv)
assert_equal(<<-CSV, @table.to_csv)
A,B,C
1,2,3
7,8,9
END_RESULT
CSV
end
def test_delete_with_blank_rows
@ -408,10 +413,10 @@ class TestCSV::Table < TestCSV
assert_equal(@table, @table.delete_if { |row| (row["B"] % 2).zero? })
# verify resulting table
assert_equal(<<-END_RESULT.gsub(/^\s+/, ""), @table.to_csv)
assert_equal(<<-CSV, @table.to_csv)
A,B,C
4,5,6
END_RESULT
CSV
end
def test_delete_if_row_without_block
@ -426,10 +431,10 @@ class TestCSV::Table < TestCSV
assert_equal(@table, enum.each { |row| (row["B"] % 2).zero? })
# verify resulting table
assert_equal(<<-END_RESULT.gsub(/^\s+/, ""), @table.to_csv)
assert_equal(<<-CSV, @table.to_csv)
A,B,C
4,5,6
END_RESULT
CSV
end
def test_delete_if_column
@ -439,12 +444,12 @@ class TestCSV::Table < TestCSV
@table.by_col!
assert_equal(@table, @table.delete_if { |h, v| h > "A" })
assert_equal(<<-END_RESULT.gsub(/^\s+/, ""), @table.to_csv)
assert_equal(<<-CSV, @table.to_csv)
A
1
4
7
END_RESULT
CSV
end
def test_delete_if_column_without_block
@ -458,12 +463,12 @@ class TestCSV::Table < TestCSV
assert_equal(@table.headers.size, enum.size)
assert_equal(@table, enum.each { |h, v| h > "A" })
assert_equal(<<-END_RESULT.gsub(/^\s+/, ""), @table.to_csv)
assert_equal(<<-CSV, @table.to_csv)
A
1
4
7
END_RESULT
CSV
end
def test_values_at