I have entered the following code from Zed Shaw's book on "Learning Ruby the Hard Way
input_file = ARGV.first #this takes the file test.txt
def print_all(f) #reading a line
puts f.read
end
def rewind(f)
f.seek(0)
end
def print_a_line(line_count, f)
current_line
puts "#{line_count}, #{f.gets.chomp}"
end
current_file = open(input_file)
puts "First let's print the whole file:\n"
print_all(current_file)
puts "Now let's rewind, kind of like a tape"
rewind(current_file)
puts "Let's print three line:"
current_line = 1
print_a_line(current_line, current_file)
current_line = current_line + 1
print_a_line(current_line, current_file)
current_line = current_line + 1
print_a_line(current_line, current_file)
The error I am getting is 'ex20.rb:12:in print_a_line': undefined method chomp' for nil:NilClass (NoMethodError)
from ex20.rb:31:in `'
Any help would be greatly appreciated. I have followed his example word by word.
You have to add a few more lines to the test.txt file (at least three lines of text for each of the method calls you do at the end).
I ran across the same issue because the lesson isn't exactly clear about it, but since the script prints out three lines in a row, you need 3 lines of text in the file for the script to work.
add more lines to your test.txt file
Related
input_file = ARGV.first
def print_all(f)
puts f.read
end
def rewind(f)
f.seek(0)
end
def print_a_line(line_count, f)
puts "#{line_count}, #{f.gets.chomp}"
end
current_file = open(input_file)
puts "First let's print the whole file:¥n"
print_all(current_file)
puts "Let's rewind kind a like a tape"
rewind(current_file)
puts "Let's print three lines:"
current_line = 1
print_a_line(current_line, current_file)
current_line += 1
print_a_line(current_line, current_file)
I'm sure there is a kinda similar post to this, but my question is a bit different. As seen above, the print_a_line method got two params that are line_count and f.
1) As I understood, line_count argument only serves as a variable which is current_line and it is just an integer. How does it relate to the rewind(f) method because when I run the code, the method print_a_line shows this:
1, Hi
2, I'm a noob
where 1 is the first line and 2 is the second. line_count is just a number, how does ruby know that 1 is line 1 and 2 is line 2?
2) Why use gets.chomp in method print_a_line? If I pass just f like this
def print_a_line(line_count, f)
puts "#{line_count}, #{f}"
end
I'll get a crazy result which is
1, #<File:0x007fccef84c4c0>
2, #<File:0x007fccef84c4c0>
Because IO#gets reads next line from readable I/O stream(in this case it's a file) and returns a String object when reading successfully and not reached end of the file. And, chomp removes carriage return characters from String object.
So when you have a file with content such as:
This is file content.
This file has multiple lines.
The code will print:
1, This is file content.
2, This file has multiple lines.
In the second case, you're passing file object itself and not reading it. Hence you see those objects in output.
I tried googling and looking through stackoverflow and still couldnt figure out why does it not work. Essentially, this line of code reads in a file.txt and loop through the line of instructions on the text file
# Load instruction in an array
File.open('file.txt').each do |line|
line_num += 1
array.to_a.push line.split(" ")
end
# Loop through the array of Instructions
array.each do |line|
instruction = line[0]
value = line[1].to_i
This is the error that I got
NoMethodError: undefined method `+' for nil:NilClass
method block in <main> in VirtualMemory.rb at line 3
method each in VirtualMemory.rb at line 2
method <main> in VirtualMemory.rb at line 2
line_num += 1
is equivalent to
line_num = line_num + 1
Since line_num is not defined, it is nil -- the fix would be to initialize it as 0 before opening the file, or you could do something like:
array = File.open('file.txt').each.map{ |line| line.split(" ")}
You have to initialize your variables.
line_num += 1
Unless line_num is previously defined this will fail, it's basically the same thing as line_num = nil + 1
This will also fail if you haven't previously defined array, and if you had, then there'd be no point calling to_a.
array.to_a.push line.split(" ")
I am going through "Learn Ruby the Hard Way" and I came across the method print_a_line in exercise 20.
input_file = ARGV.first
current_file = open(input_file)
def print_a_line(line_count, f)
puts "#{line_count}, #{f.gets.chomp}"
end
current_line = 1
print_a_line(current_line, current_file)
current_line = current_line + 1
print_a_line(current_line, current_file)
current_line = current_line + 1
print_a_line(current_line, current_file)
This method is about to take the current line count and output to the terminal only the contents of the file from that line. I don't understand how the method knows to print the line of the file that is associated with current_line. When I look at this I would think #{f.gets.chomp) would return the entire contents of they file. How does the method know to look at the current_line and print out the associated line of the file?
The gets method being called in print_a_line reads a single line from the file (not the entire contents). The File object referenced by current_file keeps track of the current position within the file, so each time gets is called, the next line is returned.
Nothing is looking at current_line to determine which line to read.
For this exercise I wrote all the code perfectly and even double checked by literally copying and pasting the code from the book (Learn Ruby the Hard Way). For some reason when I call the print_a_line() function, it won't print out the current_line argument I pass through until the 3rd call where it will print out 3 before the line. Is there some flushing of the IO stream I am missing out on here or some nuance with Powershell?
I am running Ruby 2.0.0p576 (x64) on Windows 8 64 bit machine.
Code:
input_file = ARGV.first
def print_all(f)
puts f.read
end
def rewind(f)
f.seek(0)
end
def print_a_line(line_count, f)
puts "#{line_count}, #{f.gets.chomp}"
end
current_file = open(input_file)
puts "First let's print the whole file:\n"
print_all(current_file)
puts "Now let's rewind, kind of like a tape."
rewind(current_file)
puts "Let's print three lines:"
current_line = 1
print_a_line(current_line, current_file)
current_line = current_line + 1
print_a_line(current_line, current_file)
current_line = current_line + 1
print_a_line(current_line, current_file)
I deleted the test.txt file and recreated it from scratch and this made the code work perfectly. I am not 100% as to why, but I have a hunch that from reusing that file in many different tests and playing around in Powershell I had inadvertently left some strange formatting in the file causing it to behave differently.
What does the (0, IO::SEEK_SET) do in method rewind? I understand the rest of the code, but I am honestly stuck at the (0, IO::SEEK_SET).
input_file = ARGV[0]
def print_all(f)
puts f.read()
end
def rewind(f)
f.seek(0, IO::SEEK_SET)
end
def print_a_line(line_count, f)
puts "#{line_count} #{f.readline()}"
end
current_file = File.open(input_file)
puts "First let's print the whole file:"
puts # a blank line
print_all(current_file)
puts "Now let's rewind, kind of like a tape."
rewind(current_file)
puts "Let's print three lines:"
current_line = 1
print_a_line(current_line, current_file)
current_line = current_line + 1
print_a_line(current_line, current_file)
current_line = current_line + 1
print_a_line(current_line, current_file)
seek(amount, whence=IO::SEEK_SET) → 0
Seeks to a given offset amount in the stream according to the value of whence:
:CUR or IO::SEEK_CUR | Seeks to _amount_ plus current position
----------------------+--------------------------------------------------
:END or IO::SEEK_END | Seeks to _amount_ plus end of stream (you
| probably want a negative value for _amount_)
----------------------+--------------------------------------------------
:SET or IO::SEEK_SET | Seeks to the absolute location given by _amount_
http://www.ruby-doc.org/core-2.1.2/IO.html#method-i-seek
When you specify a position to seek to, there are typically three ways to do this
SEEK_SET: from the start of the file (ie: absolute)
SEEK_CUR: from the current position (ie: relative)
SEEK_END: from the end of the file
So in your case the rewind method simply seeks to the beginning of the file.