Adding an integer to an object can be achieved by implementing +
, e.g.:
class Foo
def initialize(value)
@value = value
end
def to_i
@value
end
def +(other)
Foo.new(to_i + other.to_i)
end
end
Foo.new(5) + 4
#=> #<Foo:0x00007fbd22050640 @value=9>
In order to add an instance of Foo
to an integer, you have to also implement coerce
which takes the left-hand value as an argument and returns an array with both values converted to Foo
instances, e.g.:
class Foo
# ...
def coerce(other)
[Foo.new(other.to_i), self]
end
end
This gives you:
4 + Foo.new(5)
#=> #<Foo:0x00007fba600e3e28 @value=9>
The docs for Numeric
contain another example.
Internally, coerce
is called by Integer#+
if the argument is not an integer: (C code)
VALUE
rb_int_plus(VALUE x, VALUE y)
{
if (FIXNUM_P(x)) {
return fix_plus(x, y);
}
else if (RB_TYPE_P(x, T_BIGNUM)) {
return rb_big_plus(x, y);
}
return rb_num_coerce_bin(x, y, '+');
}
rb_num_coerce_bin
calls coerce
and then invokes the binary operator +
on the returned values.
In Ruby this would be: (simplified)
class Integer
def +(other)
if other.is_a?(Integer)
# ...
else
x, y = other.coerce(self)
x + y
end
end
end