Module: Comparable

Included in:
File::Stat, 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 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]

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)


135
136
137
138
139
140
# File 'compar.c', line 135

static VALUE
cmp_lt(VALUE x, VALUE y)
{
    if (cmpint(x, y) < 0) return Qtrue;
    return Qfalse;
}

#<=(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)


150
151
152
153
154
155
# File 'compar.c', line 150

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

#==(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
89
# 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;
    if (rb_cmpint(c, x, y) == 0) return Qtrue;
    return Qfalse;
}

#>(other) ⇒ Boolean

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

Returns:

  • (Boolean)


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

static VALUE
cmp_gt(VALUE x, VALUE y)
{
    if (cmpint(x, y) > 0) return Qtrue;
    return Qfalse;
}

#>=(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)


120
121
122
123
124
125
# File 'compar.c', line 120

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

#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)


172
173
174
175
176
177
178
# File 'compar.c', line 172

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

#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'

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:



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
252
253
254
# File 'compar.c', line 222

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) && cmpint(min, max) > 0) goto arg_error;
        }
    }
    else if (cmpint(min, max) > 0) {
      arg_error:
	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;
}