Ruby Object Comparable to Fixnum
I'd like to implement a class in Ruby that's comparable (using the <=>
operator) with any Fixnum, and vice-versa. This will ultimately be used in a range. Here is an outline of my class:
class N
include Compar开发者_如何学编程able
attr :offset
def initialize(offset = 0)
@offset = offset
end
def succ
N.new(@offset + 1)
end
def +(offset)
N.new(@offset + offset)
end
def <=>(other)
return @offset <=> other.offset if other.kind_of? N
return 1 # N is greater than everything else
end
end
def n; N.new(0); end
Now this works great when used in n..n+2
and n..999
, but not in 1..n
. This is due to the fact that n <=> 1
works but 1 <=> n
does not (returns nil).
Is there any way I can get Fixnum to treat my N class as a comparable object? Your thoughts are appreciated :)
If you want to implement your own number type, you must implement coerce
:
class N
def coerce(other)
return N.new(other), self
end
end
n = N.new
1 <=> n # => -1
All of Ruby's builtin number types in the core library, all number types in the standard library, as well as all third-party number types use the coerce
protocol to find a common type in order to make operators such as +
, *
and ==
commutative and -
, /
and <=>
symmetric.
It's not quite clear to me what the semantics of N
should be, so the above implementation is only an example.
Okay, I did a little monkey patching (freedom patching ;) that seems to have solved my problem for now.
class Fixnum
def <=>(other)
return -1 if other.kind_of? N
return -1 if self < other
return 0 if self == other
return 1 if self > other
end
end
Output seems to be as expected and it doesn't break anything in the inner workings of Fixnum
as far as I can tell. Any better ideas/comments, feel free to post 'em.
1 <=> n # => -1
1 <=> 1 # => 0
1 <=> 2 # => -1
2 <=> 1 # => 1
1 == 1 # => true
1 == 2 # => false
1 < 2 # => true
1 > 2 # => false
精彩评论