Skip to content

Instantly share code, notes, and snippets.

@mindplace
Created April 22, 2016 00:45
Show Gist options
  • Save mindplace/09b78dbe281a889665019da04f1f5fb4 to your computer and use it in GitHub Desktop.
Save mindplace/09b78dbe281a889665019da04f1f5fb4 to your computer and use it in GitHub Desktop.

Input/Output

Goals

  • Know how to use gets to read input.
  • Know why chomp is often used to clean input.
  • Know the difference between print and puts.
  • Know how to open a file
    • Know how to read a line from a file.
    • Know how to read in all the lines from a file.
    • Know how to slurp in a whole file in one go.
  • Know when you have to close a file explicitly.
  • Know how to access arguments given to your script from the command line

Standard IO

The most basic IO methods are Kernel#gets and Kernel#puts:

input = gets
puts input # put it back out

gets will read a line from the standard input, which is usually the terminal the user is typing into. It returns the string the user typed, including the newline character (newline character is the 'return' character, written "\n")

input = gets # I type Hello world!, and press enter
# input == "Hello world!\n"

Because the newline is often undesired, frequently we use String#chomp to remove it

input = gets.chomp
# get a string from the input, chop off the newline, store it in
# input

print converts its argument to a string by calling Object#to_s, then it writes it out to the standard output.

print "this that other" # prints 'this that other' to console
print [1, 2, 3] # prints '[1, 2, 3]' to console

print doesn't add a newline after it prints output, which means consecutive calls to print all print to the same line.

print "this"
print "that" # => prints "thisthat"
print "\n" # => adds a newline
print "I'm on a new line"

Since it's common to want to add newlines to the end, Ruby has another method puts. It's pretty simple:

puts "this" # => prints "this" with a newline

Finally, there is the Kernel#p method, which is like puts, but is used for debugging and the REPL (REPL means read-eval-print loop; irb is the standard Ruby REPL). Instead of calling Object#to_s, p calls Object#inspect. The main difference is:

puts "this" # => prints "this" with a newline
p "this" # => prints '"this"' with a newline; note the quotes

Notice also that puts adds newlines after each object in an array.

puts [1, 2, 3]
# prints:
# 1
# 2
# 3

If you want to print an array out on one line, you probably want p.

Opening a file

You often want to read data in from files, rather than the console. The typical way to open a file is as follows:

File.open("movie-times.txt") do |f|
  first_line = f.gets.chomp
  # ...
end

The class method File::open opens a file. You pass a block, and the block will be called with a File object passed in. To read data from a file, you can call File#gets, which works like Kernel#gets, except it reads from the file, rather than console.

If, as is often the case, you want to do something once for each line:

File.foreach("movie-times.txt") do |line|
  # ...
end

Finally, if you'd like to read the entire file into one long string, you may write:

contents = File.read("movie-times.txt")

To read the lines individually, use readlines:

contents = File.readlines("movie-times.txt")
# returns an array, with each element representing a line of
# "movie-times.txt"
# Note: Each element will end with '\n'

The File class includes Enumerable adding all the power we know and love from arrays. Here's an example of using #each.

f = File.new("todos")
f.each {|line| puts "#{f.lineno}: #{line}" }

Writing a file

To open a file for writing, you need to pass "w" to File.open for write mode:

File.open("cool-things.txt", "w") do |f|
  f.puts "Race cars"
  f.puts "Lasers"
  f.puts "Aeroplanes"
end

Note: "w" mode will create a new file or overwrite an existing file. If you wish append to an existing file, you will need to use "a". For more file mode options check this SO post.

Closing files

The examples I've shown you have all automatically closed the file when done. It is important to close files when you are finished with them; this doesn't matter so much for reading (it is merely inefficient), but if you don't close a file you are writing to, then the whole output may not be written to disk, and you may lose data.

If you use File::open without a block, it returns an open File object. You'll be responsible for calling #close when you're done.

f = File.open("cool-things.txt", "w")
f.puts "Race cars"
f.puts "Lasers"
f.puts "Aeroplanes"

# will make sure output is "synced" to disk and properly saved
f.close

Because it is error-prone to rely on remembering to #close a file, prefer the block version of ::open, ::foreach, or ::read whenever possible. These will all automatically #close the file.

Standard Output and Input

We've seen the methods Kernel#puts and Kernel#gets as well as File#puts and File#gets. Surprise! They're related!

In *nix operating systems (like Linux, BSD, and OS X), the console input and output are just special files. You can read and write to them like any other file. These are called standard input and standard output.

In Ruby, you can access standard input and output through the global variables $stdout and $stdin. These variables just hold typical File objects. In particular, Kernel#gets and Kernel#puts just call $stdin.gets and $stdout.puts.

Remembering that $stdin is a File object and that File objects include Enumerable you'll realize that you can #each over input.

$stdin.each do |input|
  puts "I was given: #{ input }"
end

Command Line Arguments

A user can pass arguments to your script from the command line. For example, if your script counts a list of cats, the user could pass the name of a file that contains a list of cats:

$ ruby my_cat_counter.rb list_of_cats.txt

To access the filename passed in, use ARGV in your script. ARGV returns an array of strings that were typed after your script name. Example:

puts ARGV
# returns ["list_of_cats.txt"]
puts ARGV[0]
# prints "list_of_cats.txt"

Resources

  • Beginning Ruby (Ch. 9, p. 203 in the 2nd Edition)
  • Ruby IO Class
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment