123456789_123456789_123456789_123456789_123456789_

Recipes for Generating CSV

For other recipes, see Recipes for CSV.

All code snippets on this page assume that the following has been executed:

require 'csv'

Contents

Output Formats

You can generate CSV output to a String, to a File (via its path), or to an IO stream.

Generating to a String

You can generate CSV output to a String, with or without headers.

Recipe: Generate to String with Headers

Use class method CSV.generate with option headers to generate to a String.

This example uses method CSV#<< to append the rows that are to be generated:

output_string = CSV.generate('', headers: ['Name', 'Value'], write_headers: true) do |csv|
  csv << ['Foo', 0]
  csv << ['Bar', 1]
  csv << ['Baz', 2]
end
output_string # => "Name,Value\nFoo,0\nBar,1\nBaz,2\n"
Recipe: Generate to String Without Headers

Use class method CSV.generate without option headers to generate to a String.

This example uses method CSV#<< to append the rows that are to be generated:

output_string = CSV.generate do |csv|
  csv << ['Foo', 0]
  csv << ['Bar', 1]
  csv << ['Baz', 2]
end
output_string # => "Foo,0\nBar,1\nBaz,2\n"

Generating to a File

You can generate /CSV data to a File, with or without headers.

Recipe: Generate to File with Headers

Use class method CSV.open with option headers generate to a File.

This example uses method CSV#<< to append the rows that are to be generated:

path = 't.csv'
CSV.open(path, 'w', headers: ['Name', 'Value'], write_headers: true) do |csv|
  csv << ['Foo', 0]
  csv << ['Bar', 1]
  csv << ['Baz', 2]
end
p File.read(path) # => "Name,Value\nFoo,0\nBar,1\nBaz,2\n"
Recipe: Generate to File Without Headers

Use class method CSV.open without option headers to generate to a File.

This example uses method CSV#<< to append the rows that are to be generated:

path = 't.csv'
CSV.open(path, 'w') do |csv|
  csv << ['Foo', 0]
  csv << ['Bar', 1]
  csv << ['Baz', 2]
end
p File.read(path) # => "Foo,0\nBar,1\nBaz,2\n"

Generating to an IO Stream

You can generate CSV data to an IO stream, with or without headers.

Recipe: Generate to IO Stream with Headers

Use class method CSV.new with option headers to generate CSV data to an IO stream:

path = 't.csv'
File.open(path, 'w') do |file|
  csv = CSV.new(file, headers: ['Name', 'Value'], write_headers: true)
  csv << ['Foo', 0]
  csv << ['Bar', 1]
  csv << ['Baz', 2]
end
p File.read(path) # => "Name,Value\nFoo,0\nBar,1\nBaz,2\n"
Recipe: Generate to IO Stream Without Headers

Use class method CSV.new without option headers to generate CSV data to an IO stream:

path = 't.csv'
File.open(path, 'w') do |file|
  csv = CSV.new(file)
  csv << ['Foo', 0]
  csv << ['Bar', 1]
  csv << ['Baz', 2]
end
p File.read(path) # => "Foo,0\nBar,1\nBaz,2\n"

Converting Fields

You can use write converters to convert fields when generating CSV.

Recipe: Filter Generated Field Strings

Use option :write_converters and a custom converter to convert field values when generating CSV.

This example defines and uses a custom write converter to strip whitespace from generated fields:

strip_converter = proc {|field| field.respond_to?(:strip) ? field.strip : field }
output_string = CSV.generate(write_converters: strip_converter) do |csv|
  csv << [' foo ', 0]
  csv << [' bar ', 1]
  csv << [' baz ', 2]
end
output_string # => "foo,0\nbar,1\nbaz,2\n"

Recipe: Specify Multiple Write Converters

Use option :write_converters and multiple custom coverters to convert field values when generating CSV.

This example defines and uses two custom write converters to strip and upcase generated fields:

strip_converter = proc {|field| field.respond_to?(:strip) ? field.strip : field }
upcase_converter = proc {|field| field.respond_to?(:upcase) ? field.upcase : field }
converters = [strip_converter, upcase_converter]
output_string = CSV.generate(write_converters: converters) do |csv|
  csv << [' foo ', 0]
  csv << [' bar ', 1]
  csv << [' baz ', 2]
end
output_string # => "FOO,0\nBAR,1\nBAZ,2\n"

RFC 4180 Compliance

By default, CSV generates data that is compliant with RFC 4180 with respect to:

Row Separator

RFC 4180 specifies the row separator CRLF (Ruby "\r\n").

Recipe: Generate Compliant Row Separator

For strict compliance, use option :row_sep to specify row separator "\r\n":

output_string = CSV.generate('', row_sep: "\r\n") do |csv|
  csv << ['Foo', 0]
  csv << ['Bar', 1]
  csv << ['Baz', 2]
end
output_string # => "Foo,0\r\nBar,1\r\nBaz,2\r\n"
Recipe: Generate Non-Compliant Row Separator

For data with non-compliant row separators, use option :row_sep with a different value: This example source uses semicolon (";') as its row separator:

output_string = CSV.generate('', row_sep: ";") do |csv|
  csv << ['Foo', 0]
  csv << ['Bar', 1]
  csv << ['Baz', 2]
end
output_string # => "Foo,0;Bar,1;Baz,2;"

Column Separator

RFC 4180 specifies column separator COMMA (Ruby ",").

Recipe: Generate Compliant Column Separator

Because the CSV default comma separator is ",", you need not specify option :col_sep for compliant data:

output_string = CSV.generate('') do |csv|
  csv << ['Foo', 0]
  csv << ['Bar', 1]
  csv << ['Baz', 2]
end
output_string # => "Foo,0\nBar,1\nBaz,2\n"
Recipe: Generate Non-Compliant Column Separator

For data with non-compliant column separators, use option :col_sep. This example source uses TAB ("\t") as its column separator:

output_string = CSV.generate('', col_sep: "\t") do |csv|
  csv << ['Foo', 0]
  csv << ['Bar', 1]
  csv << ['Baz', 2]
end
output_string # => "Foo\t0\nBar\t1\nBaz\t2\n"

Quote Character

RFC 4180 specifies quote character DQUOTE (Ruby "\"").

Recipe: Generate Compliant Quote Character

Because the CSV default quote character is "\"", you need not specify option :quote_char for compliant data:

output_string = CSV.generate('', force_quotes: true) do |csv|
  csv << ['Foo', 0]
  csv << ['Bar', 1]
  csv << ['Baz', 2]
end
output_string # => "\"Foo\",\"0\"\n\"Bar\",\"1\"\n\"Baz\",\"2\"\n"
Recipe: Generate Non-Compliant Quote Character

For data with non-compliant quote characters, use option :quote_char. This example source uses SQUOTE ("'") as its quote character:

output_string = CSV.generate('', quote_char: "'", force_quotes: true) do |csv|
  csv << ['Foo', 0]
  csv << ['Bar', 1]
  csv << ['Baz', 2]
end
output_string # => "'Foo','0'\n'Bar','1'\n'Baz','2'\n"