When does ruby release its File.write assignments? - ruby

I am writing to a file instance. While the program is still running, the file is always empty. When I check the file after the script has executed, the file has content.
class A
def initialize
#file_ref=File.new("/user/shared/ruby/ruby-example/test.html","w+")
end
def fill
#file_ref.write("whatever\nwhatever\nwhatever\n")
end
end
The Main script:
require_relative 'A'
a=A.new
a.fill
puts File.size("/user/shared/ruby/ruby-example/test.html")
After the A instance has done its job, the puts statement will print "0" as if the file is empty. Indeed it is during program execution, but if I start irb:
puts File.size("/user/shared/ruby/ruby-example/test.html")
# => 27
$ cat test.html
whatever
whatever
whatever
Is my code wrong?
Is it normal that streams are flushed only after the execution of a process?

Ruby flushes IO buffers when you call IO#close or IO#flush. Since you are not calling neither close nor flush the buffers are flushed when the program terminates and the opened file descriptors are released.
Given your simple example a possible solution is:
class A
def initialize
#file_ref_name = '/user/shared/ruby/ruby-example/test.html'
end
def fill
File.open(#file_ref_name, 'w+') do |file|
file.write("whatever\nwhatever\nwhatever\n")
end
end
end
Passing a block to IO#open makes the opened file (the file variable in this example) to be closed (and therefore flushed) once the execution of the block terminates.

Please note that Ruby (to my knowledge since version 1.9) features a one liner shortcut for simple file writes as well, flush included:
File.write('/path/to/file.txt', 'content')

Related

Popen example that I do not understand

I have a basic understanding of popen before now but it seems it has changed completely.
Please refer the example to know why?
# process.rb
IO.popen("ruby test_ex.rb","w") do |io|
io.write("#{Process.pid} hello")
io.close_write
## this does not work.
##io.readlines
end
## text_ex.rb
def readWrite
#string = gets()
puts "#{Process.pid} -- #{#string}"
end
readWrite
Now I understand in write mode the STDOUT(of popen.rb) will be writable end of the pipe and STDIN (of text_ex.rb) will be the readable end of the pipe.
All is good here.
But let see the other example
my_text = IO.popen("ssh user#host 'bash'", "w+")
my_text.write("hostname")
my_text.close_write
my_rtn = my_text.readlines.join('\n')
my_text.close
puts my_rtn
Ok, now what is different over here?
The popen start a child process(i.e ssh) send the hostname.
Now, I fail to understand how does the STDOUT of the child process(i.e ssh) is available to the parent process i.e how does the readlines work over here and does not work in my earlier example.
Thanks
The difference is in the second argument to popen: "w" versus "w+". You can read more here in the docs:
"w" Write-only, truncates existing file
to zero length or creates a new file for writing.
"w+" Read-write, truncates existing file to zero length
or creates a new file for reading and writing.
The notion of "truncating" doesn't really apply to pipes, but the fact that you need read-write mode does.

Ruby: Reading from a file written to by the system process

I'm trying to open a tmpfile in the system $EDITOR, write to it, and then read in the output. I can get it to work, but I am wondering why calling file.read returns an empty string (when the file does have content)
Basically I'd like to know the correct way of reading the file once it has been written to.
require 'tempfile'
file = Tempfile.new("note")
system("$EDITOR #{file.path}")
file.rewind
puts file.read # this puts out an empty string "" .. why?
puts IO.read(file.path) # this puts out the contents of the file
Yes, I will be running this in an ensure block to nuke the file once used ;)
I was running this on ruby 2.2.2 and using vim.
Make sure you are calling open on the file object before attempting to read it in:
require 'tempfile'
file = Tempfile.new("note")
system("$EDITOR #{file.path}")
file.open
puts file.read
file.close
file.unlink
This will also let you avoid calling rewind on the file, since your process hasn't written any bytes to it at the time you open it.
I believe IO.read will always open the file for you, which is why it worked in that case. Whereas calling .read on an IO-like object does not always open the file for you.

