# Flow Control

In many ways, a computer program is like a journey for your data. Along this journey, data encounters many things that have an impact on it and it is forever changed. Like any journey, one must travel a given path. On that path, there are many roads. Some roads are chosen and others not. Which roads are chosen depends on the end goal.

When you are writing programs, you want your data to make the right decisions. You want your data to do the right thing when it's supposed to. In computer programming, this is called conditional flow.

How do we make data do the right thing? We use conditionals.

## Conditionals

A conditional is a fork (or many forks) in the road. Your data approaches a conditional and the conditional then tells the data where to go based on some defined parameters. Conditionals are formed using a combination of `if` statements and comparison and logical operators `(<, >, <=, >=, ==, !=, &&, ||)`. They are basic logical structures that are defined with the reserved words `if`, `else`, `elsif`, and `end`. Note that `elsif` is missing an "e". Enough talking, time to code.

Create a file called `conditional.rb` and type the following code into it.

``````# conditional.rb

puts "Put in a number"
a = gets.chomp.to_i

if a == 3
puts "a is 3"
elsif a == 4
puts "a is 4"
else
puts "a is neither 3, nor 4"
end
``````

Here we are using `gets` to let the user input a number, `chomp` gets rid of the new line created when the user enters the data, and `to_i` is a method that can be called on a string to turn it into an integer. We need to convert the input into an integer because `gets` always gives us a string.

Run this code three times and do the following:

1. The first time, type in the number 3 and press enter.
2. The second time, type in the number 4 and press enter.
3. The third time, type in any number that isn't 3 or 4 and press enter.

You can repeat the third step more than once to see its effect.

What your code is doing is checking, using the `==` operator you learned previously, to see if the input is equal to the number we have defined. We have effectively controlled the flow of the program by setting conditionals in an `if` statement. Nice work!

The examples below are all valid Ruby conditionals.

``````# Example 1
if x == 3
puts "x is 3"
end

# Example 2
if x == 3
puts "x is 3"
elsif x == 4
puts "x is 4"
end

# Example 3
if x == 3
puts "x is 3"
else
puts "x is NOT 3"
end

# Example 4: must use "then" keyword when using 1-line syntax
if x == 3 then puts "x is 3" end
``````

Last, because Ruby is such an expressive language, it also allows you to append the `if` condition at the very end. Example 1 from above could be rewritten like this:

``````puts "x is 3" if x == 3
``````

Ruby also has a reserved word, `unless`. It acts as the opposite of `if`, so you can use it like this:

``````puts "x is NOT 3" unless x == 3
``````

## Comparisons

Let's go over these comparison operators in a little more depth so you can build some more complicated conditional statements. One thing to remember is that comparison operators always return a boolean value. A boolean value is either `true` or `false`, nothing else. We'll try them out in irb to see how they work as well.

1. `<` - The "less than" symbol. Anything to the left of the symbol has a lower value than anything to the right of the symbol.

2. `>` - The "greater than" symbol. Anything to the left of the symbol has a higher value than anything to the right of the symbol.

``````# Example using 'less than' and 'greater than'

irb :001 > 4 < 5
=> true

irb :002 > 4 > 5
=> false
``````
3. `<=` - The "less than or equal to" symbol. Anything to the left of the symbol is less than or equal to anything on the right.

4. `>=` - the "greater than or equal to" symbol. Anything to the left of the symbol is greater than or equal to anything on the right.

``````irb :001 > 4 <= 5
=> true

irb :002 > 5 >= 5
=> true

irb :003 > 4 >= 5
=> false

irb :004 > 4 >= 3
=> true

irb :005 > 4 >= 4
=> true
``````
5. `==` - The "is equal to" operator. Anything to the left of the symbol is exactly equal to anything on the right. We talked about this operator earlier in our chapter on variables so it shouldn't be totally foreign.

``````irb :001 > 5 == 5
=> true

irb :002 > 5 == 6
=> false

irb :003 > '5' == 5
=> false
``````

We threw that last one in as a reminder that when you are comparing for equality you must be comparing two of the same type or you will always get a `false` boolean value.

6. `!=` - The "not equal to" operator. Anything to the left of the symbol is not equal to anything to the right.

``````irb :001 > 4 != 5
=> true

irb :002 > 4 != 4
=> false

irb :003 > 4 != 156
=> true
``````

## Combining Expressions

