stephen
stephen

Reputation: 195

How Ruby .gets moves through file lines

In a stripped down exercise (20) from Learn Ruby the Hard Way, the script opens a file (test.txt) and prints three successive lines.

input_file = ARGV.first

def print_a_line(line_count, f)
  puts "#{line_count}, #{f.gets}"
end

current_file = open(input_file)

current_line = 1
print_a_line(current_line, current_file)

current_line += 1
print_a_line(current_line, current_file)

current_line += 1
print_a_line(current_line, current_file)

The result being

$ ruby ex20.rb test.txt
1, This is line 1
2, This is line 2
3, This is line 3

I understand that gets only "gets" one line at a time, but I can't figure out what in this script makes the "playhead" move from one line to the next in test.txt. When I remove .gets, it looks like it stays in the same position:

$ ruby ex20.rb test.txt
1, #<File:0x00000001b9b738>
2, #<File:0x00000001b9b738>
3, #<File:0x00000001b9b738>

And when I increase the line number on current_line by += 3, while the printed line number changes to reflect this, the content of that line doesn't:

$ ruby ex20.rb test.txt
1, This is line 1
2, This is line 2
5, This is line 3

The content of test.txt is:

This is line 1
This is line 2
This is line 3
This is line 4
This is line 5

So, how is this moving from line to line automatically, and by extension, how could I make it move to another line rather than the next successive one?

Upvotes: 1

Views: 98

Answers (2)

Sergio Tulentsev
Sergio Tulentsev

Reputation: 230296

In addition to @spickermann's answer

and by extension, how could I make it move to another line rather than the next successive one?

Generally, you can't. If you want to skip, say, two lines, you can't just jump over directly to the third one. You have to read these two and ignore them.

In a specific case where all your lines have the same fixed length, you can seek directly to a line you want (and then again, some IO streams will only allow seeking forward, not forward and backward).

I can't figure out what in this script makes the "playhead" move from one line to the next in test.txt

I sometimes visualize a typewriter, but it does the opposite thing. When you call gets, the reading head would read current line to the end, scroll the sheet one line, rewind to the beginning of the line and pause, waiting for the next gets.

Not sure if this was at all helpful to you, but it helps me. :)

Upvotes: 0

spickermann
spickermann

Reputation: 106802

From the documentation of IO#gets:

Reads the next “line” from the I/O stream; lines are separated by sep. [...] The line read in will be returned and also assigned to $_. [...]

That said: f is your file object. When you call gets on that file, it will return the next line - a string up to the next new line character ("\n") and it will store the current position (line number). When you call gets again, it can look up the last position and therefore is able to return the next line.

In the context of your example it is worth noting that line_count and current_line are totally independent. You can change current_line to any value it will not change the bahaviour of f.gets.

Upvotes: 1

Related Questions