I have been biten by this (and other) unexpected implicit #to_i
call(s) myself. OO-philospical issuses about the validity of adding a
RomanInteger class to the Numeric class hierachie aside, if you are
willing to beat the barbwires around extending the Integer class you
can construct such a RomanInteger class as a subclass of Integer. 
(The script probably requires 1.7)


------------
class Integer
  class << self
    def new; "dummy for undef" end
    def allocate; "dummy for undef" end 
    undef_method :new
    undef_method :allocate
    def new (*bla,&b) ; super (*bla,&b)  end
    def allocate; super end
  end
end

class Fixnum
  class << self
    undef_method :new
    undef_method :allocate
  end
  def to_rint; RomanInteger.new self end 
end

class Bignum
  class << self
    undef_method :new
    undef_method :allocate
  end
end

class RomanInteger < Integer
 Max=4999
 def initialize a
    raise ArgumentError unless a.kind_of?(Fixnum) and (0 < a) and (a
<= Max)
    @rep = a
 end
 def <=>(other); @rep <=> other.rep end
 def +(other)
  if other.kind_of? Fixnum
    return  RomanInteger::new @rep + other
  else
    raise ArgumentError
  end
 end
 def -(other)
  if other.kind_of? RomanInteger
    return @rep - other.rep
  else
    raise ArgumentError
  end
 end
 def coerce(other);[self,other] end
 def inspect
   case @rep
    when 1 then 'I'
    when 2 then 'II'
    when 3 then 'III'
    when 4 then 'IV'
    when 5 then 'V'
    when 6 then 'VI'
    else raise 'needs more work'
   end
 end         
 protected
 attr_reader :rep
end

r1 = 1.to_rint
r10 = 10.to_rint
p (r6 = -4 + r10) # => VI 
p (r5 = r1 + 4)   # => V
p (r5 - r6)       # => -1

(r1..r5).each do |r|  p r end