OK, you're starting to get a decent grasp of conditional flow. It is also possible to combine multiple conditional expressions together to create a more specific scenario. We can do this using the `&&` and `||` operators. Let's see what they mean.

1. `&&` - the "and" operator. Expressions to the left and to the right of this operator have to be both true for the entire expression to be evaluated to true.

``````irb :001 > (4 == 4) && (5 == 5)
=> true

irb :002 > (4 == 5) && (5 == 5)
=> false

irb :002 > (4 == 5) && (5 == 6)
=> false
``````
2. `||` - the "or" operator. Either the expression to the left has to be true, or the expression to the right has to be true for the entire expression to be evaluated to true.

``````irb :001 > (4 == 4) || (5 == 5)
=> true

irb :002 > (4 == 5) || (5 == 5)
=> true

irb :002 > (4 == 5) || (5 == 6)
=> false
``````
3. `!` - the "not" operator. When you add this in front of a boolean expression it will change that boolean value to its opposite.

``````irb :001 > !(4 == 4)
=> false
``````

What happens here is Ruby first evaluates what is in the parentheses and then the `!` operator changes it. We know that `4 == 4` would return true. If we say `!true` then that returns false. You can think of `!true` as saying "not true".

Note: When you are combining expressions as we are above, it is helpful to use parentheses to group expressions together. This is helpful for readability and also helps the computer more accurately understand your intention. The computer will evaluate parentheses in normal algebraic order.

Ruby follows an order of precedence when deciding how to evaluate multiple expressions. The following is a list of operations from highest order of precedence (top) to lowest (bottom).

1. `<=`, `<`, `>`, `>=` - Comparison
2. `==`, `!=` - Equality
3. `&&` - Logical AND
4. `||` - Logical OR

Knowing this, we can look at the following expression and see how it is evaluated.

``````if x && y || z
# do something
end
``````

First the `x && y` statement will be executed. If that statement is true, then the program will execute the `# do something` code on the next line. If the `x && y` statement is false, then the `z` will be evaluated. If the `z` is true, the code on the next line will be evaluated. If the `z` is false, then the code will exit the `if` statement.

## Ternary Operator

Ruby has a nice option for short and concise conditional `if` statements. The ternary operator is a common Ruby idiom that makes a quick `if/else` statement easy and keeps it all on one line.

The ternary operator uses a combination of the `?` and `:`.

``````# Ternary operator example

irb :001 > true ? "this is true" : "this is not true"
=> "this is true"

irb :001 > false ? "this is true" : "this is not true"
=> "this is not true"
``````

How does this work? You may have inferred that first the computer evaluates what is to the left of the `?`. If the expression to the left of `?` is true, the code directly to the right of the `?` gets executed. If the code on the left of the `?` is false, then the code directly to the right of the `:` gets executed.

Ternary operators definitely come in handy as you start to get more familiar with `if` statements. If you feel like you are unsure of how this works, play around with it in irb and test some other cases out. Nothing can create familiarity more quickly than good ol' repeated exposure and experimentation.

## Case Statement

The final conditional flow structure that we want to talk about is called a case statement. A case statement has similar functionality to an `if` statement but with a slightly different interface.

Case statements use the reserved words `case`, `when`, `else`, and `end`. You create one by first defining a case and then evaluating the value of the case and what operation to complete if that case is true. As always, talking about this stuff is much harder than simply observing how the code behaves. Let's create a file called `case_statement.rb` to play with some case statements and see how they work.

``````# case_statement.rb

a = 5

case a
when 5
puts "a is 5"
when 6
puts "a is 6"
else
puts "a is neither 5, nor 6"
end
``````

This example is roughly equivalent to the following `if/elsif/else` statement:

``````# if_statement.rb

a = 5

if a == 5
puts "a is 5"
elsif a == 6
puts "a is 6"
else
puts "a is neither 5, nor 6"
end
``````

The chief differences are that we only need to specify the variable we want to test once (as the argument to `case`) and we don't specify `a ==` on the individual `when` statements.

You can also save the result of a case statement into a variable. Let's refactor the code above to do just that. This way we don't have to write `puts` so many times.

``````# case_statement.rb <-- refactored

a = 5

when 5
"a is 5"
when 6
"a is 6"
else
"a is neither 5, nor 6"
end

``````

There's a second form of the `case` statement that doesn't take an argument:

``````# case_with_no_arg_statement.rb

a = 5

