接受的答案并没有真正回答这个问题,所以我想我会举一个有用的例子。
首先,如果您查看http://ruby-doc.org/stdlib-1.9.3/libdoc/csv/rdoc/CSV.html上的文档,如果您将鼠标悬停在方法名称上,dump
您会看到可以click to show source
。如果你这样做,你会看到该dump
方法尝试调用csv_headers
你传入的第一个对象ary_of_objs
:
obj_template = ary_of_objs.first
...snip...
headers = obj_template.csv_headers
然后稍后您会看到该方法将调用csv_dump
每个对象ary_of_objs
并传入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
那里返回 '' 仍然是一个空行,解析需要标题。因此,让 letdump
写下那行,然后在我们调用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