自定义range对象

ruby 中有个 range 对象,可以自动推测范围内的数据,比如:

(1..100).each do |i|
  puts i
end

会输出 1 到 100 内的所有数字

自定义

如果我们有一个自定义的对象,假如名字为Ym

class Ym
  attr_accessor :year, :month
  def initialize
    @year, @month = year, month
  end
end

若是想在Ym上使用((Ym.new(2009,1))..(Ym.new(2010,1))).each {|i| puts i},输出的结果按照正常的年月逻辑来显示,该如何实现呢?

其实要实现类似(1..100)的方法很容易,只需在该类中include Compareable然后实现 succ<=>方法就行了。

class Ym
  include Comparable
  attr_accessor :year, :month

  def initialize(year, month)
    @year, @month = year, month
  end

  def succ
    #如果月份满12,则年份增加一,月份再从一开始。
    # 可以按需求定制更复杂的推测方法
    yyy, mmm = @month == 12 ? [@year + 1, 1] : [@year, @month + 1]
    Ym.new(yyy, mmm)
  end

  def <=>(other)
    # 定义大小规则
    (@year * 12 + @month) <=> (other.year * 12 + other.month)
  end

  def to_s
    sprintf "%4d-%02d", @year, @month
  end
end

(Ym.new(2008,8)..(Ym.new(2019,9))).each do |y|
  puts y
end

结果如图: