How to write a file with ruby? [duplicate] - ruby

This question already has answers here:
How to write to file in Ruby?
(7 answers)
Closed 7 years ago.
I want to create a temp file:
def create_file
FileUtils.mkdir_p('/var/log/my_app')
tmp_file = '/var/log/my_app/tmp_file'
File.open(tmp_file, 'w') do |file|
file.write 'test'
end
end
Here I am sure that the /var/log/my_app path exists. But after I run this method, I can't find a file named tmp_file under that path.
And there wasn't any error, too.

I think you would do better using Ruby's TempFile class and perhaps even Ruby's temp dir as suggested in this article: Quick tips for doing IO with Ruby.
I think you will find the article helpful. I believe it will make your approach easier - especially regarding deleting the file once you're done with it.

I don't see any error in your code. If you don't get any exception, the file must have been created, if this function has been executed.
I suggest that you make a test at the end of create_file:
if File.file?
puts "File has been created"
else
fail "File is not there!"
end
If you see "File has been created", but the file is still missing, something must have erased it before you had time to check its presence. If you see "File is not there!", something weird is going on and I would call an exorcist. If you don't see any message, it means that your function has not been executed.

Related

How can I tell which file is being required here? [duplicate]

This question already has answers here:
What happens technically when a file is required in Ruby?
(3 answers)
Closed 5 years ago.
I'm reading through the codebase of the Homebrew repo, specifically the file here:
https://github.com/Homebrew/brew/blob/8518ffdee19c0c985e8631e836b78624e4926c7f/Library/Homebrew/brew.rb
I see many 'require' statements scattered throughout the file, for instance on line 104 (require 'tap'). The problem is that I see 3 files named tap.rb in the codebase:
Library/Homebrew/tap.rb
Library/Homebrew/cmd/tap.rb
Library/Homebrew/compat/tap.rb
Further down in the code I see Tap.fetch..., and in Library/Homebrew/tap.rb which contains a class named Tap with a class method named fetch, so I'm confident this is the correct file that's being included. But conceivably, there could be dozens of files with the same filename, and more than one of those could have identical class methods. My question is, is there a way to tell which Tap class is being loaded without looking through each of the files?
UPDATE: I think I have the answer to my question (see below).
If you put a binding.pry before the require and execute $: that will be the list of directories in which the require will look up the 'tap.rb' files.
See definition of require:
If the filename does not resolve to an absolute path, it will be searched for in the directories listed in $:.
I found this great explanation of how require works in Ruby:
https://github.com/ericmathison/articles/blob/master/understaning-require-in-ruby.md
Essentially, it works by looking at the Ruby $LOAD_PATH method, similar to how UNIX uses the $PATH variable to look for binary executables when it receives a command in the CLI. I was able to test this out on my local by making two files in the same directory, like so:
# file number 1- foobar.rb
module Foobar
module_function
def bar
p "foo"
end
end
# file number 2- foobaz.rb
$LOAD_PATH.unshift(".")
class Foobaz
def baz
require 'foobar'
p Foobar.bar
end
end
Foobaz.new.baz
Without the line $LOAD_PATH.unshift(".") in foobaz.rb, the code wouldn't execute with the simple require 'foobar' statement. I instead had to use require_relative 'foobar.rb'. But adding the current working directory to the $LOAD_PATH environment variable meant that I now had access to all the ruby files in the current dir, so it executed!
NB- it's likely that adding . to the $LOAD_PATH should go in a config file somewhere, not in the same file as the require statement.

Ruby: Add line in file [duplicate]

This question already has answers here:
What are the Ruby File.open modes and options?
(2 answers)
Closed 6 years ago.
I have a file in which one I want to store some datas.
Using IRB, I can add different lines in the file. However, using a Ruby script writen in a file, I have issues.
I can write a line, it is stored as it should be, but when I re launch the script and re use the method, it overwrites what was in the file instead of adding content at the next line.
def create_new_account
puts "Set the account's name"
#account_name = gets
puts "New account's name: #{#account_name}
open("accounts.txt","w+") do |account_file|
account_file.write "ac;#{#account_name}\n"
end
end
I had a look to the different parameters of the method open, but seems like it's not there.
Moreover, I tried puts instead of write, but there is no difference, always the same problem.
Could someone help me understand what is wrong with the code?
Thanks
Try opening the file in append mode like so
open('accounts.txt', 'a+')
otherwise the file is opened so as to overwrite the existing data.
"a" - Write-only, each write call appends data at end of file.
Creates a new file for writing if file does not exist.

