4.2. Conditionals

Ruby offers several conditional statements and control structures for managing the flow of your applications. In the previous chapter you had a sneak peak at the if and for statements; here they are introduced more formally, among others useful statements.

4.2.1. if / elsif / else / unless

The following illustrates the usage of the if conditional statement in Ruby:

if temperature < 0
  puts "Freezing!"
end

Visual Basic programmers will find this syntax quite natural, and it shouldn't be too foreign to C# programmers either.

Any code between the if and the end line is executed unless the tested expression evaluates to false or nil. The if statement also accepts the then token separator (as opposed to the newline alone), so you could have written the same code as follows:

if (temperature < 0) then
  puts "Freezing!"
end

Parenthesis around expressions within conditional statements are optional in Ruby, but it may not be a bad idea to include them when they're helpful in clarifying the meaning of the code. Or even as a single line:

if temperature < 0 then puts "Freezing!" end

Ruby 1.8 allows semicolons as token separators as well, but Ruby 1.9 doesn't.

Listing 4-1 shows a recursive version of the factorial in Ruby.

Example 4.1. Naïve Factorial in Ruby
# Naive, recursive implementation of the factorial in Ruby

def fact(n)
  if n <= 1
    1
  else
    n * fact(n-1)
  end
end

n = (ARGV[0] || 10).to_i
puts fact(n)

Copy the code into a fact.rb file (or whatever you wish to call it), and then run ruby fact.rb. The result should be 3628800, which is the factorial of 10. You can also pass an argument to the program by running (for example) ruby fact.rb 5, obtaining 120.

Line 11 shows you a little trick: n = (ARGV[0] || 10).to_i. ARGV is an array of arguments passed to the program, so ARGV[0] retrieves the first argument as a string or nil if no arguments were passed. ARGV[0] || 10 returns the first argument if different than nil or 10 if nil. The result is then converted to an integer (because ARGV[0] is a string when it exists). This idiom is an easy way to specify a default number when no arguments are passed to the program, while still accepting an argument from the user.

Ruby also offers the possibility of using the if statement as an expression modifier. So you can rewrite the line from the earlier example as:

puts "Freezing!" if temperature < 0

This notation offers a clear gain in readability for simple one-liners (try reading it out loud), but for non-trivial statements it's far better to use the "traditional" multiple-line if.

if statements may also include the optional elsif and else clauses using the following syntax:

if expression1
  code
elsif expression2
  code
elsif expression3
  code
else
  code
end

From now on, in these snippets, code is used as a single, generic term that indicates one or more lines of code.

There can be several elsif clauses but only one final else. Please pay attention to the peculiar syntax of the elsif clause. It's not ElseIf of VB, nor else if of C#.

Perhaps surprisingly, Ruby also offers an unless statement:

unless sold_out
  place_order
end

As you can imagine, unless is the opposite of if, and the preceding code delimited within unless and end is executed only when the condition tested is nil or false. unless can also be used as an expression/statement modifier:

place_order unless sold_out

unless supports an else clause, but unlike the if statement, it doesn't accept elseif clauses. Depending on the situation, you may opt for if or prefer unless; Ruby provides both for the sake of convenience and readability.

Though if and unless have been viewed as "statements" so far, in Ruby there's a twist: they too are expressions. Unlike C# and VB, in Ruby everything is an expression, so even if and unless return values. If you run the following snippet, the variable state is set to the returning value of the if expression, in this particular case "Gas," before being printed to the console:

h2o_temp = 130

state = if h2o_temp < 0
  "Solid"
elsif h2o_temp > 100
  "Gas"
else
  "Liquid"
end

puts state

4.2.2. The Ternary Operator

Like C#, and many other C-derived languages, Ruby also supports the ternary operator. The ?: operator returns the first value unless the condition is false or nil, in which case the second value is returned:

value = condition ? val1 : val2

The preceding line is a much more succinct way of writing the following if statement:

value = if condition
  val1
else
  val2
end

For example, you could write:

ticket = (age < 18) ? "child" : "adult"

4.2.3. The case Statement

In most languages, whenever you need to verify multiple conditions, you'd employ the "switch" statement. Ruby calls it the case statement and it's far closer to what Visual Basic developers — as opposed to C# ones — are accustomed to. That said, Ruby's case statement is much more powerful than what you may expect at first.

There are two ways of using the statement. The first, without passing an argument, is equivalent to using an if statement with a series of elsif clauses:

case
  when condition1
    code
  when condition2
    code
  when condition3
    code
  when condition4
    code
  else
    code
end

And the second, which passes an argument:

case expression
  when value1
    code
  when value2
    code
  when value3
    code
  when value4
    code
  else
    code
end

In both usages, the case statement can have multiple when clauses, and an optional else clause for code that should be executed if no other previous condition has been successful. This is equivalent to the default clause in C# and the Case Else in VB.NET.

Please note that case has no fall-through behavior, so if one of the conditions is met, no other attempts to evaluate other conditions are carried out by the interpreter. This implies that, just as in VB.NET, there's no need for break statements of any sort. Still similarly to Visual Basic, it is possible to combine multiple conditions on the same line by separating them with a comma:

case expression
  when value1, value, value3
    code
  when value4, value5
    code

when value6, value7, value8
    code
  when value9
    code
  else
    code
end

Just like if and unless, the case statement returns the last evaluated expression if any code is executed, or nil if no condition was successful and no else clause was defined. Conversely, like if and unless, the when clause supports the then token separator as well.

The case statement in Ruby is very powerful because it's able to use not only integers, strings, or what other languages consider "primitive types," but any type of expression, even when the value is determined during runtime. What's more, it works by using the so-called "case equality" operator (that is, ===). Though several classes make no distinction between this operator and the simple equality one (that is, ==), many classes implement the case equality operator in a somewhat intuitive and logical manner. The class Regexp implements the === operator to check if there is a match for the given pattern, whereas the Range class implements it in order to check whether the element is contained within the given range, and so forth. For example, the following snippet prints "Senior" to the console.

age = 85

puts case age
       when 0..12 then "Child"
       when 13..19 then "Teenager"
       when 20..65 then "Adult"
       else "Senior"
     end

Another common idiom takes advantage of the equality operator implemented by the Class class. This verifies that the given expression is an instance of the specified class:

Numeric === 3        # true
String === "Rails"   # true
Array === {}         # false, because an empty hash is not an instance of Array

Within the context of the case statement, you could then write the following:

case my_expression
  when Numeric
    # Handle number
    code
  when String
    # Handle String
    code
  when Array
    # Handle Array
    code
  when Hash
    # Handle Hash
    code

when TrueClass, FalseClass
    # Handle Boolean
    code
  else
    # Handle any other type
    code
end

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.21.46.92