2018-12-23 02:00:35 -05:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
|
|
|
class CSV
|
2019-10-12 01:03:21 -04:00
|
|
|
# Note: Don't use this class directly. This is an internal class.
|
2018-12-23 02:00:35 -05:00
|
|
|
class FieldsConverter
|
|
|
|
include Enumerable
|
2019-10-12 01:03:21 -04:00
|
|
|
#
|
|
|
|
# A CSV::FieldsConverter is a data structure for storing the
|
|
|
|
# fields converter properties to be passed as a parameter
|
|
|
|
# when parsing a new file (e.g. CSV::Parser.new(@io, parser_options))
|
|
|
|
#
|
2018-12-23 02:00:35 -05:00
|
|
|
|
|
|
|
def initialize(options={})
|
|
|
|
@converters = []
|
|
|
|
@nil_value = options[:nil_value]
|
|
|
|
@empty_value = options[:empty_value]
|
|
|
|
@empty_value_is_empty_string = (@empty_value == "")
|
|
|
|
@accept_nil = options[:accept_nil]
|
2021-09-15 02:58:57 -04:00
|
|
|
@builtin_converters_name = options[:builtin_converters_name]
|
2018-12-23 02:00:35 -05:00
|
|
|
@need_static_convert = need_static_convert?
|
|
|
|
end
|
|
|
|
|
|
|
|
def add_converter(name=nil, &converter)
|
|
|
|
if name.nil? # custom converter
|
|
|
|
@converters << converter
|
|
|
|
else # named converter
|
2021-09-15 02:58:57 -04:00
|
|
|
combo = builtin_converters[name]
|
2018-12-23 02:00:35 -05:00
|
|
|
case combo
|
|
|
|
when Array # combo converter
|
|
|
|
combo.each do |sub_name|
|
|
|
|
add_converter(sub_name)
|
|
|
|
end
|
|
|
|
else # individual named converter
|
|
|
|
@converters << combo
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def each(&block)
|
|
|
|
@converters.each(&block)
|
|
|
|
end
|
|
|
|
|
|
|
|
def empty?
|
|
|
|
@converters.empty?
|
|
|
|
end
|
|
|
|
|
|
|
|
def convert(fields, headers, lineno)
|
|
|
|
return fields unless need_convert?
|
|
|
|
|
|
|
|
fields.collect.with_index do |field, index|
|
|
|
|
if field.nil?
|
|
|
|
field = @nil_value
|
2020-05-16 22:51:06 -04:00
|
|
|
elsif field.is_a?(String) and field.empty?
|
2018-12-23 02:00:35 -05:00
|
|
|
field = @empty_value unless @empty_value_is_empty_string
|
|
|
|
end
|
|
|
|
@converters.each do |converter|
|
|
|
|
break if field.nil? and @accept_nil
|
|
|
|
if converter.arity == 1 # straight field converter
|
|
|
|
field = converter[field]
|
|
|
|
else # FieldInfo converter
|
|
|
|
if headers
|
|
|
|
header = headers[index]
|
|
|
|
else
|
|
|
|
header = nil
|
|
|
|
end
|
|
|
|
field = converter[field, FieldInfo.new(index, lineno, header)]
|
|
|
|
end
|
|
|
|
break unless field.is_a?(String) # short-circuit pipeline for speed
|
|
|
|
end
|
|
|
|
field # final state of each field, converted or original
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
private
|
|
|
|
def need_static_convert?
|
|
|
|
not (@nil_value.nil? and @empty_value_is_empty_string)
|
|
|
|
end
|
|
|
|
|
|
|
|
def need_convert?
|
|
|
|
@need_static_convert or
|
|
|
|
(not @converters.empty?)
|
|
|
|
end
|
2021-09-15 02:58:57 -04:00
|
|
|
|
|
|
|
def builtin_converters
|
|
|
|
@builtin_converters ||= ::CSV.const_get(@builtin_converters_name)
|
|
|
|
end
|
2018-12-23 02:00:35 -05:00
|
|
|
end
|
|
|
|
end
|