Reputation: 238777
I would like to simplify my code that performs a single action when multiple conditions apply. Here's a simplified example:
case button
when 'up', 'upper-right', 'right', 'lower-right', 'down', 'lower-left', 'left', 'upper-left'
move_direction(button)
else
do_something_else
end
If I could encapsulate those options into something like a class or a constant, that would be helpful, but I'm not sure how to do that or if it's even possible. How can I encapsulate these conditions?
Upvotes: 3
Views: 146
Reputation: 10359
The solution below isn't particularly sophisticated, but it's arguably more readable than the original case statement.
def is_navigatable?(button)
['up',
'upper-right',
'right',
'lower-right',
'down',
'lower-left',
'left',
'upper-left'
].member? button
end
def main_method
if is_navigatable? button
move_direction button
else
do_something_else
end
end
Upvotes: 3
Reputation: 168131
In your particular case, you can also do this:
case button
when "up", "down", /\A(?:upper-|lower-|)(?:right|left)\z/
move_direction(button)
else
do_something_else
end
Upvotes: 0
Reputation: 42192
The fastest way will be using a set
require 'set'
def direction?(button)
directions = Set[:up,
:'upper-right',
:right,
:'lower-right',
:down,
:'lower-left',
:left,
:'upper-left']
directions.include?(button)
end
button = 'up'
puts direction?(button.to_sym) #true
Upvotes: 0
Reputation: 76250
If I could encapsulate those options into something like a class or a constant, that would be helpful, but I'm not sure how to do that or if it's even possible. How can I encapsulate these conditions?
Why not simply refactor that code to drop the case-while
condition and simply use if-else
instead (since you don't seem to be using other options):
OPTIONS = 'up', 'upper-right', 'right', 'lower-right', 'down', 'lower-left', 'left', 'upper-left'
if OPTIONS.include? button
move_direction(button)
else
do_something_else
end
Upvotes: 1
Reputation: 62658
You can just use an array splat.
VALID_DIRECTION = %w( upper-left up upper-right left right
lower-right down lower-left )
case button
when *VALID_DIRECTION
move_direction(button)
else
do_something_else
end
Upvotes: 7
Reputation: 198388
Not quite sure what you're looking for, but maybe something like this?
class CaseMatchingArray < Array
def ===(element)
self.include?(element)
end
end
direction = CaseMatchingArray.new([
'up', 'upper-right', 'right', 'lower-right',
'down', 'lower-left', 'left', 'upper-left'])
case 'up'
when direction
puts "Yup, it's a direction"
end
Remember that the Ruby case
statement applies the ===
operator, and you can do whatever test you wish by matching against things that implement it. If you remember that Proc
also implements ===
as a call, you could do:
direction = lambda { |x|
[
'up', 'upper-right', 'right', 'lower-right',
'down', 'lower-left', 'left', 'upper-left'
].include?(x)
}
and have the same result, without defining a class. Or you could even do it in a singleton:
direction = [
'up', 'upper-right', 'right', 'lower-right',
'down', 'lower-left', 'left', 'upper-left'
]
def direction.===(other)
self.include?(other)
end
EDIT: or what Chuck says :) Although, implementing objects that define ===
is more general, not limited to just membership of arrays.
Upvotes: 4