# Conditionals, case and Ranges — Ruby

Source: https://www.geekswithgeeks.com/en/ruby/c-control

> Write expressive conditions with if, unless, modifiers, case/when and ranges.

## Expressive control flow

Ruby's `if`, `elsif` and `else` are **expressions** that return a value, so `label = if total > 1000 then "large" else "small" end` works, as does the ternary operator. **`unless`** reads better for negative conditions (`unless order.paid?`), but avoid `unless ... else`. **Statement modifiers** put short conditions at the end of a line: `return if items.empty?` and `send_reminder unless paid`. **`case`/`when`** compares using the **`===`** operator, so `when` clauses can match **ranges** (`when 90..100`), **classes** (`when Integer`), **regular expressions** (`when /\A\d{6}\z/`) and lists of values, and `case` also returns a value. **Ranges** are objects: `1..10` includes the end, `1...10` excludes it, and endless ranges (`18..`) and beginless ranges (`..17`) express open intervals. Loops exist (`while`, `until`, `loop do ... end` with `break`), but idiomatic Ruby iterates with methods such as `each`, `times` and `upto` instead of index-based loops.

## case/when matching with ===

Each when clause asks whether its pattern matches the value: ranges, classes and regexes all work.

![A value token passing a series of differently shaped gates: a bracket range, a class badge and a pattern stencil.](assets/figures/ruby/section-2-map.svg) — Figure 2.1 — case/when dispatching on ranges, classes and patterns.

## case/when, ranges and modifiers

case returns a value, and when clauses use ===.

```ruby
def grade(marks)
  case marks
  when 85..100 then "A"
  when 70...85 then "B"
  when 40...70 then "C"
  when 0...40  then "Fail"
  else "Invalid"
  end
end

def describe(value)
  case value
  when Integer, Float then "number"
  when /\A\d{6}\z/    then "PIN code"
  when String         then "text"
  when nil            then "missing"
  else "something else"
  end
end

puts grade(72)              # B
puts describe("411001")     # PIN code

def ship(order)
  return "Nothing to ship" if order[:items].empty?   # guard clause with a modifier
  "Shipping #{order[:items].size} items"
end

adult = (18..).cover?(25)   # endless range: true
1.upto(3) { |n| puts n }
```

## A sorting machine with smart slots

case/when is a sorting machine where each slot knows how to recognise its items: one slot takes any number between 85 and 100, another takes any text that looks like a PIN code, another takes anything that is a String.

**Quiz:** Which operator does case/when use to compare the value with each when clause?

- [ ] ==
- [ ] equal?
- [x] ===
- [ ] <=>

*Answer:* ===. when clauses call pattern === value, which ranges, classes and regexes implement meaningfully.
