The Comparable mixin is used by classes whose objects may be ordered. The class must define the <=> operator, which compares the receiver against another object, returning a value less than 0, returning 0, or returning a value greater than 0, depending on whether the receiver is less than, equal to, or greater than the other object. If the other object is not comparable then the <=> operator should return nil. Comparable uses <=> to implement the conventional comparison operators (<, <=, ==, >=, and >) and the method between?.
class SizeMatters include Comparable attr :str def <=>(other) str.size <=> other.str.size end def initialize(str) @str = str end def inspect @str end end s1 = SizeMatters.new("Z") s2 = SizeMatters.new("YY") s3 = SizeMatters.new("XXX") s4 = SizeMatters.new("WWWW") s5 = SizeMatters.new("VVVVV") s1 < s2 #=> true s4.between?(s1, s3) #=> false s4.between?(s3, s5) #=> true [ s3, s2, s5, s4, s1 ].sort #=> [Z, YY, XXX, WWWW, VVVVV]
Module Comparable provides these methods, all of which use method <=>:
Returns whether self is less than the given object.
Returns whether self is less than or equal to the given object.
Returns whether self is equal to the given object.
Returns whether self is greater than or equal to the given object.
Returns whether self is greater than the given object.
between? Returns true if self is between two given objects.
clamp
For given objects min and max, or range (min..max), returns:
min if (self <=> min) < 0.
max if (self <=> max) > 0.
self otherwise.
Compares two objects based on the receiver's <=> method, returning true if it returns a value less than 0.
static VALUE
cmp_lt(VALUE x, VALUE y)
{
return RBOOL(cmpint(x, y) < 0);
}
Compares two objects based on the receiver's <=> method, returning true if it returns a value less than or equal to 0.
static VALUE
cmp_le(VALUE x, VALUE y)
{
return RBOOL(cmpint(x, y) <= 0);
}
Compares two objects based on the receiver's <=> method, returning true if it returns 0. Also returns true if obj and other are the same object.
static VALUE
cmp_equal(VALUE x, VALUE y)
{
VALUE c;
if (x == y) return Qtrue;
c = rb_exec_recursive_paired_outer(cmp_eq_recursive, x, y, y);
if (NIL_P(c)) return Qfalse;
return RBOOL(rb_cmpint(c, x, y) == 0);
}
Compares two objects based on the receiver's <=> method, returning true if it returns a value greater than 0.
static VALUE
cmp_gt(VALUE x, VALUE y)
{
return RBOOL(cmpint(x, y) > 0);
}
Compares two objects based on the receiver's <=> method, returning true if it returns a value greater than or equal to 0.
static VALUE
cmp_ge(VALUE x, VALUE y)
{
return RBOOL(cmpint(x, y) >= 0);
}
Returns false if obj <=> min is less than zero or if obj <=> max is greater than zero, true otherwise.
3.between?(1, 5) #=> true 6.between?(1, 5) #=> false 'cat'.between?('ant', 'dog') #=> true 'gnu'.between?('ant', 'dog') #=> false
static VALUE
cmp_between(VALUE x, VALUE min, VALUE max)
{
if (cmpint(x, min) < 0) return Qfalse;
if (cmpint(x, max) > 0) return Qfalse;
return Qtrue;
}
In (min, max) form, returns min if obj <=> min is less than zero, max if obj <=> max is greater than zero, and obj otherwise.
12.clamp(0, 100) #=> 12 523.clamp(0, 100) #=> 100 -3.123.clamp(0, 100) #=> 0 'd'.clamp('a', 'f') #=> 'd' 'z'.clamp('a', 'f') #=> 'f'
In (range) form, returns range.begin if obj <=> range.begin is less than zero, range.end if obj <=> range.end is greater than zero, and obj otherwise.
12.clamp(0..100) #=> 12 523.clamp(0..100) #=> 100 -3.123.clamp(0..100) #=> 0 'd'.clamp('a'..'f') #=> 'd' 'z'.clamp('a'..'f') #=> 'f'
If range.begin is nil, it is considered smaller than obj, and if range.end is nil, it is considered greater than obj.
-20.clamp(0..) #=> 0 523.clamp(..100) #=> 100
When range.end is excluded and not nil, an exception is raised.
100.clamp(0...100) # ArgumentError
static VALUE
cmp_clamp(int argc, VALUE *argv, VALUE x)
{
VALUE min, max;
int c, excl = 0;
if (rb_scan_args(argc, argv, "11", &min, &max) == 1) {
VALUE range = min;
if (!rb_range_values(range, &min, &max, &excl)) {
rb_raise(rb_eTypeError, "wrong argument type %s (expected Range)",
rb_builtin_class_name(range));
}
if (!NIL_P(max)) {
if (excl) rb_raise(rb_eArgError, "cannot clamp with an exclusive range");
}
}
if (!NIL_P(min) && !NIL_P(max) && cmpint(min, max) > 0) {
rb_raise(rb_eArgError, "min argument must be smaller than max argument");
}
if (!NIL_P(min)) {
c = cmpint(x, min);
if (c == 0) return x;
if (c < 0) return min;
}
if (!NIL_P(max)) {
c = cmpint(x, max);
if (c > 0) return max;
}
return x;
}