LoginSignup
6
4

More than 5 years have passed since last update.

Ruby で季節のような循環する概念を表したい

Last updated at Posted at 2018-11-27

春, 夏, 秋, 冬, 春, 夏, ... のように循環する概念を Ruby で表したい。具体的には

Season.new('春').next #=> #<Season @name="夏">
Season.new('夏').next #=> #<Season @name="秋">
Season.new('秋').next #=> #<Season @name="冬">
Season.new('冬').next #=> #<Season @name="春">

Season.new('春').prev #=> #<Season @name="冬">
Season.new('夏').prev #=> #<Season @name="春">
Season.new('秋').prev #=> #<Season @name="夏">
Season.new('冬').prev #=> #<Season @name="秋">

となるような Season クラスを実装したい。

方法

剰余を使う。

class Season
  attr_reader :name

  NAMES = %w[春 夏 秋 冬].freeze

  def initialize(name)
    raise(ArgumentError) unless NAMES.include?(name)
    @name = name
  end

  def next
    self.class.new(NAMES[(index + 1) % NAMES.length])
  end

  def prev
    self.class.new(NAMES[(index - 1) % NAMES.length])
  end

  private

  def index
    NAMES.index(name)
  end
end

方法 (ボツ)

循環するイテレータを使う。難しく考えすぎていたのでボツ。

class Season
  attr_reader :name

  NAMES = %w[春 夏 秋 冬].freeze

  def initialize(name)
    raise(ArgumentError) unless NAMES.include?(name)
    @name = name
  end

  def next
    seasons = NAMES.cycle
    until seasons.next == name do; end
    self.class.new(seasons.peek)
  end

  def prev
    seasons = NAMES.cycle
    tmp = nil
    loop do
      tmp = seasons.next
      break if seasons.peek == name
    end
    self.class.new(tmp)
  end
end
6
4
6

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
4