The accepted answer really does not answer the question, so I thought that I was giving a useful example.
First of all, if you look at the docs at http://ruby-doc.org/stdlib-1.9.3/libdoc/csv/rdoc/CSV.html , if you hover the method name for dump
, you will see that you can click to show source
. If you do this, you will see that the dump
method tries to call csv_headers
on the first object that you pass from ary_of_objs
:
obj_template = ary_of_objs.first ...snip... headers = obj_template.csv_headers
Then you will see that the method will call csv_dump
for each object in ary_of_objs
and pass it to headers
:
ary_of_objs.each do |obj| begin csv << obj.csv_dump(headers) rescue NoMethodError csv << headers.map do |var| if var[0] == @ obj.instance_variable_get(var) else obj[var[0..-2]] end end end end
Therefore, we need to increase each entry in array_of_objs
in order to answer these two methods. Here is an example of a wrapper class that will accept Hash
and return the hash keys as CSV headers, and then be able to flush each line based on the headers.
class CsvRowDump def initialize(row_hash) @row = row_hash end def csv_headers @row.keys end def csv_dump(headers) headers.map { |h| @row[h] } end end
Thereβs another catch. This dump
method wants to write an extra line at the top of the CSV file before the headers, and there is no way to skip this if you call this method because of this code at the top:
# write meta information begin csv << obj_template.class.csv_meta rescue NoMethodError csv << [:class, obj_template.class] end
Even if you return '' from CsvRowDump.csv_meta
, which will still be the empty string where the parsing awaits the headers. So instead, let dump
write this line and then delete it after calling dump
. This example assumes that you have an array of hashes, all of which have the same keys (which will be the CSV header).
@rows = @hashes.map { |h| CsvRowDump.new(h) } File.open(@filename, "wb") do |f| str = CSV::dump(@rows) f.write(str.split(/\n/)[1..-1].join("\n")) end