Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Custom Ruby CSV converters for multiple fields

I am importing a CSV file that contains fields that need to be converted as follows:

  • "True" (string) -> true (boolean)
  • "False" (string) -> false (boolean)
  • "%m/%d/%Y" (string format) -> Date object
  • "%m/%d/%Y %I:%M:%S %p" (string format) -> DateTime object

The default CSV converters don't match the Date and DateTime fields. This method below seems to work, but wonder if there is a better way, possibly by override the matching pattern used by the converters?

 require 'csv'
 require 'date'

 src = <<csv
 active,date_created,date_modified
 "True","03/12/2012","03/12/2012 2:14:23 PM"
 "False","01/25/2011","03/12/2013 3:14:27 AM"
 csv

 CSV::Converters[:my_converters] = lambda{|field| 
   begin 
     case field.to_s
       when "True"
         true
       when "False"
         false
       when /^\d{2}\/\d{2}\/\d{4}$/
         Date.strptime(field,"%m/%d/%Y")
       else
         DateTime.strptime(field,"%m/%d/%Y %I:%M:%S %p")
       end
   rescue ArgumentError
     field
   end
 }

 csv = CSV(src, :headers => true, :converters => [:my_converters])
 csv.each{|row| puts row}

true,2012-03-12,2012-03-12T14:14:23+00:00

false,2011-01-25,2013-03-12T03:14:27+00:00

like image 311
regulus Avatar asked Oct 09 '13 05:10

regulus


People also ask

What does CSV parse Do Ruby?

The parser works in the Encoding of the IO or String object being read from or written to. Your data is never transcoded (unless you ask Ruby to transcode it for you) and will literally be parsed in the Encoding it is in. Thus CSV will return Arrays or Rows of Strings in the Encoding of your data.

What does CSV parse do?

The csv-parse package is a parser converting CSV text input into arrays or objects. It is part of the CSV project. It implements the Node. js stream.

What is csv file in Ruby on Rails?

CSV stands for “Comma-Separated Values”. It's a common data format which consist of rows with values separated by commas. It's used for exporting & importing data. For example: You can export your Gmail contacts as a CSV file, and you can also import them using the same format.


1 Answers

Convert fields accordingly field's name (header's name)

custom_converter = lambda { |value, field_info|
  case field_info.header
  when 'OrderUuid', 'Exchange', 'Type', 'OrderType'
    value.to_s
  when 'Quantity', 'Limit', 'CommissionPaid', 'Price'
    value.to_f
  when 'Opened', 'Closed'
    Time.zone.parse(value)
  else
    fail("Unknown field name #{field_info.inspect}=#{value}")
  end
}

CSV.parse(content, headers: :first_row, converters: [custom_converter]).map(&:to_h)
like image 128
a0s Avatar answered Nov 08 '22 10:11

a0s