Edited at

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


春, 夏, 秋, 冬, 春, 夏, ... のように循環する概念を 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