Take this spec:
I've reimplemented it here for simplicity:
class Mock
def coerce(x)
[1, 10]
end
end
p 1.fdiv(Mock.new)
That calls fdiv
on a Fixnum
:
def fdiv(other)
self.to_f / other
end
That converts the receiver to a Float
and calls /
. As the RHS is a Mock
the primitive for Float#/
will fail and will call redo_coerced
.
def divide(other)
Rubinius.primitive :float_div
redo_coerced :/, other
end
That calls other.coerce
. Our mock object returns [1, 10]
for this. Then we re-call /
on the first value, with the operand as the right value. That's 1./(10)
. That does integral division.
def math_coerce(other, error=:coerce_error)
begin
values = other.coerce(self)
rescue
if error == :coerce_error
raise TypeError, "#{other.class} can't be coerced into #{self.class}"
else
raise ArgumentError, "comparison of #{self.class} with #{other.class} failed"
end
end
unless Rubinius::Type.object_kind_of?(values, Array) && values.length == 2
raise TypeError, "coerce must return [x, y]"
end
return values[1], values[0]
end
def redo_coerced(meth, right)
b, a = math_coerce(right)
a.__send__ meth, b
end
So why does the test produce a Float
, 0.1
? When I run this code in Truffle I get a Fixnum
, 0
, which makes sense to me reading the code, but it isn't right.