Kernel#gets
gets(sep=$/) -> string or nil gets reads the next line from standard input (STDIN), returning it as a string with the line separator removed. At end of file, it returns nil. This method is commonly used for interactive command-line programs that need to read user input.
Syntax
gets(sep=$/)
When called with no arguments, gets uses the global record separator $/ which defaults to a newline. This means each call reads exactly one line from the input stream and includes the trailing newline in the returned string. At the end of the stream the method returns nil, which is the natural signal for callers to stop their read loop.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
sep | String | $/ (newline) | The line separator. When specified, gets reads until it encounters this string. |
Examples
Basic usage
# Simulating user input with StringIO
require 'stringio'
input = StringIO.new("Hello\nWorld\n")
$stdin = input
first_line = gets
puts first_line.inspect # => "Hello\n"
second_line = gets
puts second_line.inspect # => "World\n"
third_line = gets
puts third_line.inspect # => nil
$stdin = STDIN # Restore stdin
This example uses StringIO to simulate user input so the code can be tested without waiting for a real person to type. The method reads line by line, and the third call returns nil because the stream has been exhausted. In a real interactive session, gets would block until the user presses Enter and would only return nil if the input stream is closed with Ctrl+D.
Reading with custom separator
require 'stringio'
input = StringIO.new("one,two,three\n")
$stdin = input
# Read until comma instead of newline
line = gets(",")
puts line.inspect # => "one,two,three\n"
$stdin = STDIN
When you pass a custom separator like ",", gets reads until it encounters that character instead of the default newline. This changes the behavior: each call now returns a chunk of text up to and including the separator. The trailing separator is still part of the returned string, so you may want to strip it depending on how you plan to use the result.
Common Patterns
Interactive input loop
puts "Enter your name:"
name = gets
puts "Hello, #{name.chomp}!"
This is the canonical interactive pattern in Ruby: prompt the user, read a line with gets, and strip the trailing newline with chomp before using the value. Without chomp the string would carry a newline character that often causes formatting issues when you embed it in further output or pass it to other methods.
Chomp before using
# Always chomp to remove the trailing newline
print "Enter command: "
cmd = gets.chomp
if cmd == "exit"
puts "Goodbye!"
exit
end
Errors
- IOError: If STDIN is closed,
getsreturnsnilrather than raising an error. - ArgumentError: Raised if the separator is an empty string (Ruby 3.0+).
reading input line by line
gets is the simplest way to pull a line from standard input when the program is waiting on a person or another process. It keeps the code honest about the fact that input may stop at any time, since nil marks the end of the stream. In scripts that interact with the terminal, that small behavior is often enough to drive a whole loop. The calling code just needs to remember to trim or check the value before using it further.
That pattern fits well in command-line utilities because the loop can stay narrow: read a line, clean it up, decide what to do next, and continue or stop. The method does not try to interpret the input for you, which leaves the calling code in control of the rule. That makes it a straightforward building block for interactive tools, small importers, and other programs that wait on user input one line at a time.
It is also a reminder that line-oriented input should be handled as a stream rather than as a one-time value. The caller can keep asking for lines until the stream ends, and each line can be treated as a small unit of work. That keeps the control flow simple and makes the program easy to explain to someone reading it for the first time.