Can't print file after writing to it - ruby

For some reason I cannot get this to print anything with the final line.
prev_std = STDOUT
$stdout = File.open(reportname, 'w')
# Several things happen to print to STDOUT here
$stdout = STDOUT
# Tell them that the report was written
puts "Report written to #{ reportname }"
# Slurp in the report ( FIXME )
reporttext = File.open(reportname, 'r') { |f| f.read }
# Print out the report after ( FIXME )
puts reporttext
I've just written the report to the file, but somehow I can't read it back to the screen. I'm using the exact same string in the code to refer to the file in both cases. Checking at the shell prompt proves the file was written correctly, and yet I still can't get it to print to the screen.
What am I doing wrong here?

It looks like the issue comes from the file not being closed. Changing $stdout doesn't close the file object it used to refer to. Add $stdout.close to the line before you reassign it to the old stdout.

Related

Reading file input with ruby via command line input

So I am trying to read a file in ruby by giving the name via the command line. So far my code reads as follows:
puts "What is the name of the file to read?"
fileName = gets.chomp
file = $stdin.read.strip
f = File.open(file, “r”)
f.each_line { |line|
puts line
}
What I see happening is it is reading the inputs through the command line but does not read a file. For example, I can pass 'input.txt', 'code.txt', and 'sonic.txt' as file names but the program just loops back seeking another input. How can I change this to read the file by name and then out put the contents of that file?
Your problems are:
The line fileName = gets.chomp is useless. Remove that.
file = $stdin.read.strip will not let you terminate the input. Use gets to get user's input from the command line.
You are using the wrong quotation “ in your parameter “r” for File.open.
You are not closing the file after reading it. It is better to use the block form of File.open to ensure the file is closed after using.
Here is a minimum fix:
puts "What is the name of the file to read?"
file = gets.chomp
File.open(file, "r"){|f|
f.each_line {|line|
puts line
}
}

How would you close this file descriptor?

Let's say you have the following code:
from_file, to_file = ARGV
puts "Copying from #{from_file} to #{to_file}"
#in_file = open(from_file)
#indata = in_file.read
indata = open(from_file).read # Combined in_file and indata.
puts "The input file is #{indata.length} bytes long."
puts "Does the output file exist? #{File.exist?(to_file)}"
puts "Ready, hit RETURN to continue or CTRL-C to abort."
$stdin.gets
out_file = open(to_file, 'w')
out_file.write(indata)
puts "Alright, all done."
out_file.close
#in_file.close
How would you close the file descriptor invoked by indata? You will need to close File open, but indata is really a (File open).read.
P.S. Since it's a script, it will be closed automatically upon exit. Let's assume that we're running a general, consistently running backend service. And we don't know whether garbage collector will kick in, so we will need to explicitly close it. What would you do?
If you are just copying the file...
you could just use FileUtils#cp:
FileUtils.cp("from_file", "to_file")
or even shell-out to the operating system and do it with a system command.
Let's suppose you want to do something to the input file before writing it to the output file.
If from_file is not large,...
you could "gulp it" into a string using IO.read:
str = IO.read(from_file)
manipulate str as desired, to obtain new_str, then then blast it to the output file using IO#write:
IO.write("to_file", new_str)
Note that for the class File:
File < IO #=> true # File inherits IO's methods
which is why you often see this written File.read(...) and File.write(...).
If from_file is large, read a line, write a line...
provided the changes to be made are done for each line separately.
f = File.open("to_file", "w") # or File.new("to_file", "w")
IO.foreach("from_file") do |line|
# < modify line to produce new_line >
f.puts new_line
end
f.close
foreach closes "from_file" when it's finished. If f.close is not present, Ruby will close "to_file" when the method containing the code goes out of scope. Still, it's a good idea to close it in case other work is done before the code goes out of scope.
Passing File.open a block is generally a nice way to go about things, so I’ll offer it up as an alternative even if it doesn’t seem to be quite what you asked.
indata = File.open(from_file) do |f|
f.read
end

Can't pipe into gvim from a ruby sub process

