Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

223 lines (197 sloc) 5.241 kb
/*
* This file is covered by the Ruby license. See COPYING for more details.
*
* Copyright (C) 2012, The MacRuby Team. All rights reserved.
* Copyright (C) 2007-2011, Apple Inc. All rights reserved.
* Copyright (C) 1993-2007 Yukihiro Matsumoto
*/
#include "macruby_internal.h"
#include "ruby/node.h"
#include "vm.h"
VALUE rb_mComparable;
static SEL cmp = 0;
void
rb_cmperr(VALUE x, VALUE y)
{
const char *classname;
if (SPECIAL_CONST_P(y)) {
y = rb_inspect(y);
classname = StringValuePtr(y);
}
else {
classname = rb_obj_classname(y);
}
rb_raise(rb_eArgError, "comparison of %s with %s failed",
rb_obj_classname(x), classname);
}
VALUE
rb_objs_cmp(VALUE x, VALUE y)
{
return rb_vm_call(x, cmp, 1, &y);
}
static VALUE
cmp_eq(VALUE *a)
{
VALUE c = rb_vm_call(a[0], cmp, 1, &a[1]);
if (NIL_P(c)) {
return Qfalse;
}
if (rb_cmpint(c, a[0], a[1]) == 0) {
return Qtrue;
}
return Qfalse;
}
static VALUE
cmp_failed(void)
{
return Qfalse;
}
/*
* call-seq:
* obj == other => true or false
*
* Compares two objects based on the receiver's <code><=></code>
* method, returning true if it returns 0. Also returns true if
* _obj_ and _other_ are the same object.
*/
static VALUE
cmp_equal(VALUE x, SEL sel, VALUE y)
{
VALUE a[2];
if (x == y) return Qtrue;
a[0] = x; a[1] = y;
return rb_rescue(cmp_eq, (VALUE)a, cmp_failed, 0);
}
/*
* call-seq:
* obj > other => true or false
*
* Compares two objects based on the receiver's <code><=></code>
* method, returning true if it returns 1.
*/
static VALUE
cmp_gt(VALUE x, SEL sel, VALUE y)
{
VALUE c = rb_vm_call(x, cmp, 1, &y);
if (rb_cmpint(c, x, y) > 0) {
return Qtrue;
}
return Qfalse;
}
/*
* call-seq:
* obj >= other => true or false
*
* Compares two objects based on the receiver's <code><=></code>
* method, returning true if it returns 0 or 1.
*/
static VALUE
cmp_ge(VALUE x, SEL sel, VALUE y)
{
VALUE c = rb_vm_call(x, cmp, 1, &y);
if (rb_cmpint(c, x, y) >= 0) {
return Qtrue;
}
return Qfalse;
}
/*
* call-seq:
* obj < other => true or false
*
* Compares two objects based on the receiver's <code><=></code>
* method, returning true if it returns -1.
*/
static VALUE
cmp_lt(VALUE x, SEL sel, VALUE y)
{
VALUE c = rb_vm_call(x, cmp, 1, &y);
if (rb_cmpint(c, x, y) < 0) {
return Qtrue;
}
return Qfalse;
}
/*
* call-seq:
* obj <= other => true or false
*
* Compares two objects based on the receiver's <code><=></code>
* method, returning true if it returns -1 or 0.
*/
static VALUE
cmp_le(VALUE x, SEL sel, VALUE y)
{
VALUE c = rb_vm_call(x, cmp, 1, &y);
if (rb_cmpint(c, x, y) <= 0) {
return Qtrue;
}
return Qfalse;
}
/*
* call-seq:
* obj.between?(min, max) => true or false
*
* Returns <code>false</code> if <i>obj</i> <code><=></code>
* <i>min</i> is less than zero or if <i>anObject</i> <code><=></code>
* <i>max</i> is greater than zero, <code>true</code> 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, SEL sel, VALUE min, VALUE max)
{
if (RTEST(cmp_lt(x, 0, min))) return Qfalse;
if (RTEST(cmp_gt(x, 0, max))) return Qfalse;
return Qtrue;
}
/*
* The <code>Comparable</code> mixin is used by classes whose objects
* may be ordered. The class must define the <code><=></code> operator,
* which compares the receiver against another object, returning -1, 0,
* or +1 depending on whether the receiver is less than, equal to, or
* greater than the other object. <code>Comparable</code> uses
* <code><=></code> to implement the conventional comparison operators
* (<code><</code>, <code><=</code>, <code>==</code>, <code>>=</code>,
* and <code>></code>) and the method <code>between?</code>.
*
* class SizeMatters
* include Comparable
* attr :str
* def <=>(anOther)
* str.size <=> anOther.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]
*
*/
void
Init_Comparable(void)
{
rb_mComparable = rb_define_module("Comparable");
rb_objc_define_method(rb_mComparable, "==", cmp_equal, 1);
rb_objc_define_method(rb_mComparable, ">", cmp_gt, 1);
rb_objc_define_method(rb_mComparable, ">=", cmp_ge, 1);
rb_objc_define_method(rb_mComparable, "<", cmp_lt, 1);
rb_objc_define_method(rb_mComparable, "<=", cmp_le, 1);
rb_objc_define_method(rb_mComparable, "between?", cmp_between, 2);
cmp = sel_registerName("<=>:");
}
Jump to Line
Something went wrong with that request. Please try again.