Ruby on rails 干掉这个ruby代码的最好方法是什么?

Ruby on rails 干掉这个ruby代码的最好方法是什么?,ruby-on-rails,ruby,dry,Ruby On Rails,Ruby,Dry,我想擦干这段代码。在rails中使用before_action方法是最好的解决方案吗 class Direction attr_accessor :dir def initialize(dir) @dir = dir end DIRECTIONS = %w[N E S W] def turn_left d = DIRECTIONS.find_index(dir) @dir = DIRECTIONS.rotate!(d-1

我想擦干这段代码。在rails中使用before_action方法是最好的解决方案吗

class Direction
    attr_accessor :dir

    def initialize(dir)
     @dir = dir
    end

    DIRECTIONS = %w[N E S W]

    def turn_left
     d = DIRECTIONS.find_index(dir)
     @dir = DIRECTIONS.rotate!(d-1).first
    end

    def turn_right
     d = DIRECTIONS.find_index(dir)
     @dir = DIRECTIONS.rotate!(d+1).first
    end
end
你可以:

  • 冻结
    常数以避免修改
  • 如果常量未在
    方向
    类之外使用,请更改其可见性
  • 如果只在类本身中使用
    dir
    ,请更改其可见性
  • 创建一个
    OPERATIONS
    hash,它定义了返回下一个方向的方向和操作
  • 迭代
    操作
    键,动态定义方法
    左转
    右转
  • 定义一个
    direction\u index
    方法,该方法使用
    dir
    返回
    DIRECTIONS
    中的索引
  • 定义一个转弯方法,该方法接收一个
    操作
    参数:
    • 使用
      operation
      可以从
      OPERATIONS
      获取操作,该操作告诉您如何旋转(正旋转或负旋转)
    • 将方法
      -
      +
      应用于
      方向索引的结果,可以得到要旋转的参数
    • 然后调用
      DIRECTIONS
      上的
      rotate
      ,并获取第一个元素

您始终可以实施独立于状态的方向图:

class DirectionMap
  def initialize(*list)
    # Create a Hash mapping table with left and right directions
    # pre-computed. This uses modulo to "wrap" the array around.
    @directions = list.map.with_index do |dir, i|
      [ dir, [ list[(i - 1) % list.length], list[(i + 1) % list.length] ] ]
    end.to_h
  end

  # These methods use dig to avoid blowing up on an invalid direction,
  # instead just returning nil for garbage input.
  def left(dir)
    @directions.dig(dir, 0)
  end

  def right(dir)
    @directions.dig(dir, 1)
  end
end
您现在可以在其中导航任意指南针映射:

map = DirectionMap.new(*%w[ N E S W ])

map.left('N') # => 'W'
map.left(map.left('N')) # => 'S'

map.right('N') # => 'E'
map.right(map.left('N')) # => 'N'

因此,您也可以执行
%w[N NE E SE S SW w NW]

我建议使用哈希,主要是为了可读性

class Direction
  NEXT_LEFT  = { 'N'=>'W', 'W'=>'S', 'S'=>'E', 'E'=>'N' }
  NEXT_RIGHT = NEXT_LEFT.invert

  attr_reader :dir

  def initialize(dir)
    @dir = dir
  end

  def turn_left
    turn(NEXT_LEFT)
  end

  def turn_right
    turn(NEXT_RIGHT)
  end

  private

  def turn(nxt)
    @dir = nxt[@dir]
  end
end

注:


有很多很好的答案,但一个简单的直接解决方案是将两种方法中常见的部分分解成一个turn方法,然后传入
1
-1

class Direction
  attr_accessor :dir

  def initialize(dir)
    @dir = dir
  end

  DIRECTIONS = %w[N E S W]

  def turn(delta_d)
    d = DIRECTIONS.find_index(dir)
    @dir = DIRECTIONS.rotate!(d + delta_d).first
  end

  def turn_left
    turn(-1)
  end

  def turn_right
    turn(1)
  end

end

我认为,您可以避免每次打开时创建新阵列的所有工作(通过调用
rotate
)。只需将当前方向存储为其字母在数组中的索引。旋转只是索引上的模运算(注意在Ruby中为-1%4==3)。当需要方向的字母时,只需使用索引从数组中获取它

类方向
方向=%w[N东S西]。冻结
def初始化(dir)
self.dir=dir
结束
#迪尔盖特
def目录
方向[@dir_索引]
结束
#定向器
def dir=(dir)
@dir\u index=方向索引(dir)
结束
#转向逻辑
def转弯(三角洲)
@dir_index=(@dir_index+delta)%DIRECTIONS.size
迪尔
结束
左转
转弯(-1)
结束
右转
转弯(1)
结束
结束
p方向。新('N')。左转#=>“W”
p方向。新建('E')。左转#=>“N”
p方向。新建('S')。左转#=>“E”
p方向。新建('W')。向左拐#=>“S”
p方向。新('N')。右转#=>“E”
p方向。新建('E')。右转#=>“S”
p方向。新('S')。右转#=>“W”
p方向。新('W')。右转#=>“N”

一些控制器代码会很有用。将状态与方向概念分开可能更有意义。这种方法将两件事混为一谈,即基本方向的定义和方向状态的存储。您可以使用
dir
而不是
@dir
来简化方法,因为您有
attr\u访问器:dir
“是否可以像在rails中那样在ruby中实现?”?你知道Rails是Ruby代码,对吧?所以,当然有可能。调用
rotate修改您的
方向
常量所指的数组。不要这样做-常量不应该是偶然的。好的和简单的,使它非常自我记录!我会给你的代码的答案,因为它是尽可能干燥。我可能还会添加一个
掉头
方法。:-)
d = Direction.new('N')
d.dir
  #=> "N" 
d.turn_left
  #=> "W" 
d.turn_left
  #=> "S" 
d.turn_right
  #=> "W" 
NEXT_RIGHT
  #=> {"W"=>"N", "S"=>"W", "E"=>"S", "N"=>"E"}
class Direction
  attr_accessor :dir

  def initialize(dir)
    @dir = dir
  end

  DIRECTIONS = %w[N E S W]

  def turn(delta_d)
    d = DIRECTIONS.find_index(dir)
    @dir = DIRECTIONS.rotate!(d + delta_d).first
  end

  def turn_left
    turn(-1)
  end

  def turn_right
    turn(1)
  end

end