Having trouble in getting input from user in Ruby

I have a method which check if the file exists, If the file does not exist then it should call another method which prompts the questions. Below is the sample code.
def readFile1()
flag = false
begin
#ssh.exec!("cd #{##home_dir}")
puts "\nChecking if file exists on #{#hostname}\n"
if #ssh.exec!("sh -c '[ -f "#{file_name}" ]; echo $?'").to_i == 0
flag = true
puts "File exists on #{#hostname}"
display()
else
puts "File does not exist. Please answer following questions."
prompt()
end
rescue => e
puts "readFile1 failed... #{e}"
end
return exists
end
def prompt()
puts "\nDo you want to enter the new file location? [y/n]"
ans = gets.chomp
puts "New location is #{ans}"
end
When I am calling readFile method, if the file does not exists, it prints Do you want to enter the new file location? [y/n] and does not wait for the user to enter the value but immediately prints the rescue block and quits. Below is the Output if file does not exists.
Checking if file exists on LNXAPP
File does not exist. Please answer following questions.
Do you want to enter the new file location? [y/n]
readFile1 failed... No such file or directory - LNXAPP
I want the user to enter the values for the questions but it's not happening.Need help in fixing this.
Your code is not ideal.
You should check if the file exists via:
if File.exist? location_of_your_file_goes_here
The begin/rescue is then not required, because
you already check before whether the file exists.
Also two spaces should be better than one tab,
at least when you display on a site such as here.
Reason is simple - it makes your code easier
to read for others.
You also don't need the flag variable if I am
right - try to omit it and use solely File.exist?
there.
Also you wrote:
"When I am calling readFile method"
But you have no method called readFile().
Your method is called readFile1().
I know that you probably know this too, but
you must be very specific so that the ruby
parser understands precisely what you mean,
and that what you describe with words also
matches to the code you use.
Another issue I see with your code is that
you do this:
return exists
but what is "exists" here? A variable?
A method? It has not been defined elsewhere
in your code.
Try to make your code as simple and as logical
as possible.

How to create a file in Ruby

I'm trying to create a new file and things don't seem to be working as I expect them too. Here's what I've tried:
File.new "out.txt"
File.open "out.txt"
File.new "out.txt","w"
File.open "out.txt","w"
According to everything I've read online all of those should work but every single one of them gives me this:
ERRNO::ENOENT: No such file or directory - out.txt
This happens from IRB as well as a Ruby script. What am I missing?
Use:
File.open("out.txt", [your-option-string]) {|f| f.write("write your stuff here") }
where your options are:
r - Read only. The file must exist.
w - Create an empty file for writing.
a - Append to a file.The file is created if it does not exist.
r+ - Open a file for update both reading and writing. The file must exist.
w+ - Create an empty file for both reading and writing.
a+ - Open a file for reading and appending. The file is created if it does not exist.
In your case, 'w' is preferable.
OR you could have:
out_file = File.new("out.txt", "w")
#...
out_file.puts("write your stuff here")
#...
out_file.close
Try
File.open("out.txt", "w") do |f|
f.write(data_you_want_to_write)
end
without using the
File.new "out.txt"
Try using "w+" as the write mode instead of just "w":
File.open("out.txt", "w+") { |file| file.write("boo!") }
OK, now I feel stupid. The first two definitely do not work but the second two do. Not sure how I convinced my self that I had tried them. Sorry for wasting everyone's time.
In case this helps anyone else, this can occur when you are trying to make a new file in a directory that does not exist.
If the objective is just to create a file, the most direct way I see is:
FileUtils.touch "foobar.txt"
The directory doesn't exist. Make sure it exists as open won't create those dirs for you.
I ran into this myself a while back.
File.new and File.open default to read mode ('r') as a safety mechanism, to avoid possibly overwriting a file. We have to explicitly tell Ruby to use write mode ('w' is the most common way) if we're going to output to the file.
If the text to be output is a string, rather than write:
File.open('foo.txt', 'w') { |fo| fo.puts "bar" }
or worse:
fo = File.open('foo.txt', 'w')
fo.puts "bar"
fo.close
Use the more succinct write:
File.write('foo.txt', 'bar')
write has modes allowed so we can use 'w', 'a', 'r+' if necessary.
open with a block is useful if you have to compute the output in an iterative loop and want to leave the file open as you do so. write is useful if you are going to output the content in one blast then close the file.
See the documentation for more information.
data = 'data you want inside the file'.
You can use File.write('name of file here', data)
You can also use constants instead of strings to specify the mode you want. The benefit is if you make a typo in a constant name, your program will raise an runtime exception.
The constants are File::RDONLY or File::WRONLY or File::CREAT. You can also combine them if you like.
Full description of file open modes on ruby-doc.org

