是否有用于比较红宝石中潜在的无对象的模式?

时间:2017-06-24 19:17:47

标签: ruby null

我需要比较潜在的nil个对象。例如,

Foo.new(Date.new) < Foo.new(nil)
  # => true

Foo.new(nil) < Foo.new(Date.new)
  # => true

class Foo 
  attr_accessor :time
  def initialize(time)
    @time = time
  end

  def <=>(other)
    # I don't know what to do here.
  end
end

是否有解决此类问题的模式?

2 个答案:

答案 0 :(得分:3)

您可以定义Foo#to_f方法:

  • 如果定义了@time,则返回@time.to_f
  • 如果@time为零,则返回负无穷大

这样,Foo.new(nil)小于任何其他Foo

require 'date'
class Foo
  attr_accessor :time
  include Comparable
  def initialize(time)
    @time = time && time.to_time # time can be nil, a Date or a Time
  end

  def to_f
    @time ? @time.to_f : -Float::INFINITY
  end

  def <=>(other)
    to_f <=> other.to_f
  end

  def to_s
    @time ? @time.strftime('%Y-%m-%d') : 'nil'
  end

  alias inspect to_s
end

p Foo.new(Date.new) < Foo.new(nil)
# false

p Foo.new(nil) < Foo.new(Date.new)
# true

p [Foo.new(Date.today), Foo.new(nil), Foo.new(Date.new(2015, 3, 1)), Foo.new(Date.new(2018, 5, 14)), Foo.new(Time.now + 3600)].sort
# [nil, 2015-03-01, 2017-06-24, 2017-06-25, 2018-05-14]

使用Null对象模式重构

require 'date'

class NilTime
  def to_f
    - Float::INFINITY
  end

  def strftime(*)
    'nil'
  end
end

class Foo
  attr_accessor :time
  include Comparable
  def initialize(time = nil)
    @time = if time.respond_to?(:to_time)
              time.to_time
            else
              NilTime.new
            end
  end

  def to_f
    @time.to_f
  end

  def <=>(other)
    to_f <=> other.to_f
  end

  def to_s
    @time.strftime('%Y-%m-%d')
  end

  alias inspect to_s
end

答案 1 :(得分:1)

另一种方式

nil.to_i为0

    nil_obj.to_i < date_obj.to_i

    Foo.new(nil.to_i) < Foo.new(Date.to_i) # true