unless
Bean Cart should warn the barista when the milk runs low. You could write if !milk_ok, but that little ! is easy to miss when you skim. Ruby has a keyword that reads the way you would say it out loud: "warn, unless the milk is fine".
The rule
unlessisif not; keep it short and never give it anelse.
unless runs its body when the condition is falsy:
unless milk_ok
puts "Order more milk!"
endThat is exactly the same as:
if !milk_ok
puts "Order more milk!"
endIts best use is the modifier form, often as a guard at the start of some code:
puts "Cart is closed" unless open
puts "Out of oat milk" unless stock[:oat_milk] > 0Like if, unless is an expression and returns the value of the body, or nil when the body does not run.
Ruby allows unless ... else ... end, but the result is a double negative that readers must untangle:
# Hard to read: "unless not open... wait"
unless open
puts "Closed"
else
puts "Welcome"
end
# Clear: flip it to an if
if open
puts "Welcome"
else
puts "Closed"
endStyle guides, and tools such as RuboCop, recommend never pairing unless with else. There is also no elsunless.
Avoid negative conditions inside unless as well. unless !sold_out means "if sold out", so write that. The same goes for compound conditions: unless a && b makes readers apply De Morgan's laws in their heads.
The shortcut
Read unless aloud as "if not" and listen. If the sentence sounds natural ("print closed if not open"), keep unless. If it contains "not not", an else, or an and/or, rewrite it as an if.
The original
unless !sold_outfollowed byputs "Order taken".
Drills
Answer fast — trust the rule.
When does the body of unless milk_ok run?
Which is the same as puts "Closed" unless open?
What does unless !sold_out really mean?
What do Ruby style guides say about unless with else?
Remember
unlessisif not; best as a short modifier guard.- Read it aloud as "if not": if you hear a double negative, an else or an and/or, switch to
if. - Trap:
unlesswithelse, or a!inside theunlesscondition.
