Conditional Expressions
Conditional keywords
Never use
then
for multi-lineif/unless
.
[link]# bad
if some_condition then
...
end
# good
if some_condition
...
end
Never use
do
for multi-linewhile
or
until
.[link]# bad
while x > 5 do
...
end
until x > 5 do
...
end
# good
while x > 5
...
end
until x > 5
...
end
The
and
,or
, andnot
keywords are banned. It’s
just not worth it. Always use&&
,||
, and!
instead.
[link]Modifier
if/unless
usage is okay when
the body is simple, the condition is simple, and the whole thing fits on
one line. Otherwise, avoid modifierif/unless
.
[link]# bad - this doesn't fit on one line
add_trebuchet_experiments_on_page(request_opts[:trebuchet_experiments_on_page]) if request_opts[:trebuchet_experiments_on_page] && !request_opts[:trebuchet_experiments_on_page].empty?
# okay
if request_opts[:trebuchet_experiments_on_page] &&
!request_opts[:trebuchet_experiments_on_page].empty?
add_trebuchet_experiments_on_page(request_opts[:trebuchet_experiments_on_page])
end
# bad - this is complex and deserves multiple lines and a comment
parts[i] = part.to_i(INTEGER_BASE) if !part.nil? && [0, 2, 3].include?(i)
# okay
return if reconciled?
Never use
unless
withelse
. Rewrite
these with the positive case first.[link]# bad
unless success?
puts 'failure'
else
puts 'success'
end
# good
if success?
puts 'success'
else
puts 'failure'
end
Avoid
unless
with multiple
conditions.[link]# bad
unless foo? && bar?
...
end
# okay
if !(foo? && bar?)
...
end
Avoid
unless
with comparison operators if you can useif
with an opposing comparison operator.[link]# bad
unless x == 10
...
end
# good
if x != 10
...
end
# bad
unless x < 10
...
end
# good
if x >= 10
...
end
# ok
unless x === 10
...
end
Don’t use parentheses around the
condition of anif/unless/while
.
[link]# bad
if (x > 10)
...
end
# good
if x > 10
...
end
Ternary operator
Avoid the ternary operator (
?:
) except
in cases where all expressions are extremely trivial. However, do use the
ternary operator(?:
) overif/then/else/end
constructs for single line
conditionals.[link]# bad
result = if some_condition then something else something_else end
# good
result = some_condition ? something : something_else
Use one expression per branch in a ternary
operator. This also means that ternary operators must not be nested. Prefer
if/else
constructs in these cases.[link]# bad
some_condition ? (nested_condition ? nested_something : nested_something_else) : something_else
# good
if some_condition
nested_condition ? nested_something : nested_something_else
else
something_else
end
Avoid multiple conditions in ternaries.
Ternaries are best used with single conditions.
[link]Avoid multi-line
?:
(the ternary
operator), useif/then/else/end
instead.
[link]# bad
some_really_long_condition_that_might_make_you_want_to_split_lines ?
something : something_else
# good
if some_really_long_condition_that_might_make_you_want_to_split_lines
something
else
something_else
end
Nested conditionals
Avoid the use of nested conditionals for flow of control.
([More on this][avoid-else-return-early].) [link]Prefer a guard clause when you can assert invalid data. A guard clause
is a conditional statement at the top of a function that returns as soon
as it can.The general principles boil down to:
- Return immediately once you know your function cannot do anything more.
- Reduce nesting and indentation in the code by returning early. This makes
the code easier to read and requires less mental bookkeeping on the part
of the reader to keep track ofelse
branches. - The core or most important flows should be the least indented.
# bad
def compute
server = find_server
if server
client = server.client
if client
request = client.make_request
if request
process_request(request)
end
end
end
end
# good
def compute
server = find_server
return unless server
client = server.client
return unless client
request = client.make_request
return unless request
process_request(request)
end
Prefer
next
in loops instead of conditional blocks.# bad
[0, 1, 2, 3].each do |item|
if item > 1
puts item
end
end
# good
[0, 1, 2, 3].each do |item|
next unless item > 1
puts item
end
See also the section “Guard Clause”, p68-70 in Beck, Kent.
Implementation Patterns. Upper Saddle River: Addison-Wesley, 2008, which
has inspired some of the content above.