How to read an open file in Ruby

I want to be able to read a currently open file. The test.rb is sending its output to test.log which I want to be able to read and ultimately send via email.
I am running this using cron:
*/5 * * * /tmp/test.rb > /tmp/log/test.log 2>&1
I have something like this in test.rb:
#!/usr/bin/ruby
def read_file(file_name)
file = File.open(file_name, "r")
data = file.read
file.close
return data
end
puts "Start"
puts read_file("/tmp/log/test.log")
puts "End"
When I run this code, it only gives me this output:
Start
End
I would expect the output to be something like this:
Start
Start (from the reading of the test.log since it should have the word start already)
End
Ok, you're trying to do several things at once, and I suspect you didn't systematically test before moving from one step to the next.
First we're going to clean up your code:
def read_file(file_name)
file = File.open(file_name, "r")
data = file.read
file.close
return data
end
puts "Start"
puts read_file("/tmp/log/test.log")
puts "End"
can be replaced with:
puts "Start"
puts File.read("./test.log")
puts "End"
It's plain and simple; There's no need for a method or anything complicated... yet.
Note that for ease of testing I'm working with a file in the current directory. To put some content in it I'll simply do:
echo "foo" > ./test.log
Running the test code gives me...
Greg:Desktop greg$ ruby test.rb
Start
foo
End
so I know the code is reading and printing correctly.
Now we can test what would go into the crontab, before we deal with its madness:
Greg:Desktop greg$ ruby test.rb > ./test.log
Greg:Desktop greg$
Hmm. No output. Something is broken with that. We knew there was content in the file previously, so what happened?
Greg:Desktop greg$ cat ./test.log
Start
End
Cat'ing the file shows it has the "Start" and "End" output of the code, but the part that should have been read and output is now missing.
What happening is that the shell truncated "test.log" just before it passed control to Ruby, which then opened and executed the code, which opened the now empty file to print it. In other words, you're asking the shell to truncate (empty) it just before you read it.
The fix is to read from a different file than you're going to write to, if you're trying to do something with the contents of it. If you're not trying to do something with its contents then there's no point in reading it with Ruby just to write it to a different file: We have cp and/or mv to do those things for us witout Ruby being involved. So, this makes more sense if we're going to do something with the contents:
ruby test.rb > ./test.log.out
I'll reset the file contents using echo "foo" > ./test.log, and cat'ing it showed 'foo', so I'm ready to try the redirection test again:
Greg:Desktop greg$ ruby test.rb > ./test.log.out
Greg:Desktop greg$ cat test.log.out
Start
foo
End
That time it worked. Trying it again has the same result, so I won't show the results here.
If you're going to email the file you could add that code at this point. Replacing the puts in the puts File.read('./test.log') line with an assignment to a variable will store the file's content:
contents = File.read('./test.log')
Then you can use contents as the body of a email. (And, rather than use Ruby for all of this I'd probably do it using mail or mailx or pipe it directly to sendmail, using the command-line and shell, but that's your call.)
At this point things are in a good position to add the command to crontab, using the same command as used on the command-line. Because it's running in cron, and errors can happen that we'd want to know about, we'd add the 2>&1 redirect to capture STDERR also, just as you did before. Just remember that you can NOT write to the same file you're going to read from or you'll have an empty file to read.
That's enough to get your app working.
class FileLineRead
File.open("file_line_read.txt") do |file|
file.each do |line|
phone_number = line.gsub(/\n/,'')
user = User.find_by_phone_number(line)
user.destroy unless user.nil?
end
end
end
open file
read line
DB Select
DB Update
In the cron job you have already opened and cleared test.log (via redirection) before you have read it in the Ruby script.
Why not do both the read and write in Ruby?
It may be a permissions issue or the file may not exist.
f = File.open("test","r")
puts f.read()
f.close()
The above will read the file test. If the file exists in the current directory
The problem is, as I can see, already solved by Slomojo. I'll only add:
to read and print a text file in Ruby, just:
puts File.read("/tmp/log/test.log")

Resources