24

Is there anyway to write the following code in Ruby without writing the file to disk?

temp_file = 'path/to/file.csv'
users = [a@b.c, c@b.a]

CSV.open(temp_file, "w") do |csv|
  csv << data_for_report
end

Reports.sendreport users temp_file

File.delete(temp_file)

The Reports.sendreport attaches a file and sends an email, so it needs to be a file...

hirolau
  • 13,451
  • 8
  • 35
  • 47
  • So you want a string of comma separated values? Do you need the csv at that point? Could you join your columns with commas, and your rows with newlines? – quandrum Jan 23 '13 at 20:31
  • 1
    Ohh, the sendreport function sends a mail with a csv-file attached. So I really need it to be a file... – hirolau Jan 23 '13 at 20:37
  • Are you saying the sendreport method reads the file from disk? – quandrum Jan 23 '13 at 20:52
  • 1
    Correct.. It reads a file from disc and attaches it to an email. The question now is if there is anyway to save the file, as a file, in memory. – hirolau Jan 23 '13 at 21:02
  • If you can't change `Reports`, then you probably are doing it the right way. It's probably more trouble than it's worth to get a section of memory to pretend it's a disk so `Reports` can read from it. – quandrum Jan 23 '13 at 21:25

4 Answers4

20

You could use Tempfile. Tempfile writes the file to disc, so it does not fit your request.

But I think Tempfile provides some features you need:

When a Tempfile object is garbage collected, or when the Ruby interpreter exits, its associated temporary file is automatically deleted.

Example:

require 'tempfile'
require 'csv'

data_for_report = [1,2,3,4]
temp_file = Tempfile.new('foo')

CSV.open(temp_file, "w") do |csv|
  csv << data_for_report
end
knut
  • 27,320
  • 6
  • 84
  • 112
4
temp_file = CSV.generate do |csv|
  csv << data_for_report
end

Reports.sendreport users temp_file
Gregory Ray
  • 305
  • 2
  • 4
  • This is the correct answer to the question `Is there anyway to write the following code in Ruby without writing the file to disk?` Other answers seems to be workarounds (tempfiles) – Greg Mar 30 '23 at 10:53
3

With your current code that's not possible, if your code would use file pointers/handles instead you can do the following:

require 'csv'
require 'stringio'

data_for_report = [1,2,3,4]
temp_file = StringIO.new # creates a fake file as string.

CSV.new(temp_file, "w") do |csv|
  csv << data_for_report
end

The key problem why it isn't working for your usecase is the line Reports.report users temp_file

If that accepts a handle instead of a string it'll work.

See also this SO: https://stackoverflow.com/a/19110958/887836

Alexander Oh
  • 24,223
  • 14
  • 73
  • 76
2

Try one of the mmap gems. If the library only takes a filename, that's your option.

If it can accept a file-like object, however, you can use a StringIO.

You might consider changing whatever Reports is, making it more general-purpose. It depends on what it's using to create its mail message–this might be trivial.

Dave Newton
  • 158,873
  • 26
  • 254
  • 302
  • I will look into StringIO, think that might be what I am looking for... Reports.sendreport is really just my own wrapper on the gmail gem, so I am not really sure if i need a real if or if StringIO will work. – hirolau Jan 23 '13 at 22:13