Books / Ruby for Beginners / Chapter 9

String Interpolation

Readability of a program can be significantly improved by taking advantage of string interpolation:

puts "Your age?"
age = gets.to_i
age_months = age * 12
puts "Your age is #{age_months}"

There is no need for type casting on line 4. Every Object in Ruby can be converted to a string (to_s method is responsible for that). That’s why there is a common syntax for every type, and it’s called “interpolation”.

The trick is the expression gets evaluated inside of curly braces. We have very simple expression inside of curly braces, just age_months, but it can be any Ruby code (for example, 2 + 2). And at the end final result gets converted to a string. Look at another example:

puts "Your age?"
age = gets.to_i
puts "Your age is #{age * 12}"

Only 3 lines of code! There is no need for extra variable, because we can evaluate expression right inside of curly braces, result will be the same.

At first glance, there is little improvement. Even old JavaScript syntax allows to use + for strings and numbers:

$ node
> "Your age is " + 30 * 12
'Your age is 360'

But newer JavaScript (ES6+) also has string interpolation syntax. There was need for that, but many programmers found that it simplifies a program, and adds mode readability:

$ node
> `Your age is ${30 * 12}`
'Your age is 360'
>

Keep in mind that for interpolation in JavaScript you’ll need backticks, and in Ruby double quotes.

Interpolation is quite useful when you deal with multiple variables. For example:

puts "Your name?"
name = gets

puts "Your age?"
age = gets.to_i

puts "Your city?"
city = gets

puts "=" * 80
puts "You are #{name}, your age in months is #{age * 12}, and you are from #{city}"

Note: example above has 12 lines, but the last line was too long for Leanpub book, and was wrapped automatically. In your editor you can remove \ sign and continue on line 11.

Result:

Your name?
Roman
Your age?
30
Your city?
San Francisco
========================================================================
You are Roman
, your age in months is 360, and you are from San Francisco

Almost works, there are some quirks though. We used string interpolation on the last line, and were able to output all the information with only one line. However, something is not right. Do you see new line right after “Roman”? What is happening here?

The thing is gets function returns a string with special character \n. This character is not visible on the screen, but when your terminal sees that, it moves the caret to the next (new) line. This special character is called “new line character”. It’s only one byte in standard character table (ASCII) with position number 10.

Let’s prove that gets returns a string with new line character at the end. Run this in your REPL:

$ irb
> x = gets
Hi
 => "Hi\n"
> x.class
 => String
> x.size
 => 3

We’ve assigned a value to variable x, and this value comes from gets (you need to type “Hi”). As we already know, REPL prints the result of operation, so we see Hi\n. So it says there is a new line character at the end of this string. Then we check the type of this object with .class, and it’s String. After that we use .size to find out the length of this string, and it shows 3 (and it makes sense because we touched our keyboard exactly three times: one time for letter “H”, second time for letter “i”, and then we pressed “Enter”). So the code for “Enter” key is still there.

When we did interpolation in our program above, new line character was there as well. That’s why our output was misaligned. Let’s fix our program:

puts "Your name?"
name = gets.chomp

puts "Your age?"
age = gets.to_i

puts "Your city?"
city = gets.chomp

puts "=" * 80
puts "You are #{name}, your age in months is #{age * 12}, and you are from #{city}"

Result:

$ ruby app.rb
Your name?
Roman
Your age?
30
Your city?
San Francisco
========================================================================
You are Roman, your age in months is 360, and you are from San Francisco

It works! We used chomp method for String class to remove new line characters from the end.

It’s important to remember that interpolation only works with double quotes. Single quotes like ' can be used in Ruby as well, but interpolation is not supported intentionally for single quotes. Moreover, some tools for code analysis (like Rubocop) will complain about double quotes without interpolation inside. The rule of thumb here is to use single quotes when you don’t need interpolation, and to use double quotes when you actually need string interpolation.

Exercise 1 Find and read documentation for chomp and size methods for String class.

Exercise 2 Write a program to calculate your average daily salary. User should be able to type annual income, and program should calculate daily salary. Modify the program so it also calculates monthly salary.

Bang !

Another interesting challenge we should tackle is “bang”, “exclamation mark”, or just ! at the end of some method. Let’s look at Ruby program below (if you’re using non-English characters on Windows, you may have some difficulties with “downcase”):

x = 'I AM COOL'
x = x.downcase
puts x

Note that text is “I AM COOL”, not “I’M COOL” - you can do that too, but keep it in double quotes (because this phrase contains apostrophe).

Result:

$ ruby app.rb
i am cool

We defined variable with value “I AM COOL”, all capital letters. On the second line we redefined the variable and assigned new value to it, the result of x.downcase operation. Since initially x is String, we have the right to call any method for String class. And we’re calling “downcase” method for class String. This method translates upper case letters to lower case, and we see this result on the screen.

But the most interesting part is on line 2: x = x.downcase. There is alternative syntax for that in Ruby, and instead of reassigning variable, we can just type x.downcase!. It looks similar, but with alternative syntax Ruby will understand that it needs to perform operation on the object itself. In other words, line 2 has two parts:

  • x.downcase
  • x = result of operation (or y = result of operation, we can use any other variable here)

And with x.downcase! it’s only one part: do downcase operation on this object x.

But not every method supports such functionality, in every single case you will need to lookup documentation. Also, bang-methods in Ruby are considered dangerous, because these methods always change the state of the object. But why it’s dangerous? - curious reader will ask - We are just changing the value of this particular object, and that’s it! But it’s not that simple.

Look at the following program. No tricks here, just try to guess what will be printed on the screen:

a = 'HI'
b = a
a = 'xxx'
puts b

We have two variables: a and b. We assign the value of a to variable b on line 2. In other words, b equals to HI now. On line 3 we replace the value of variable a with xxx (because we can, there is no too much sense for that now, but you’ll understand later why we did that). What will be printed on the screen? Nothing out of the ordinary, just HI.

Now let’s modify this program a little bit, everything is the same, except line 3:

a = 'HI'
b = a
a.downcase!
puts b

Note that we didn’t touch variable b. But we did “dangerous operation” with a. What will be printed on the screen? There is a trick here. It turns out that dangerous operation will affect variable b and change its value. Try it yourself and you’ll see hi on the screen (instead of HI in previous example).

Explanation is about how Ruby works internally. There is no need for a beginner to know all the details, but it’s worth mentioning that every variable keeps an address (reference, pointer) to the actual data. This address is a pointer to location in computer memory, and the value of this pointer is something like 123456789. But the actual data is not address, it can be found by using this address.

It’s similar to apartments house with multiple doorbells. New variable is similar to a doorbell that leads to this or another apartment. Doorbell is not apartment itself, but it’s associated with it. When we assign variable b = a we just say that doorbell b now leads to the same apartment as doorbell a. These doorbells don’t know about each other. But when we do dangerous operation, we change the state of the apartment, its internals. So both doorbells remain the same, they will even keep the same numbers on them, but now they will lead to apartment with modified state.

There is no any magic in bang-methods. In the next chapters we will shed some light on how to create your own classes and objects, and you’ll be able to make your own bang-methods. Some popular web frameworks (like Rails) have their own dangerous methods, for example save! (it saves an object to a database). And exclamation mark implies that this method is dangerous:

  • It changes the state of the object, so all references now will point to modified object.
  • If something goes wrong, this method will generate exception (we’ll cover this topic later in this book).

Exercise Find out if there are any other bang methods for String class.


Licenses and Attributions


Speak Your Mind

-->