Read more

Ruby: Reading and writing CSVs

Emanuel
December 06, 2018Software engineer at makandra GmbH

In ruby you can easily read and write CSVs with the standard CSV library Show archive.org snapshot class.

Illustration online protection

Rails Long Term Support

Rails LTS provides security patches for old versions of Ruby on Rails (2.3, 3.2, 4.2 and 5.2)

  • Prevents you from data breaches and liability risks
  • Upgrade at your own pace
  • Works with modern Rubies
Read more Show archive.org snapshot

On top of this, you can use the gem smarter_csv Show archive.org snapshot for reading (not writing) CSVs in a more comfortable way:

  • Keep in mind, that the development of this gem is in an unknown state and the 2.0 release seems to happen never
  • The API will change completely for 2.0, so you might find a bunch of unrelated documentation for 1.2

Here is an example, what smarter_csv does for you:

Input:

first name,last name,dogs,cats,birds,fish
Dan,McAllister,2,,,
Lucy,Laweless,,5,,
Miles,O'Brian,,,,21
Nancy,Homes,2,,1,

Output:

[
  {first_name: 'Dan', last_name: 'McAllister', dogs: '2'},
  {first_name: 'Lucy', last_name: 'Laweless', cats: '5'},
  {first_name: 'Miles', last_name: "O'Brian", fish: '21'},
  {first_name: 'Nancy', last_name: 'Homes', dogs: '2', birds: '1'}
]

You might want to keep empty lines, use string keys or change the encoding. This is all possible, look up for the proper options Show archive.org snapshot .

RSpec

We used this helper in some project to do not have to write comma separated values, but use data objects instead.

Place this file in spec/supper/csv_helper.rb.

module CsvHelpers
  def generate_csv(csv_data)
    csv_string = CSV.generate do |csv|
      csv << csv_data.first.keys
      csv_data.inject(csv) { |acc, row| acc << row.values }
    end

    file = Tempfile.new
    file.write(csv_string)
    file.rewind
    file
  end

  def generate_empty_csv
    file = Tempfile.new
    file.write(' ')
    file.rewind
    file
  end
end

RSpec.configure do |c|
  c.include CsvHelpers
end

The you can generate a csv file like this:

let(:csv_data) do
  [
    {
      'first_name' => 'Dan',
      'last_name' => 'McAllister',
      'dogs' => '2',
      'cats' => nil,
      'fish' => nil,
      'birds' => nil
    },
    {
      'first_name' => 'Lucy',
      'last_name' => 'Laweless',
      'dogs' => nil,
      'cats' => '5',
      'fish' => nil,
      'birds' => nil
    },
    {
      'first_name' => 'Miles',
      'last_name' => "O'Brian",
      'dogs' => nil,
      'cats' => nil,
      'fish' => '21',
      'birds' => nil
    },
    {
      'first_name' => 'Nancy',
      'last_name' => 'Homes',
      'dogs' => '2',
      'cats' => nil,
      'fish' => nil,
      'birds' => '1'
    }
  ]
end

let(:csv) { generate_csv(csv_data) } # This will return a CSV with one header row and four data rows
Emanuel
December 06, 2018Software engineer at makandra GmbH
Posted by Emanuel to makandra dev (2018-12-06 14:16)