How to display contents of file - ruby

I'm trying to display the contents of a file.
class CommonLog
def initialize(filename)
#filename = filename
end
def readfile
text = File.readlines(#filename).map do |line|
line.split(" ")
puts text
end
end
end
my_file = CommonLog.new("test.log")
puts my_file.readfile
I am receiving the error No such file or directory - test.log".

Create the file. But once you get past that error where the file does not exist, you are doing things that are not worthwhile.
You are splitting the line, but not storing or using the information.
You are using puts to output the return of the text object, but your question title is how to view the contents.
You can puts line which will output each line of the file once it exists.
You are assigning text, and referencing it in the same statement, and so when you puts text it is nil. The method will return the assignment to text, but otherwise it is not being used.
If you remove the reference to text inside the block, you get get rid of the assignment to text variable.
Finally, you can remove the entire block if you would simply want an array of lines to be returned, or use join on the readlines method.
The redesigned version may look like this:
class CommonLog
def initialize(filename)
#filename = filename
end
def readfile
File.readlines(#filename)
end
end
my_file = CommonLog.new("test.log")
puts my_file.readfile # This actually prints an Array
That array holds the contents of your file, and the puts displays the contents of that file as stored in that array.

Related

How to push into arrays when reading ruby files?

I've followed the tutorial about how to read a text file with ruby with the purposes of printing it out with arrays, but it doesn't seem like working... here are the attempts in test.rb.
tutorial:https://www.codecademy.com/articles/writing-to-file-ruby
this test list file is successfully printing put in the console but its not in an array, how do I turn it into array? thanks!
# test.rb
class File
File.open("test_list.txt").each do |line|
puts line
def ProcessText
test_list.txt = File.to_s
end
end
end
If I understand correctly, you want to save each line in an array. This is what you would do
# test.rb
class File
array = []
File.open("test_list.txt").each do |line|
array << line
def ProcessText
test_list.txt = File.to_s
end
end
puts array
end

Outputting hash to text file

I am having trouble outputting the contents of my hash to a file. The program is one that manages a list of student records, including their StudentID, first name, last name, Major, and catalog year. Once the user is finished adding records, it is then added to the hash.
Everything in the program works perfectly, except when I try running the quit_program function, it doesn't save the contents in the file. Additionally, i am not getting any errors, any ideas?
could it potentially not be working because it is having trouble with converting the text in my hash, which is alphanumeric, into the text file?
def quit_program()
puts "Save Changes? y/n"
#changes = gets().chomp
if #changes=="y"
#fh=File.open(#file_name, 'w')
#this_string=""
#sDB.each do |key, store_account_data| #line 50
puts "#{key}: #{store_account_data.join(',')}"
end
end
#fh.puts(#this_string)
#fh.close()
end
You're not writing anything to the file. The string #this_string is empty. You should do
#sDB.each do |key, store_account_data|
#fh.puts "#{key}: #{store_account_data.join(',')}"
end
it doesn't save the contents in the file.
The following is NOT how you write to a file:
puts "#{key}: #{store_account_data.join(',')}"
That is how you write to your terminal/console window.
And this code:
#this_string=""
#fh.puts(#this_string)
writes a blank string to the file.
Here is how you write to a file:
class Student
def initialize(sDB, filename)
#sDB = sDB
#filename = filename
end
def save_changes()
puts "Save Changes? y/n"
user_answer = gets().chomp
if user_answer == "y"
File.open(#file_name, 'w') do |f|
#sDB.each do |key, store_account_data| #line 50
f.puts "#{key}: #{store_account_data.join(',')}"
end
end
end
end
could it potentially not be working because it is having trouble with
converting the text in my hash, which is alphanumeric, into the text
file?
No. Here is a concrete example you can try:
data = {
"John" => ['a', 123, 'b', 456],
"Sally" => ['c', 789, 'b', 0]
}
File.open('data.txt', 'w') do |f|
data.each do |name, data|
f.puts "#{name}: #{data.join(',')}"
end
end
$ ruby myprog.rb
$ cat data.txt
John: a,123,b,456
Sally: c,789,b,0
Also, ruby indenting is 2 spaces--not 0 spaces or 3 spaces, or anything else.
The answer is given in the error message: undefined local variable or method 'sDB'. (Which you have since removed from your question making the edited version next to impossible to answer.) Where and when is sDB defined in your program? You are evidently attempting to quit before initializing it.
In any case it is not a good thing to be accessing instance variables directly inside other methods. You should use accessor (getter and setter) methods instead. That would have probably prevented this situation from biting you in the first place.
def sdb
#sDB ||= Hash.new
end
def sdb=( key, value )
sdb
#sDB[ key ] = value
end
. . .
You are not properly writing to a file even if #sDB is defined. See Ruby - Printing a hash to txt file for an example.
Your question is missing essential input data, so there's no way to test our suggested changes.
Here's untested code I'd work from:
def quit_program
puts "Save Changes? y/n"
if gets.chomp.downcase == 'y'
File.write(
#file_name,
#s_db.map{ |k, v| "#{ k }: #{ v.join(',') }" }.join("\n")
)
end
end
Note:
#sDB isn't a proper variable name in Ruby. We use snake_case, not camelCase for variables and method names. ItsAMatterOfReadability. Follow the convention or suffer the wrath of your team members the first time you have a code review.
Don't add empty parenthesis to method names (quit_program()) or calls (gets()) unless it's essential to tell the difference between a variable and a method invocation. You should also never name a variable the same as a method because it'll confuse everyone working on the code, so that should never be a consideration.
Don't create a variable (#changes) you use once and throw away, unless what you're doing is so complex you need to break down the operation into smaller chunks. And, if you're doing that, it'd be a really good candidate for refactoring into separate methods, so again, just don't.
When comparing user-input to something you expect, fold the case of their input to match what you expect. (gets.chomp.downcase == 'y'). It really irritates users to enter "y" and fail because you insisted on "Y".
While you can use File.open to create or write to a file, there's less visual noise to use File.write. open is great when you need to use various options for the mode but for plain text write is sufficient.
The whole block used for writing looks like it can be cleaned up to a single map and join, which coerces the data into an array of strings then into a single string.

Reading a file by passing filename to a function

I am trying to read the file name and process each line. How do I pass the file name to the the function?
puts "file name?? "
_file = get.chomps
def printFile(_file)
do |f|
f.each_line do |line|
print_me = "Line 1 " + line
return print_me
end
end
end
I am planning to pass print_me to another function like:
def thisWillPrint(print_me)
new_print = print_me + " DONE! "
end
I can see a few problems in your code. First you are using a block inside the definition of your printFile function which is a syntax error, next you use the variable f in that block which was never given a value, on top of that you try to do a loop on it and never open a file descriptor. Finally you must call the printFile function somewhere so that ruby knows it has to run it.
The first thing your printFile function should do is get a file descriptor to the file the user gives you as a string in the _file variable, this way you actually have a stream you can read lines from not just the string object. So I recommend you change the variable from _file to fileName, and leave file for the stream. You do this by using Ruby's own File class and calling its open method. As you can see from the documentation open can be called in a few different ways, but let's use a block like you were trying to do.
puts 'give me a path to a file'
fileName = gets.chomp
def printFile(fileName)
counter = 0
File.open(fileName) do |file|
while line = file.gets
print_me = "line " + counter.to_s + " "+line
thisWillPrint(print_me)
end
end
end
def thisWillPrint(print_me)
puts print_me + " DONE! "
end
printFile(fileName)
You also have to call the printFile function at the end so that ruby actually runs something.
Note that by returning inside the loop, you will exit it as well. With the following, you will get the contents of the file.
def printfile(filename)
print_me = ""
File.open(filename, "r") do |f|
f.each {|line| print_me << line }
end
print_me
end
For large files, the return variable will also be very large.
To read a line from standard input you can use the gets method. The gets method captures a newline \n by default. You have to use the chomp method to get rid of the newline.
So to get the file's name from standard input you can do the following:
print "File's name? "
_file = gets.chomp
Inside the printFile method you can do the following:
def printFile(_file)
print_me = ""
File.foreach(_file) do |line|
# process each line however you'd like inside this block
# for example:
print_me += line
end
return print_me # explicit return not required
end
Note that you do not have to explicity 'return' something if it's the last expression in the method. The last expression could have just been print_me instead.
You can pass what this method returns to another method like thisWillPrint like this:
def thisWillPrint(print_me)
new_print = print_me + "Done!"
end
output = printFile(_file)
thisWillPrint(output)

loop, array and file problem in ruby

I'm currently learning ruby and here what I'm trying to do:
A script which open a file, make a subsitution, then comparing every lines to each other to see if it exist many times.
So, I tried to work directly with the string, but I didn't find how to do it, so I put every line in an array, and comparing every row.
But I got a first problem.
Here is my code:
#!/usr/bin/env ruby
DOC = "test.txt"
FIND = /,,^M/
SEP = "\n"
#make substitution
puts File.read(DOC).gsub(FIND, SEP)
#open the file and put every line in an array
openFile = File.open(DOC, "r+")
fileArray = openFile.each { |line| line.split(SEP) }
#print fileArray #--> give the name of the object
#Cross the array to compare every items to every others
fileArray.each do |items|
items.chomp
fileArray.each do |items2|
items2.chomp
#Delete if the item already exist
if items = items2
fileArray.delete(items2)
end
end
end
#Save the result in a new file
File.open("test2.txt", "w") do |f|
f.puts fileArray
end
At the end, I only have the name of the array object "fileArray". I print the object after the split, and i've got the same, so I guess the problem is from here. Little help required (if you know how to do this without array, just with the line in the file, answer appreciate too).
Thanks !
EDIT:
So, here's my code now
#!/usr/bin/env ruby
DOC = "test.txt"
FIND = /,,^M/
SEP = "\n"
#make substitution
File.read(DOC).gsub(FIND, SEP)
unique_lines = File.readlines(DOC).uniq
#Save the result in a new file
File.open('test2.txt', 'w') { |f| f.puts(unique_lines) }
Can't figure out how to chomp this.
Deleting duplicate lines in a file:
no_duplicate_lines = File.readlines("filename").uniq
No need to write so much code :)
Modify your code like this:
f.puts fileArray.join("\n")
Alternate way:
unique_lines = File.readlines("filename").uniq
# puts(unique_lines.join("\n")) # Uncomment this line and see if the variable holds the result you want...
File.open('filename', 'w') {|f| f.puts(unique_lines.join("\n"))}
Just a couple of points about the original code:
fileArray = openFile.each { |line| line.split(SEP) }
sets fileArray to a File object, which I suspect wasn't your intention. File#each (the # notation is Ruby convention to describe a particular method on an object of the supplied class) executes your supplied block for each line (it's also available with a synonym: each_line), where a line is defined by default as your OS's end-line character(s).
If you were looking to build an array of lines, then you could just have written
fileArray = openFile.readlines
and if you wanted those lines to be chomped (often a good idea) then that could be achieved by something like
fileArray = openFile.readlines.collect { |line| line.chomp }
or even (since File mixes in Enumerable)
fileArray = openFile.collect { |line| line.chomp }
And one other tiny thing: Ruby tests for equality with ==, = is only for assignment, so
if items = items2
will set items to items2 (and will always evaluate as true)

Ruby: Deleting last iterated item?

What I'm doing is this: have one file as input, another as output. I chose a random line in the input, put it in the output, and then delete it.
Now, I've iterated over the file and am on the line I want. I've copied it to the output file. Is there a way to delete it? I'm doing something like this:
for i in 0..number_of_lines_to_remove
line = rand(lines_in_file-2) + 1 #not removing the first line
counter = 0
IO.foreach("input.csv", "r") { |current_line|
if counter == line
File.open("output.csv", "a") { |output|
output.write(current_line)
}
end
counter += 1
}
end
So, I have current_line, but I'm not sure how to remove it from the source file.
Array.delete_at might do. Given an index, it removes the object at that index, returning the object.
input.csv:
one,1
two,2
three,3
Program:
#!/usr/bin/ruby1.8
lines = File.readlines('/tmp/input.csv')
File.open('/tmp/output.csv', 'a') do |file|
file.write(lines.delete_at(rand(lines.size)))
end
p lines # ["two,2\n", "three,3\n"]
output.csv:
one,1
Here is a randomline class. You create a new randomline object by passing it an input file name and an output file name. You can then call the deleterandom method on that object and pass it a number of lines to delete.
The data is stored internally in arrays as well as being put to file. Currently output is in append mode so if you use the same file it will just add to the end, you could change the a to a w if you wanted to start the file fresh each time.
class Randomline
attr_accessor :inputarray, :outputarray
def initialize(filein, fileout)
#filename = filein
#filein = File.open(filein,"r+")
#fileoutput = File.open(fileout,"a")
#inputarray = []
#outputarray = []
readin()
end
def readin()
#filein.each do |line|
#inputarray << line
end
end
def deleterandom(numtodelete)
numtodelete.times do |num|
random = rand(#inputarray.size)
#outputarray << inputarray[random]
#fileoutput.puts inputarray[random]
#inputarray.delete_at(random)
end
#filein = File.open(#filename,"w")
#inputarray.each do |line|
#filein.puts line
end
end
end
here is an example of it being used
a = Randomline.new("testin.csv","testout.csv")
a.deleterandom(3)
You have to re-write the source-file after removing a line otherwise the modifications won't stick as they're performed on a copy of the data.
Keep in mind that any operation which modifies a file in-place runs the risk of truncating the file if there's an error of any sort and the operation cannot complete.
It would be safer to use some kind of simple database for this kind of thing as libraries like SQLite and BDB have methods for ensuring data integrity, but if that's not an option, you just need to be careful when writing the new input file.

Resources