Let's first examine why you are obtaining incorrect results.
If a
equals false
or nil
(is falsy, meaning logically false
), a or b
returns the value of b
. If a
equals any other value (is truthy, meaning logically true
), a or b
returns a
.
Suppose we have an expression a op1 b op2 c
, where op1
and op2
are operators (e.g., a == b or c
). This could be evaluated (a op1 b) op2 c
or a op1 (b op2 c)
, where parentheses have the highest precedence.
The precedence of Ruby's operators (most implemented as methods) is given here. Note that ==
has higher precedence than or
. Moreover, for any given operator op
, a op b op c
is evaluated (a op b) op c
.
The expression num == 1 or 2 or 3
is therefore evaluated
((num == 1) or 2) or 3
Now consider the value of this expression, depending on the value of num
.
num = 1
((num == 1) or 2) or 3 => (true or 2) or 3 => true or 3 => true
num != 1
((num == 1) or 2) or 3 => (false or 2) or 3 => 2 or 3 => 2
Here are some ways to obtain your desired result.
(num == 1) or (num == 2) or (num == 3)
(num == 1) || (num == 2) || (num == 3)
[1, 2, 3].include?(num)
[1, 2, 3] & [num] == [num]
([num] - [1, 2, 3]).empty?
Because of the precedence rules for operators, the parentheses are not needed in the first two expressions, but it can be argued they clarify the code, at least for some readers. (I would include them.)
Regarding the choice between using or
or ||
, see this SO queston, particularly the second answer. In practice, or
is rarely used.
See Array#include?, Array#& and Array#-.
To round out the possibilities, one could conceivably use a case statement.
case num
when 1, 2, 3 then true
else false
end
If, as here, the acceptable values of num
form a range, one could write either of the following.
num.between?(1, 3)
(1..3).cover?(num)
(num >= 1) && (num <= 3)
See Comparable#between and Range#cover?. Again, the parentheses in the latter are optional.