Module: Comparable

Included in:
File::Stat, IO::Buffer, Numeric, String, Symbol, Time
Defined in:
compar.c

Overview

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 StringSorter
  include Comparable

  attr :str
  def <=>(other)
    str.size <=> other.str.size
  end

  def initialize(str)
    @str = str
  end

  def inspect
    @str
  end
end

s1 = StringSorter.new("Z")
s2 = StringSorter.new("YY")
s3 = StringSorter.new("XXX")
s4 = StringSorter.new("WWWW")
s5 = StringSorter.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]

What’s Here

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 the given object.

  • #>=: Returns whether self is greater than or equal to 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.

Instance Method Summary collapse

Instance Method Details

#<(other) ⇒ Boolean

Compares two objects based on the receiver’s <=> method, returning true if it returns a value less than 0.

Returns:

  • (Boolean)


132
133
134
135
136
# File 'compar.c', line 132

static VALUE
cmp_lt(VALUE x, VALUE y)
{
    return RBOOL(cmpint(x, y) < 0);
}

#<=(other) ⇒ Boolean

Compares two objects based on the receiver’s <=> method, returning true if it returns a value less than or equal to 0.

Returns:

  • (Boolean)


146
147
148
149
150
# File 'compar.c', line 146

static VALUE
cmp_le(VALUE x, VALUE y)
{
    return RBOOL(cmpint(x, y) <= 0);
}

#==(other) ⇒ Boolean

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.

Returns:

  • (Boolean)


78
79
80
81
82
83
84
85
86
87
88
# File 'compar.c', line 78

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);
}

#>(other) ⇒ Boolean

Compares two objects based on the receiver’s <=> method, returning true if it returns a value greater than 0.

Returns:

  • (Boolean)


104
105
106
107
108
# File 'compar.c', line 104

static VALUE
cmp_gt(VALUE x, VALUE y)
{
    return RBOOL(cmpint(x, y) > 0);
}

#>=(other) ⇒ Boolean

Compares two objects based on the receiver’s <=> method, returning true if it returns a value greater than or equal to 0.

Returns:

  • (Boolean)


118
119
120
121
122
# File 'compar.c', line 118

static VALUE
cmp_ge(VALUE x, VALUE y)
{
    return RBOOL(cmpint(x, y) >= 0);
}

#between?(min, max) ⇒ Boolean

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

Returns:

  • (Boolean)


167
168
169
170
171
# File 'compar.c', line 167

static VALUE
cmp_between(VALUE x, VALUE min, VALUE max)
{
    return RBOOL((cmpint(x, min) >= 0 && cmpint(x, max) <= 0));
}

#clamp(min, max) ⇒ Object #clamp(range) ⇒ Object

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'

If min is nil, it is considered smaller than obj, and if max is nil, it is considered greater than obj.

-20.clamp(0, nil)           #=> 0
523.clamp(nil, 100)         #=> 100

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

Overloads:



221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
# File 'compar.c', line 221

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 less than or equal to 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;
}