I've been attempting to use the PA_translator.vim plugin but found that it doesn't work in Win32 Gvim. This appears to be because in an embedded Vim Ruby script it's not possible to use any of the commands which pipe in from a subprocess. The original process builds a command dymanically and then launches a subprocess to obtain a JSON snippet like so:
cmd = "require 'net/http'; p Net::HTTP.get('%s', '%s')"% [host, path]
response = `ruby -e "#{cmd}"`
If I run this in a command line ruby script it works fine, but inside a Vim script the pipe appears to return an empty string..
I've also tried several other methods which produce the same result:
response = ''
IO.popen("ruby.exe", "w+") do |f|
f.write cmd
f.close_write
response = f.read
p response
end
And even:
def redirect
orig_defout = $stdout
$stdout = StringIO.new
yield
$stdout.string
ensure
$stdout = orig_defout
end
response = redirect { eval cmd }
All of these seem to fail for the same reason, it's not possible to get the output from the pipe and I get back an empty string. GVim is a true win32 process, is there some reason why piping from a subprocess won't work?
EDIT: If I try to capture piped output from embedded vim/perl, that works fine, so I guess it's some particular issue with the vim -> win32 -> ruby combination:
fun! SayHello()
perl << EOF
$bob = `ls`;
VIM::Msg($bob);
EOF
endfun

Ruby: How to replace text in a file?

The following code is a line in an xml file:
<appId>455360226</appId>
How can I replace the number between the 2 tags with another number using ruby?
There is no possibility to modify a file content in one step (at least none I know, when the file size would change).
You have to read the file and store the modified text in another file.
replace="100"
infile = "xmlfile_in"
outfile = "xmlfile_out"
File.open(outfile, 'w') do |out|
out << File.open(infile).read.gsub(/<appId>\d+<\/appId>/, "<appId>#{replace}</appId>")
end
Or you read the file content to memory and afterwords you overwrite the file with the modified content:
replace="100"
filename = "xmlfile_in"
outdata = File.read(filename).gsub(/<appId>\d+<\/appId>/, "<appId>#{replace}</appId>")
File.open(filename, 'w') do |out|
out << outdata
end
(Hope it works, the code is not tested)
You can do it in one line like this:
IO.write(filepath, File.open(filepath) {|f| f.read.gsub(//<appId>\d+<\/appId>/, "<appId>42</appId>"/)})
IO.write truncates the given file by default, so if you read the text first, perform the regex String.gsub and return the resulting string using File.open in block mode, it will replace the file's content in one fell swoop.
I like the way this reads, but it can be written in multiple lines too of course:
IO.write(filepath, File.open(filepath) do |f|
f.read.gsub(//<appId>\d+<\/appId>/, "<appId>42</appId>"/)
end
)
replace="100"
File.open("xmlfile").each do |line|
if line[/<appId>/ ]
line.sub!(/<appId>\d+<\/appId>/, "<appId>#{replace}</appId>")
end
puts line
end
The right way is to use an XML parsing tool, and example of which is XmlSimple.
You did tag your question with regex. If you really must do it with a regex then
s = "Blah blah <appId>455360226</appId> blah"
s.sub(/<appId>\d+<\/appId>/, "<appId>42</appId>")
is an illustration of the kind of thing you can do but shouldn't.

Find and replace in a file in Ruby

I have this little program I write in ruby. I found a nice piece of code here, on SO, to find and replace something in a file, but it doesn't seems to work.
Here's the code:
#!/usr/bin/env ruby
DOC = "test.txt"
FIND = /,,^M/
SEP = "\n"
#make substitution
File.read(DOC).gsub(FIND, SEP)
#Check if the line already exist
unique_lines = File.readlines(DOC).uniq
#Save the result in a new file
File.open('test2.txt', 'w') { |f| f.puts(unique_lines) }
Thanks everybody !
I skip the check you make to see if the line already exists and usually go with something like this (here I want to replace 'FOO' with 'BAR'):
full_path_to_read = File.expand_path('~/test1.txt')
full_path_to_write = File.expand_path('~/test2.txt')
File.open(full_path_to_read) do |source_file|
contents = source_file.read
contents.gsub!(/FOO/, 'BAR')
File.open(full_path_to_write, "w+") { |f| f.write(contents) }
end
The use of expand_path is also probably a bit pedantic here, but I like it just so that I don't accidentally clobber some file I didn't mean to.

Resources