我想创建一个方法,如果给定一些CSV输出写入文件名,如果没有给出则写入stdout。
似乎我需要以不同的方式处理对CSV
的来电,具体取决于它是文件还是stdout,但我真的很想处理输出流z
作为我可以写的内容而不是它是否是磁盘上的文件或stdout流。
这可能吗?
以下是我的尝试和错误:
require 'csv'
require 'pathname'
require 'csv'
require 'pathname'
def write_to_csv_or_stdout foo, bar, z=nil
z = Pathname.new(z) if z
z ||= $stdout
res = [[foo, bar, "baz"]]
CSV(z) do |csv|
res.each do |row|
csv << row
end
end
end
write_to_csv_or_stdout "foo", "bar"
# foo
# bar
#=> foo,bar,baz
# write_to_csv_or_stdout "foo", "bar", "baz"
# (NoMethodError)
答案 0 :(得分:2)
这适用于stdout和文件名。
使用$stdout.dup
关闭io
而不关闭$stdout
。
require 'csv'
def write_csv(rows, filename = nil)
io = filename ? File.open(filename, 'w+') : $stdout.dup
CSV(io) do |csv|
rows.each do |row|
csv << row
end
end
ensure
io.close
end
rows = [["foo", "bar", "baz"]]
write_csv(rows)
#=> foo,bar,baz
write_csv(rows, 'test.csv')
#=> 'test.csv' written
答案 1 :(得分:0)
一种解决方案是不使用Pathname对象,因为它不是IO对象。
如果您打开文件,则可以像使用stdout对象一样使用它。
def some_method x, y, z=nil
puts x
puts y
z = Pathname.new(z).open if z # <== here you get an IO Object back
z ||= $stdout
res = [["foo", "bar", "baz"]]
CSV(z) do |csv|
res.each do |row|
csv << row
end
end
end
答案 2 :(得分:0)
我使用辅助方法:
def write_csv(io_or_filename, &block)
if io_or_filename.is_a?(IO)
CSV.new(io_or_filename, &block)
else
CSV.open(io_or_filename, 'wb', &block)
end
end
可以使用此代替CSV(...)
:
def some_method(x, y, z = $stdout)
write_csv(z) do |csv|
csv << # ...
end
end