Chapter 1. More with Less: Code the Way You Want

image with no caption

You’re wondering what this crazy Ruby language is all about, and if it’s right for you. Let us ask you this: Do you like being productive? Do you feel like all those extra compilers and libraries and class files and keystrokes in your other language bring you closer to a finished product, admiring coworkers, and happy customers? Would you like a language that takes care of the details for you? If you sometimes wish you could stop maintaining boilerplate code and get to work on your problem, then Ruby is for you. Ruby lets you get more done with less code.

The Ruby philosophy

Back in the 1990s in Japan, a programmer named Yukihiro Matsumoto (“Matz” for short) was dreaming about his ideal programming language. He wanted something that:

  • Was easy to learn and use

  • Was flexible enough to handle any programming task

  • Let the programmer concentrate on the problem they were trying to solve

  • Gave the programmer less stress

  • Was object-oriented

He looked at the languages that were available, but felt that none of them was exactly what he wanted. So he set out to make his own. He called it Ruby.

After tinkering around with Ruby for his own work for a while, Matz released it to the public in 1995. Since then, the Ruby community has done some amazing things:

  • Built out a vast collection of Ruby libraries that can help you do anything from reading CSV (comma-separated value) files to controlling objects over a network

  • Written alternate interpreters that can run your Ruby code faster or integrate it with other languages

  • Created Ruby on Rails, a hugely popular framework for web applications

This explosion of creativity and productivity was enabled by the Ruby language itself. Flexibility and ease of use are core principles of the language, meaning you can use Ruby to accomplish any programming task, in fewer lines of code than other languages.

Once you’ve got the basics down, you’ll agree: Ruby is a joy to use!

Flexibility and ease of use are core principles of Ruby.

Get Ruby

First things first: you can write Ruby code all day, but it won’t do you much good if you can’t run it. Let’s make sure you have a working Ruby interpreter installed. We want version 2.0 or later. Open up a new terminal window (also known as a command-line prompt) and type:

ruby -v
image with no caption

When you type ruby -v at a prompt, if you see a response like this, you’re in business:

image with no caption

Do this!

If you don’t have Ruby 2.0 or later, visit www.ruby-lang.org and download a copy for your favorite OS.

By the way, if you accidentally type ruby by itself (without the -v), Ruby will wait for you to enter some code. To exit this mode, just hold the Control key and press the C key on your keyboard. You can do this any time you need Ruby to exit immediately.

Use Ruby

Ruby source files that you can execute are referred to as scripts, but they’re really just plain-text files. To run a Ruby script, you simply save your Ruby code in a file, and run that file with the Ruby interpreter.

