lib/smarter_csv.rb in smarter_csv-1.8.5 vs lib/smarter_csv.rb in smarter_csv-1.9.0

- old
+ new

@@ -10,16 +10,16 @@ class SmarterCSVException < StandardError; end class HeaderSizeMismatch < SmarterCSVException; end class IncorrectOption < SmarterCSVException; end class ValidationError < SmarterCSVException; end class DuplicateHeaders < SmarterCSVException; end - class MissingHeaders < SmarterCSVException; end + class MissingKeys < SmarterCSVException; end # previously known as MissingHeaders class NoColSepDetected < SmarterCSVException; end - class KeyMappingError < SmarterCSVException; end # CURRENTLY UNUSED -> version 1.9.0 + class KeyMappingError < SmarterCSVException; end # first parameter: filename or input object which responds to readline method - def SmarterCSV.process(input, options = {}, &block) + def SmarterCSV.process(input, options = {}, &block) # rubocop:disable Lint/UnusedMethodArgument options = default_options.merge(options) options[:invalid_byte_sequence] = '' if options[:invalid_byte_sequence].nil? puts "SmarterCSV OPTIONS: #{options.inspect}" if options[:verbose] validate_options!(options) @@ -97,11 +97,11 @@ if options[:remove_empty_values] == true hash.delete_if{|_k, v| has_rails ? v.blank? : blank?(v)} end - hash.delete_if{|_k, v| !v.nil? && v =~ /^(\d+|\d+\.\d+)$/ && v.to_f == 0} if options[:remove_zero_values] # values are typically Strings! + hash.delete_if{|_k, v| !v.nil? && v =~ /^(0+|0+\.0+)$/} if options[:remove_zero_values] # values are Strings hash.delete_if{|_k, v| v =~ options[:remove_values_matching]} if options[:remove_values_matching] if options[:convert_values_to_numeric] hash.each do |k, v| # deal with the :only / :except options to :convert_values_to_numeric @@ -169,19 +169,19 @@ yield chunk # do something with the hashes in the chunk in the block else result << chunk # not sure yet, why anybody would want to do this without a block end chunk_count += 1 - chunk = [] # initialize for next chunk of data + # chunk = [] # initialize for next chunk of data end ensure fh.close if fh.respond_to?(:close) end if block_given? - return chunk_count # when we do processing through a block we only care how many chunks we processed + chunk_count # when we do processing through a block we only care how many chunks we processed else - return result # returns either an Array of Hashes, or an Array of Arrays of Hashes (if in chunked mode) + result # returns either an Array of Hashes, or an Array of Arrays of Hashes (if in chunked mode) end end class << self def has_acceleration? @@ -283,15 +283,15 @@ if options[:acceleration] && has_acceleration? # :nocov: has_quotes = line =~ /#{options[:quote_char]}/ elements = parse_csv_line_c(line, options[:col_sep], options[:quote_char], header_size) elements.map!{|x| cleanup_quotes(x, options[:quote_char])} if has_quotes - return [elements, elements.size] + [elements, elements.size] # :nocov: else # puts "WARNING: SmarterCSV is using un-accelerated parsing of lines. Check options[:acceleration]" - return parse_csv_line_ruby(line, options, header_size) + parse_csv_line_ruby(line, options, header_size) end end # ------------------------------------------------------------------ # Ruby equivalent of the C-extension for parse_line @@ -400,11 +400,11 @@ return true if Array(options[option_name][:except]).include?(key) elsif options[option_name].has_key?(:only) return true unless Array(options[option_name][:only]).include?(key) end end - return false + false end # If file has headers, then guesses column separator from headers. # Otherwise guesses column separator from contents. # Raises exception if none is found. @@ -465,12 +465,12 @@ end rewind(filehandle) counts["\r"] += 1 if last_char == "\r" # find the most frequent key/value pair: - k, _ = counts.max_by{|_, v| v} - return k + most_frequent_key, _count = counts.max_by{|_, v| v} + most_frequent_key end def process_headers(filehandle, options) @raw_header = nil @headers = nil @@ -488,10 +488,11 @@ file_headerA, file_header_size = parse(header, options) file_headerA.map!{|x| x.gsub(%r/#{options[:quote_char]}/, '')} file_headerA.map!{|x| x.strip} if options[:strip_whitespace] + unless options[:keep_original_headers] file_headerA.map!{|x| x.gsub(/\s+|-+/, '_')} file_headerA.map!{|x| x.downcase} if options[:downcase_header] end else @@ -521,14 +522,17 @@ key_mappingH = options[:key_mapping] # do some key mapping on the keys in the file header # if you want to completely delete a key, then map it to nil or to '' if !key_mappingH.nil? && key_mappingH.class == Hash && key_mappingH.keys.size > 0 - unless options[:silence_missing_keys] - # if silence_missing_keys are not set, raise error if missing header - missing_keys = key_mappingH.keys - headerA - puts "WARNING: missing header(s): #{missing_keys.join(",")}" unless missing_keys.empty? + # if silence_missing_keys are not set, raise error if missing header + missing_keys = key_mappingH.keys - headerA + # if the user passes a list of speciffic mapped keys that are optional + missing_keys -= options[:silence_missing_keys] if options[:silence_missing_keys].is_a?(Array) + + unless missing_keys.empty? || options[:silence_missing_keys] == true + raise SmarterCSV::KeyMappingError, "ERROR: can not map headers: #{missing_keys.join(', ')}" end headerA.map!{|x| key_mappingH.has_key?(x) ? (key_mappingH[x].nil? ? nil : key_mappingH[x]) : (options[:remove_unmapped_keys] ? nil : x)} end end @@ -542,12 +546,12 @@ unless options[:user_provided_headers] || duplicate_headers.empty? raise SmarterCSV::DuplicateHeaders, "ERROR: duplicate headers: #{duplicate_headers.join(',')}" end # deprecate required_headers - if !options[:required_headers].nil? - puts "DEPRECATION WARNING: please use 'required_keys' instead of 'required headers'" + unless options[:required_headers].nil? + puts "DEPRECATION WARNING: please use 'required_keys' instead of 'required_headers'" if options[:required_keys].nil? options[:required_keys] = options[:required_headers] options[:required_headers] = nil end end @@ -555,11 +559,11 @@ if options[:required_keys] && options[:required_keys].is_a?(Array) missing_keys = [] options[:required_keys].each do |k| missing_keys << k unless headerA.include?(k) end - raise SmarterCSV::MissingHeaders, "ERROR: missing attributes: #{missing_keys.join(',')}" unless missing_keys.empty? + raise SmarterCSV::MissingKeys, "ERROR: missing attributes: #{missing_keys.join(',')}" unless missing_keys.empty? end @headers = headerA [headerA, header_size] end @@ -609,9 +613,10 @@ end def option_valid?(str) return true if str.is_a?(Symbol) && str == :auto return true if str.is_a?(String) && !str.empty? + false end end end