# Class equality with coercion

I created this class based on predefined tests

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

but I'm still failing this one

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

The problem is, that res is "kind of" Fixnum. How's that possible? How to make it pass the test?

## Answers

The problem is that 6 - Roman.new(1) is the same as 6.-(Roman.new(1)) i.e. it is calling the built in subtraction method of Fixnum. Since Fixnum doesn't know about your Roman class, this calls your coerce method.

But you defined coerce to return a Fixnum in this case! The solution is to coerce the other operand, rather than self.

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

But if you try this with your code, you'll get a stack error! That's because it's now coercing both operands into instances of Roman and it still doesn't know how to subtract them. You should redefine your subtraction method to handle those cases.

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