You may be used to other languages (like C++, C#, or Java) where you have to manually compile your code to a binary format that a CPU or virtual machine can understand. In these languages, your code can’t be executed before you compile it.

Other languages:

image with no caption

With Ruby, you skip that step. Ruby instantly and automatically compiles the source code in your script. This means less time between writing your code and trying it out!

The Ruby way:

image with no caption
image with no caption

Type your source code. Save as: hello.rb

image with no caption

Run your source code with the Ruby interpreter.

Use Ruby—interactively

There’s another big benefit to using a language like Ruby. Not only do you not have to run a compiler each time you want to try out your code, but you don’t even have to put it in a script first.

Ruby comes with a separate program, called irb (for Interactive Ruby). The irb shell lets you type any Ruby expression, which it will then immediately evaluate and show you the results. It’s a great way to learn the language, because you get immediate feedback. But even Ruby professionals use irb to try out new ideas.

Throughout the book, we’ll be writing lots of scripts to be run via the Ruby interpreter. But any time you’re testing out a new concept, it’s a great idea to launch irb and experiment a bit.

So what are we waiting for? Let’s get into irb now and play around with some Ruby expressions.

Using the irb shell

Open a terminal window, and type irb. This will launch the interactive Ruby interpreter. (You’ll know it’s running because the prompt will change, although it may not match exactly what you see here.)

From there, you can type any expression you want, followed by the Enter/Return key. Ruby will instantly evaluate it and show you the result.

When you’re done with irb, type exit at the prompt, and you’ll be returned to your OS’s prompt.

image with no caption

Your first Ruby expressions

Now that you know how to launch irb, let’s try out a few expressions and see what results we get!

Type the following at the prompt, then press Return: 1 + 2

You’ll be shown the result:

image with no caption

Math operations and comparisons

Ruby’s basic math operators work just like they do in most other languages. The + symbol is for addition, - for subtraction, * for multiplication, / for division, and ** for exponentiation.

image with no caption

You can use < and > to compare two values and see if one is less than or greater than another. You can also use == (that’s two equals signs) to see if two values are equal.

image with no caption

Strings

A string is a series of text characters. You can use strings to hold names, email addresses, phone numbers, and a million other things. Ruby’s strings are special because even very large strings are highly efficient to work with (this isn’t true in many other languages).

The easiest way to specify a string is to surround it either with double quotes (") or single quotes ('). The two types of quotes work a little differently; we’ll cover that later in the chapter.

image with no caption

Variables

Ruby lets us create variables—names that refer to values.

You don’t have to declare variables in Ruby; assigning to them creates them. You assign to a variable with the = symbol (that’s a single equals sign).

image with no caption

A variable name starts with a lowercase letter, and can contain letters, numbers, and underscores.

Once you’ve assigned to variables, you can access their values whenever you need, in any context where you might use the original value.

image with no caption

Variables don’t have types in Ruby; they can hold any value you want. You can assign a string to a variable, then immediately assign a floating-point number to the same variable, and it’s perfectly legal.

image with no caption

The += operator lets you add on to the existing value of a variable.

image with no caption

Conventional Wisdom

Use all lowercase letters in variable names. Avoid numbers; they’re rarely used. Separate words with underscores.

my_rank = 1

This style is sometimes called “snake case,” because the underscores make the name look like it’s crawling on the ground.

Everything is an object!

Ruby is an object-oriented language. That means your data has useful methods (fragments of code that you can execute on demand) attached directly to it.

In modern languages, it’s pretty common for something like a string to be a full-fledged object, so of course strings have methods to call:

image with no caption

What’s cool about Ruby, though, is that everything is an object. Even something as simple as a number is an object. That means numbers have useful methods, too.

image with no caption

Calling a method on an object

When you make a call like this, the object you’re calling the method on is known as the method receiver. It’s whatever is to the left of the dot operator. You can think of calling a method on an object as passing it a message—like a note saying, “Hey, can you send me back an uppercase version of yourself ?” or “Can I have your absolute value?”

image with no caption

Let’s build a game

In this first chapter, we’re going to build a simple game. If that sounds daunting, don’t worry; it’s easy when you’re using Ruby!

Let’s look at what we’ll need to do:

image with no caption

Gary Richardott Game Designer

Input, storage, and output

Our first requirement is to greet the user by name. To accomplish that, we’ll need to write a script that gets input from the user, stores that input, and then uses that stored value to create some output.

We can do all this in just a few lines of Ruby code:

image with no caption

We’ll go into detail on each component of this script over the next few pages. But first, let’s give it a try!

Running scripts

We’ve written a simple script that fulfills our first requirement: to greet the player by name. Now, you’ll learn how to execute the script so you can see what you’ve created.

Do this!

Step One:

Open a new document in your favorite text editor, and type in the following code.

image with no caption

Step Two:

Save the file as get_number.rb.

Step Three:

Open up a terminal window and change into the directory where you saved your program.

Step Four:

Run the program by typing ruby get_number.rb.

image with no caption

Step Five:

You’ll see a greeting and a prompt. Type your name and hit the Enter/Return key. You’ll then see a message that welcomes you by name.

Let’s take a few pages to look at each part of this code in more detail.

Comments

Our source file starts out with a couple of comments. Ruby ignores everything from a hash mark (#) up until the end of the line, so that you can leave instructions or notes for yourself and your fellow developers.

image with no caption

If you place a # in your code, then everything from that point until the end of the line will be treated as a comment. This works just like the double-slash (//) marker in Java or JavaScript.

i_am = "executed" # I'm not.
# Me neither.

“puts” and “print”

The actual code starts with a call to the puts method (“puts” is short for “put string”), which displays text on standard output (usually the terminal). We pass puts a string containing the text to display.

image with no caption

We pass another string to the print method on the following line, to ask the user their name. The print method works just like puts, except that puts adds a newline character at the end of the string (if it doesn’t already have one) to skip to the following line, whereas print doesn’t. For cosmetic reasons, we end the string that we pass to print with a space, so that our text doesn’t run up against the area where the user types their name.

image with no caption

Sometimes you don’t have to specify a receiver for method calls.

The puts and print methods are so important, and so commonly used, that they’re among a select few methods that have been included in Ruby’s top-level execution environment. Methods defined in the top-level environment are available for you to call anywhere in your Ruby code, without specifying a receiver. You’ll see how to define methods like this at the start of Chapter 2.

Method arguments

The puts method takes a string and prints it to standard output (your terminal window).

puts "first line"
image with no caption

The string passed to the puts method is known as the method argument.

The puts method can take more than one argument; just separate the arguments with commas. Each argument gets printed on its own line.

puts "second line", "third line", "fourth line"

“gets”

The gets method (short for “get string”) reads a line from standard input (characters typed in the terminal window). When you call gets, it causes the program to halt until the user types their name and presses the Enter key. It returns the user’s text to the program as another string.

image with no caption

As with puts and print, you can call the gets method from anywhere in your code without specifying a receiver.

Parentheses are optional on method calls

Method arguments can be surrounded with parentheses in Ruby:

puts("one", "two")

But the parentheses are optional, and in the case of puts, most Rubyists prefer to leave them off.

puts "one", "two"

As noted above, the gets method reads a line from standard input. It doesn’t (usually) need any arguments:

gets

Rubyists are adamant that parentheses not be used if a method takes no arguments. So please, don’t do this, even though it’s valid code:

image with no caption

Conventional Wisdom

Leave parentheses off of a method call if there are no arguments. You can leave them off for method calls where there are arguments as well, but this can make some code more difficult to read. When in doubt, use parentheses!

String interpolation

The last thing our script does is to call puts with one more string. This one is special because we interpolate (substitute) the value in the name variable into the string. Whenever you include the #{...} notation inside a double-quoted string, Ruby uses the value in the curly braces to “fill in the blank.” The #{...} markers can occur anywhere in the string: the beginning, end, or somewhere in the middle.

image with no caption

You’re not limited to using variables within the #{...} marker—you can use any Ruby expression.

image with no caption

Note that Ruby applies interpolation only in double-quoted strings. If you include a #{...} marker in a single-quoted string, it will be taken literally.

image with no caption

Ruby doesn’t require a bunch of ceremony for simple programs.

What’s in that string?

image with no caption
image with no caption

Well, that’s easy enough to add. Let’s throw an exclamation point on the end of the greeting string, after the interpolated value.

image with no caption

But if we try running the program again, we’ll see that rather than appearing immediately after the user’s name, the exclamation point jumps down to the next line!

image with no caption

Why is this happening? Maybe there’s something going on within that input variable...

Printing it via the puts method doesn’t reveal anything special about it, though. If we append this line to the code above, we’d see this output:

image with no caption

Inspecting objects with the “inspect” and “p” methods

Now let’s try again, using a method meant especially for troubleshooting Ruby programs. The inspect method is available on any Ruby object. It converts the object to a string representation that’s suitable for debugging. That is, it will reveal aspects of the object that don’t normally show up in program output.

Here’s the result of calling inspect on our string:

image with no caption

What’s that \n at the end of the string? We’ll solve that mystery on the next page...

Printing the result of inspect is so common that Ruby offers another shortcut: the p method. It works just like puts, except that it calls inspect on each argument before printing it.

This call to p is effectively identical to the previous code:

image with no caption

Remember the p method; we’ll be using it in later chapters to help debug Ruby code!

The “inspect” method reveals information about an object that doesn’t normally show up in program output.

Escape sequences in strings

Our use of the p method has revealed some unexpected data at the end of the user’s input:

image with no caption

These two characters, the backslash (\) and the n that follows it, actually represent a single character: a newline character. (The newline character is named thus because it makes terminal output jump down to a new line.) There’s a newline at the end of the user input because when the user hits the Return key to indicate their entry is done, that gets recorded as an extra character. That newline is then included in the return value of the gets method.

Commonly used escape sequences

If you include this in a double-quoted string...

...you get this character...

\n

newline

\t

tab

\"

double-quotes

\'

single-quote

\\

backslash

The backslash character (\) and the n that follows it are an escape sequence—a portion of a string that represents characters that can’t normally be represented in source code.

The most commonly used escape sequences are \n (newline, as we’ve seen) and \t (a tab character, for indentation).

image with no caption

Normally, when you try to include a double-quotation mark (") in a double-quoted string, it gets treated as the end of the string, leading to errors:

image with no caption

If you escape the double-quotation marks by placing a backslash before each, you can place them in the middle of a double-quoted string without causing an error.

image with no caption

Lastly, because \ marks the start of an escape sequence, we also need a way to represent a backlash character that isn’t part of an escape sequence. Using \\ will give us a literal backslash.

image with no caption

Bear in mind that most of these escape sequences apply only in double-quoted strings. In single-quoted strings, most escape sequences are treated literally.

image with no caption

Calling “chomp” on the string object

image with no caption
image with no caption

We can use the chomp method to remove the newline character.

If the last character of a string is a newline, the chomp method will remove it. It’s great for things like cleaning up strings returned from gets.

The chomp method is more specialized than print, puts, and gets, so it’s available only on individual string objects. That means we need to specify that the string referenced by the input variable is the receiver of the chomp method. We need to use the dot operator on input.

image with no caption

The chomp method returns the same string, but without the newline character at the end. We store this in a new variable, name, which we then print as part of our welcome message.

If we try running the program again, we’ll see that our new, emphatic greeting is working properly now!

image with no caption

What methods are available on an object?

You can’t call just any method on just any object. If you try something like this, you’ll get an error:

image with no caption

Which, if you think about it, isn’t so wrong. After all, it doesn’t make a lot of sense to capitalize a number, does it?

But, then, what methods can you call on a number? That question can be answered with a method called methods:

image with no caption

If you call methods on a string, you’ll get a different list: puts "hello".methods

image with no caption

Why the difference? It has to do with the object’s class. A class is a blueprint for making new objects, and it decides, among other things, what methods you can call on the object.

There’s another method that lets objects tell us what their class is. It’s called, sensibly enough, class. Let’s try it out on a few objects.

image with no caption

We’ll be talking more about classes in the next chapter, so stay tuned!

That’s all the code for our first requirement. You can check it off the list!

Generating a random number

Our player greeting is done. Let’s look at our next requirement.

The rand method will generate a random number within a given range. It should be able to create a target number for us.

We need to pass an argument to rand with the number that will be at the upper end of our range (100). Let’s try it out a couple of times:

image with no caption

Looks good, but there’s one problem: rand generates numbers between zero and just below the maximum value you specify. That means we’ll be getting random numbers in the range 0–99, not 1–100 like we need.

That’s easy to fix, though. We’ll just add 1 to whatever value we get back from rand. That will put us back in the range of 1–100!

rand(100) + 1

We’ll store the result in a new variable, named target.

image with no caption

Converting to strings

That’s another requirement down! Let’s look at the next one...

“Keep track of how many guesses the player has made...” Looks like we’ll need a variable for the number of guesses. Obviously, when the player first starts, they haven’t made any guesses, so we’ll create a variable named num_guesses that’s set to 0 initially.

num_guesses = 0

Now, the first thing you might attempt to do in order to display the number of guesses remaining is to concatenate (join) the strings together using the plus sign (+), as many other languages do. Something like this won’t work, however:

image with no caption

The + operator is used to add numbers as well as to concatenate strings, and since remaining_guesses contains a number, this plus sign looks like an attempt to add numbers.

What’s the solution? You need to convert the number to a string. Almost all Ruby objects have a to_s method you can call to do this conversion; let’s try that now.

image with no caption

That works! Converting the number to a string first makes it clear to Ruby that you’re doing concatenation, not addition.

Ruby provides an easier way to handle this, though. Read on...

Ruby makes working with strings easy

Instead of calling to_s, we could save ourselves the effort of explicitly converting a number to a string by using string interpolation. As you saw in our code to greet the user, when you include #{...} in a double-quoted string, code within the curly braces is evaluated, converted to a string if necessary, and interpolated (substituted) into the longer string.

The automatic string conversion means we can get rid of the to_s call.

image with no caption

Ruby lets us do operations directly within the curly braces, so we can also get rid of the remaining_guesses variable.

image with no caption

The #{...} can occur anywhere within the string, so it’s easy to make the output a little more user-friendly, too.

image with no caption

Now the player will know how many guesses they have left. We can check another requirement off our list!

image with no caption

Converting strings to numbers

Our next requirement is to prompt the player to guess the target number. So we need to print a prompt, then record the user’s input as their guess. The gets method, as you may recall, retrieves input from the user. (We already used it to get the player’s name.) Unfortunately, we can’t just use gets by itself to get a number from the user, because it returns a string. The problem will arise later, when we try to compare the player’s guess with the target number using the > and < operators.

image with no caption

We need to convert the string returned from the gets method to a number so that we can compare the guess to our target number. No problem! Strings have a to_i method to do the conversion for us.

Common conversions

If you call this method on an object...

...you get this kind of object back.

to_s

string

to_i

integer

to_f

floating-point number

This code will call to_i on the string returned from gets. We don’t even need to put the string in a variable first; we’ll just use the dot operator to call the method directly on the return value.

guess = gets.to_i

When you call to_i on a string, it ignores any non-numeric characters that follow the number. So we don’t even need to remove the newline character left by gets.

If we want to test our changes, we can print out the result of a comparison.

image with no caption

Much better—we have a guess that we can compare to the target. That’s another requirement done!

image with no caption

Conditionals

Two more requirements for our game down, four to go! Let’s look at the next batch.

Now, we need to compare the player’s guess with the target. If it’s too high, we print a message saying so. Otherwise, if it’s too low, we print a message to that effect, and so on... Looks like we need the ability to execute portions of our code only under certain conditions.

Like most languages, Ruby has conditional statements: statements that cause code to be executed only if a condition is met. An expression is evaluated, and if its result is true, the code in the conditional body is executed. If not, it’s skipped.

image with no caption

As with most other languages, Ruby supports multiple branches in the condition. These statements take the form if/elsif/else.

image with no caption

Conditionals rely on a Boolean expression (one with a true or false value) to decide whether the code they contain should be executed. Ruby has constants representing the two Boolean values, true and false.

if true
  puts "I'll be printed!"
end

if false
  puts "I won't!"
end

Ruby also has all the comparison operators you’re used to.

image with no caption

It has the Boolean negation operator, !, which lets you take a true value and make it false, or a false value and make it true. It also has the more-readable keyword not, which does basically the same thing.

if ! true
  puts "I won't be printed!"
end

if ! false
  puts "I will!"
end

if not true
  puts "I won't be printed!"
end

if not false
  puts "I will!"
end

If you need to ensure that two conditions are both true, you can use the && (“and”) operator. If you need to ensure that either of two conditions is true, you can use the || (“or”) operator.

if true && true
  puts "I'll be printed!"
end

if true && false
  puts "I won't!"
end

if false || true
  puts "I'll be printed!"
end

if false || false
  puts "I won't!"
end
image with no caption

No, Ruby doesn’t treat indentation as significant to the meaning of the program (unlike some other languages, such as Python).

But indenting code within if statements, loops, methods, classes, and the like is just good coding style. It helps make the structure of your code clear to your fellow developers (and even to yourself).

We need to compare the player’s guess to the random target number. Let’s use everything we’ve learned about conditionals to implement this batch of requirements.

image with no caption

The opposite of “if” is “unless”

This statement works, but it’s a little awkward to read:

if not guessed_it
  puts "Sorry. You didn't get my number. (It was #{target}.)"
end

Conventional Wisdom

It’s valid to use else and elsif together with unless in Ruby:

image with no caption

But it’s very hard to read. If you need an else clause, use if for the main clause instead!

image with no caption

In most respects, Ruby’s conditional statements are just like most other languages. Ruby has an additional keyword, though: unless.

Code within an if statement executes only if a condition is true, but code within an unless statement executes only if the condition is false.

unless true
  puts "I won't be printed!"
end

unless false
  puts "I will!"
end

The unless keyword is an example of how Ruby works hard to make your code a little easier to read. You can use unless in situations where a negation operator would be awkward. So instead of this:

if ! (light == "red")
  puts "Go!"
end

You can write this:

unless light == "red"
  puts "Go!"
end

We can use unless to clean up that last conditional.

unless guessed_it
  puts "Sorry. You didn't get my number. (It was #{target}.)"
end

Much more legible! And our conditional statements are working great!

image with no caption

Note

You’ll see something like this if you run get_number.rb now...

As it stands right now, though, the player gets only one guess—they’re supposed to get 10. We’ll fix that next...

Loops

Great work so far! We have just one more requirement to go for our guessing game!

Currently, the player gets one guess. Since there’s 100 possible target numbers, those don’t seem like very fair odds. We need to keep asking the player 10 times, or until they get the right answer, whichever comes first.

The code to prompt for a guess is already in place, so we just need to run it more than once. We can use a loop to execute a segment of code repeatedly. You’ve probably encountered loops in other languages. When you need one or more statements to be executed over and over, you place them inside a loop.

image with no caption

A while loop consists of the word while, a Boolean expression (just like in if or unless statements), the code you want to repeat, and the word end. The code within the loop body repeats while the condition is true.

Here’s a simple example that uses a loop for counting.

image with no caption

Just as unless is the counterpart to if, Ruby offers an until loop as a counterpart to while. An until loop repeats until the condition is true (that is, it loops while it’s false).

Here’s a similar example, using until.

image with no caption

Here’s our conditional code again, updated to run within a while loop:

image with no caption

There’s one more readability improvement we can make. As with the if statement that we replaced with an unless, we can make this while loop read more clearly by replacing it with an until.

Before:

while num_guesses  <  10 && guessed_it == false
  ...
end

After:

until num_guesses == 10 || guessed_it
  ...
end

Here’s our complete code listing.

image with no caption

Let’s try running our game!

Our loop is in place—that’s the last requirement! Let’s open a terminal window and try running the program!

image with no caption
image with no caption

Using variables, strings, method calls, conditionals, and loops, you’ve written a complete game in Ruby! Better yet, it took fewer than 30 lines of code! Pour yourself a cold drink—you’ve earned it!

Your Ruby Toolbox

You’ve got Chapter 1 under your belt and now you’ve added method calls, conditionals, and loops to your toolbox.

Statements

Conditional statements execute the code they enclose if a condition is met.

Loops execute the code they enclose repeatedly. They exit when a condition is met.

Up Next...

All your code is in one big lump right now. In the next chapter, you’ll learn how to break your code into easily maintainable chunks, using classes and methods.

Get Head First Ruby now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.