diff options
author | kou <kou@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2019-04-14 21:01:51 +0000 |
---|---|---|
committer | kou <kou@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2019-04-14 21:01:51 +0000 |
commit | e3b6c7c7ebca1b051dbaa6f33494e92f5638fcc9 (patch) | |
tree | f98e60ecbeb320a9e9d8bdacfa3f9231cd55ddda /lib/csv.rb | |
parent | fb96811d15f83c6b692e8e00d458eef32032af6a (diff) | |
download | ruby-e3b6c7c7ebca1b051dbaa6f33494e92f5638fcc9.tar.gz |
Import CSV 3.0.8
This includes performance improvements and backward incompatibility
fixes.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@67560 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'lib/csv.rb')
-rw-r--r-- | lib/csv.rb | 129 |
1 files changed, 101 insertions, 28 deletions
diff --git a/lib/csv.rb b/lib/csv.rb index 1a173c6d68..1239554ad6 100644 --- a/lib/csv.rb +++ b/lib/csv.rb @@ -504,9 +504,9 @@ class CSV # <tt>encoding: "UTF-32BE:UTF-8"</tt> would read UTF-32BE data from the file # but transcode it to UTF-8 before CSV parses it. # - def self.foreach(path, **options, &block) - return to_enum(__method__, path, options) unless block_given? - open(path, options) do |csv| + def self.foreach(path, mode="r", **options, &block) + return to_enum(__method__, path, mode, options) unless block_given? + open(path, mode, options) do |csv| csv.each(&block) end end @@ -885,6 +885,10 @@ class CSV # blank string field is replaced by # the set object. # <b><tt>:quote_empty</tt></b>:: TODO + # <b><tt>:write_converters</tt></b>:: TODO + # <b><tt>:write_nil_value</tt></b>:: TODO + # <b><tt>:write_empty_value</tt></b>:: TODO + # <b><tt>:strip</tt></b>:: TODO # # See CSV::DEFAULT_OPTIONS for the default settings. # @@ -911,7 +915,11 @@ class CSV encoding: nil, nil_value: nil, empty_value: "", - quote_empty: true) + quote_empty: true, + write_converters: nil, + write_nil_value: nil, + write_empty_value: "", + strip: false) raise ArgumentError.new("Cannot parse nil as CSV") if data.nil? # create the IO object we will read from @@ -922,8 +930,13 @@ class CSV nil_value: nil_value, empty_value: empty_value, } + @write_fields_converter_options = { + nil_value: write_nil_value, + empty_value: write_empty_value, + } @initial_converters = converters @initial_header_converters = header_converters + @initial_write_converters = write_converters @parser_options = { column_separator: col_sep, @@ -939,6 +952,7 @@ class CSV encoding: @encoding, nil_value: nil_value, empty_value: empty_value, + strip: strip, } @parser = nil @@ -998,7 +1012,7 @@ class CSV # as is. # def converters - fields_converter.map do |converter| + parser_fields_converter.map do |converter| name = Converters.rassoc(converter) name ? name.first : converter end @@ -1098,12 +1112,58 @@ class CSV ### IO and StringIO Delegation ### extend Forwardable - def_delegators :@io, :binmode, :binmode?, :close, :close_read, :close_write, - :closed?, :eof, :eof?, :external_encoding, :fcntl, - :fileno, :flock, :flush, :fsync, :internal_encoding, - :ioctl, :isatty, :path, :pid, :pos, :pos=, :reopen, - :seek, :stat, :string, :sync, :sync=, :tell, :to_i, - :to_io, :truncate, :tty? + def_delegators :@io, :binmode, :close, :close_read, :close_write, + :closed?, :external_encoding, :fcntl, + :fileno, :flush, :fsync, :internal_encoding, + :isatty, :pid, :pos, :pos=, :reopen, + :seek, :string, :sync, :sync=, :tell, + :truncate, :tty? + + def binmode? + if @io.respond_to?(:binmode?) + @io.binmode? + else + false + end + end + + def flock(*args) + raise NotImplementedError unless @io.respond_to?(:flock) + @io.flock(*args) + end + + def ioctl(*args) + raise NotImplementedError unless @io.respond_to?(:ioctl) + @io.ioctl(*args) + end + + def path + @io.path if @io.respond_to?(:path) + end + + def stat(*args) + raise NotImplementedError unless @io.respond_to?(:stat) + @io.stat(*args) + end + + def to_i + raise NotImplementedError unless @io.respond_to?(:to_i) + @io.to_i + end + + def to_io + @io.respond_to?(:to_io) ? @io.to_io : @io + end + + def eof? + begin + parser_enumerator.peek + false + rescue StopIteration + true + end + end + alias_method :eof, :eof? # Rewinds the underlying IO object and resets CSV's lineno() counter. def rewind @@ -1145,7 +1205,7 @@ class CSV # converted field or the field itself. # def convert(name = nil, &converter) - fields_converter.add_converter(name, &converter) + parser_fields_converter.add_converter(name, &converter) end # @@ -1173,7 +1233,7 @@ class CSV # The data source must be open for reading. # def each(&block) - parser.parse(&block) + parser_enumerator.each(&block) end # @@ -1204,9 +1264,8 @@ class CSV # The data source must be open for reading. # def shift - @parser_enumerator ||= parser.parse begin - @parser_enumerator.next + parser_enumerator.next rescue StopIteration nil end @@ -1299,7 +1358,7 @@ class CSV if headers header_fields_converter.convert(fields, nil, 0) else - fields_converter.convert(fields, @headers, lineno) + parser_fields_converter.convert(fields, @headers, lineno) end end @@ -1316,20 +1375,16 @@ class CSV end end - def fields_converter - @fields_converter ||= build_fields_converter + def parser_fields_converter + @parser_fields_converter ||= build_parser_fields_converter end - def build_fields_converter + def build_parser_fields_converter specific_options = { builtin_converters: Converters, } options = @base_fields_converter_options.merge(specific_options) - fields_converter = FieldsConverter.new(options) - normalize_converters(@initial_converters).each do |name, converter| - fields_converter.add_converter(name, &converter) - end - fields_converter + build_fields_converter(@initial_converters, options) end def header_fields_converter @@ -1342,8 +1397,21 @@ class CSV accept_nil: true, } options = @base_fields_converter_options.merge(specific_options) + build_fields_converter(@initial_header_converters, options) + end + + def writer_fields_converter + @writer_fields_converter ||= build_writer_fields_converter + end + + def build_writer_fields_converter + build_fields_converter(@initial_write_converters, + @write_fields_converter_options) + end + + def build_fields_converter(initial_converters, options) fields_converter = FieldsConverter.new(options) - normalize_converters(@initial_header_converters).each do |name, converter| + normalize_converters(initial_converters).each do |name, converter| fields_converter.add_converter(name, &converter) end fields_converter @@ -1354,8 +1422,12 @@ class CSV end def parser_options - @parser_options.merge(fields_converter: fields_converter, - header_fields_converter: header_fields_converter) + @parser_options.merge(header_fields_converter: header_fields_converter, + fields_converter: parser_fields_converter) + end + + def parser_enumerator + @parser_enumerator ||= parser.parse end def writer @@ -1363,7 +1435,8 @@ class CSV end def writer_options - @writer_options.merge(header_fields_converter: header_fields_converter) + @writer_options.merge(header_fields_converter: header_fields_converter, + fields_converter: writer_fields_converter) end end |