阶级平等与强制

时间:2014-01-31 13:32:08

标签: ruby equality

我是根据预定义的测试创建了这个类

class Roman
  include Comparable
  ROMAN_NUMBERS = { 1000 => "m", 900 => "cm", 500 => "d", 400 => "cd", 
      100 => "c", 90 => "xc", 50 => "l", 40 => "xl", 10 => "x", 9 => "ix", 
      5 => "v", 4 => "iv", 1 => "i" }

  def initialize(number)
    @number = number
  end

  def coerce(other)
    if Integer === other
      [ other, @number ]
    else
      [ Float(other), Float(@number) ]
    end
  end

  def <=>(n)
    @number <=> n
  end

  def -(n)
    Roman.new(@number - n)
  end 

  def to_s
    roman = ''
    ROMAN_NUMBERS.each do |value, letter|
      roman << letter * (@number / value)
      @number = @number % value
    end
    roman
  end
end

但我还是失败了

it "should support substraction" do
  (Roman.new(5) - Roman.new(3)).should == 2
  (Roman.new(4) - Roman.new(1)).should == 3
  (Roman.new(4) - 2).should == 2
  res = 6 - Roman.new(1)
  res.should == 5
  (res.kind_of? Roman).should be true
end

问题是,res是“有点”Fixnum。怎么可能?如何通过测试?

1 个答案:

答案 0 :(得分:2)

问题是6 - Roman.new(1)6.-(Roman.new(1))相同,即它正在调用Fixnum的内置减法方法。由于Fixnum不了解您的Roman课程,因此会调用您的coerce方法。

但是你定义coerce在这种情况下返回Fixnum!解决方案是强制使用另一个操作数,而不是self

def coerce other
  [self.class.new(other), self]
end

但是如果你用你的代码尝试这个,你会得到一个堆栈错误!那是因为它现在将两个操作数强制转换为Roman的实例,但它仍然不知道如何减去它们。你应该重新定义你的减法方法来处理这些情况。

attr_reader :number
def - n
  return Roman.new(@number - n.number) if n.is_a? Roman
  Roman.new(@number - n)
end