Write CSV to stdout or filename

2019-09-08 18:09发布

I want to make a method that writes some CSV output to a filename if given and stdout if not given.

It seems like I need to treat my calls to CSV differently depending on if it's a file or to stdout, but I'd really like to treat the output stream z as something I can write to and not have to whether it's a file on disk or the stdout stream.

Is this possible?

Below is my attempt and errors:

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)

标签: ruby csv oop
3条回答
一夜七次
2楼-- · 2019-09-08 18:33

This works for stdout and filenames.

It uses $stdout.dup to be able to close io without closing $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
查看更多
SAY GOODBYE
3楼-- · 2019-09-08 18:36

One solution would be not to use only the Pathname object since it isn't an IO object.

If you open the file then you can use it the same way as you would use the stdout object.

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
查看更多
啃猪蹄的小仙女
4楼-- · 2019-09-08 18:40

I'd use a helper method:

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

This can be used instead of CSV(...):

def some_method(x, y, z = $stdout)
  write_csv(z) do |csv|
    csv << # ...
  end
end
查看更多
登录 后发表回答