case
when a == 5
puts "a is 5"
when a == 6
puts "a is 6"
else
puts "a is neither 5, nor 6"
end
``````

The difference here is that we don't provide an argument on line 5, and we have to fully test each value with `a ==`; most developers prefer to use `if/elsif/else/end` instead, but there are situations where this form is preferred. We won't get into that here.

As you can see, there are lots of uses for `case` statements and they can be very powerful tools when writing Ruby programs. Remember, if you're uncomfortable with these, spend some time modifying them and watching how they respond to the changes you make. Test their boundaries to see what they are capable of. Curiosity will serve you well in your journey to learning Ruby. There is much to discover!

## True and False

Notice that after `if` and `elsif` we have to put an expression that evaluates to a boolean value: `true` or `false`. In Ruby, you could even write code like this:

``````a = 5
if a
puts "how can this be true?"
else
puts "it is not true"
end
``````

The output is "how can this be true?". In Ruby, every expression evaluates to `true` when used in flow control, except for `false` and `nil`. Try the code above and give `a` values of 0, ""(empty string) and even the string 'false' to see the result yourself!

Because of this, we could even write code like this:

``````if x = 5
puts "how can this be true?"
else
puts "it is not true"
end
``````

The above code is not testing whether `x` is equal to "5". It's assigning the variable `x` the value of "5", which will always evaluate to `true`. Unfortunately, that looks very similar to `if x == 5`, which is testing whether `x` is equal to "5". Be careful when reading or writing Ruby; its expressiveness can also be a source of many subtle bugs.

## Summary

This chapter covered booleans, comparisons and the ability to control the flow of code execution with conditionals. These are some of the fundamental tools that you'll carry with you as a Ruby developer. We've got more exercises to drill these skills into your head and fingers!

## Exercises

1. Write down whether the following expressions return `true` or `false`. Then type the expressions into `irb` to see the results.

``````(32 * 4) >= 129
false != !true
true == 4
false == (847 == '874')
(!true || (!(100 / 5) == 20) || ((328 / 4) == 82)) || false
``````

1. false
2. false
3. false
4. true
5. true

#### Video Walkthrough 2. Write a method that takes a string as argument. The method should return a new, all-caps version of the string, only if the string is longer than 10 characters. Example: change "hello world" to "HELLO WORLD". (Hint: Ruby's String class has a few methods that would be helpful. Check the Ruby Docs!)

#### Solution

``````# caps_method.rb

def caps(string)
if string.length > 10
string.upcase
else
string
end
end

puts caps("Joe Smith")
puts caps("Joe Robertson")
``````

#### Video Walkthrough 3. Write a program that takes a number from the user between 0 and 100 and reports back whether the number is between 0 and 50, 51 and 100, or above 100.

#### Solution

``````# evaluate_num.rb

puts "Please enter a number between 0 and 100."
number = gets.chomp.to_i

if number < 0
puts "You can't enter a negative number!"
elsif number <= 50
puts "#{number} is between 0 and 50"
elsif number <= 100
puts "#{number} is between 51 and 100"
else
puts "#{number} is above 100"
end
``````

#### Video Walkthrough 4. What will each block of code below print to the screen? Write your answer on a piece of paper or in a text editor and then run each block of code to see if you were correct.

``````# Snippet 1
'4' == 4 ? puts("TRUE") : puts("FALSE")
``````
``````# Snippet 2
x = 2
if ((x * 3) / 2) == (4 + 4 - x - 3)
puts "Did you get it right?"
else
puts "Did you?"
end
``````
``````# Snippet 3
y = 9
x = 10
if (x + 1) <= (y)
puts "Alright."
elsif (x + 1) >= (y)
puts "Alright now!"
elsif (y + 1) == x
puts "ALRIGHT NOW!"
else
puts "Alrighty!"
end
``````

#### Solution

1. `"FALSE"`
2. `"Did you get it right?"`
3. `"Alright now!"`

#### Video Walkthrough 5. When you run the following code...

``````def equal_to_four(x)
if x == 4
puts "yup"
else
puts "nope"
end

equal_to_four(5)
``````

You get the following error message..

``````exercise.rb:8: syntax error, unexpected end-of-input, expecting keyword_end
``````

Why do you get this error and how can you fix it?

#### Solution

You get this error because the `end` in the code above gets matched with the `if..else` statement. The error message is telling us that the interpreter was expecting the keyword `end` to close off our `equal_to_four` method, that `end` was not found.

#### Video Walkthrough  