如何在单个对象中封装许多Ruby案例条件?

时间:2013-08-14 04:51:50

标签: ruby

我希望简化在多个条件适用时执行单个操作的代码。这是一个简化的例子:

case button
when 'up', 'upper-right', 'right', 'lower-right', 'down', 'lower-left', 'left', 'upper-left' 
  move_direction(button)
else
  do_something_else
end

如果我可以将这些选项封装成类或常量之类的东西,那将会有所帮助,但我不知道该怎么做或者甚至可能。我怎样才能封装这些条件?

6 个答案:

答案 0 :(得分:7)

你可以使用数组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

答案 1 :(得分:4)

不太确定你在寻找什么,但也许是这样的?

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

请记住,Ruby case语句应用===运算符,您可以通过匹配实现它的内容来执行您希望的任何测试。如果您还记得Proc也实施了===作为通话,您可以这样做:

direction = lambda { |x|
  [
    'up', 'upper-right', 'right', 'lower-right',
    'down', 'lower-left', 'left', 'upper-left'
  ].include?(x)
}

并且在没有定义类的情况下具有相同的结果。或者你甚至可以用单身人士来做这件事:

direction = [
    'up', 'upper-right', 'right', 'lower-right',
    'down', 'lower-left', 'left', 'upper-left'
]
def direction.===(other)
  self.include?(other)
end

编辑:或者Chuck说的:)虽然实现定义===的对象更为通用,但不仅限于数组的成员资格。

答案 2 :(得分:3)

下面的解决方案并不是特别复杂,但它可以说比原始案例陈述更具可读性。

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

答案 3 :(得分:1)

  

如果我可以将这些选项封装成类或常量之类的东西,那将会有所帮助,但我不知道该怎么做或者甚至可能。我怎样才能封装这些条件?

为什么不简单地重构该代码以放弃case-while条件而只使用if-else代替(因为您似乎没有使用其他选项):

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

答案 4 :(得分:0)

最快的方法是使用套装

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

答案 5 :(得分:0)

在您的特定情况下,您也可以这样做:

case button
when "up", "down", /\A(?:upper-|lower-|)(?:right|left)\z/
  move_direction(button)
else
  do_something_else
end