After reading a file ruby leaves it open/locked on Windows XP

I read a text file to get some info from it and later on I need to rename the directory that the file sits in. I am not able do to that because the file is locked. If I comment out the function that reads from the file or if I manually unlock the file (unlocker utility) everything goes fine.
I am on ruby 1.8.7 (2010-08-16 patchlevel 302) [i386-mingw32]
This line leaves the file open File.open(file).readlines.each{|line|
These two lines leave the file open
my_file=File.open(file,"r")
my_file.collect {|line|
unless I close the file at the end using my_file.close
The man for core 1.8.7 of IO.html#method-c-open states
If the optional code block is given, it will be passed io as an argument, and the IO object will automatically be closed when the block terminates.
So I don't understand why the file is still open.
What would be the one line code in 1.8.7 to read a text file and close it automatically?
The documentation is clear. However, you're passing the block to collect. And since you're not passing it to open, you are responsible for closing the file.
To have file auto-closed, try this:
File.open(file,"r") do |f|
f.collect # or whatever
end
Try passing the block directly to the "open" call:
File.open(file, 'r') do |f|
f.each_line do |line|
# Process each line
end
end
Or if you just want the file contents in a single shot then try this:
lines = File.read(file).split(/\r?\n/)
If you want the block to close the file automagically without passing the file handle to a block, you can use the IO#readlines method of your File object.
array_of_lines = File.readlines('/tmp/foo')
This will read the entire contents of the file, then close the file handle. It's a good option whenever a file is small enough to fit easily into memory.

Can't delete Dir/Files after using File.open block

When trying to delete a directory (+ contents) and after reading the files inside, FileUtils.rm_rf(path) will not delete all the folders, although it does delete all the files and some of the folders.
After some experimentation it seems to be related to a File.open block. (I actually do a regex match inside the block, but I'm just using a puts here to keep things clear)
File.open(file).each do |line|
puts line
end
From what I've read, the above should automatically close the file but when using this, FileUtils fails to complete its task.
However, if I use the following code, FileUtils works as desired.
open_file = File.open(file)
open_file.each do |line|
puts line
end
open_file.close
It's no big deal to use the code in the second example, but I do prefer the cleanliness of the first.
Is there any reason why that first example breaks FileUtils?
P.S. I'm new to both Ruby and Stack Overflow....Hi. My system is Ubuntu 11.04 (64bit), running RVM with Ruby 1.9.2-p180
You should use something like this:
File.open(file) do |f|
f.each{|line| puts line}
end
In your example the block is supplied to the each method and the version of open without a block is executed returning an IO object on which the each method is called.

Ruby - redefining instance methods not working

My simple attempt to redefine instance methods are not working
class File
alias_method :old_atime, :atime
def atime(*args)
puts "helllllo"
old_atime(*args)
end
end
f = File.new("C:\\abc.txt","w")
puts f.atime
Any idea why?
I'm attempting to print "helllllo" everytime File#atime is called. Even alias old_atime atime is not working.
Is there something I'm doing wrong here?
Above code works perfectly as it should be. Puts "helllllo" writes "helllllo" in to your opened file. Puts inside the file instance meant for writing.
Just call f.close and open your file in text editor. You can see the content.
Yep, Ramesh is right. Try this:
class File
alias_method :old_atime, :atime
def atime(*args)
Kernel.puts "helllllo" # <---- Kernel method
old_atime(*args)
end
end
f = File.new("C:\\abc.txt","w")
puts f.atime
The issue is that 'puts' is defined in File for writing to files. You want the Kernel one which is used unless defined in a more specific scope.
This should work fine, but IO#puts writes to the IO object itself, not STDOUT. In other words, it's writing to the file.
Call f.atime a few times and then f.close within irb and you should see it printing helllllo to the file for each call to atime.
To print to STDOUT, you could use $stdout.puts or Kernel.puts.

Resources