接受的答案并没有真正回答问题,所以我想我会举一个有用的例子。
首先,如果您查看http://ruby-doc.org/stdlib-1.9.3/libdoc/csv/rdoc/CSV.html 的文档,如果您将鼠标悬停在dump 的方法名称上,您会看到您可以click to show source。如果你这样做,你会看到dump 方法尝试在你从ary_of_objs 传入的第一个对象上调用csv_headers:
obj_template = ary_of_objs.first
...snip...
headers = obj_template.csv_headers
然后你会看到该方法会对ary_of_objs中的每个对象调用csv_dump并传入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
所以我们需要增加array_of_objs 中的每个条目来响应这两种方法。这是一个示例包装类,它将采用 Hash,并将哈希键作为 CSV 标头返回,然后能够根据标头转储每一行。
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
不过还有一个问题。 dump 方法想在 CSV 文件顶部的标题之前写一个额外的行,如果由于顶部的代码而调用此方法,则无法跳过:
# write meta information
begin
csv << obj_template.class.csv_meta
rescue NoMethodError
csv << [:class, obj_template.class]
end
即使你从CsvRowDump.csv_meta 返回 '' ,它仍然是一个空行,解析需要标题。因此,让dump 写入该行,然后在我们调用dump 时将其删除。此示例假设您有一个哈希数组,它们都具有相同的键(将是 CSV 标头)。
@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