Ruby 1.9.3p327(2012-11-10revision37606)
|
00001 /********************************************************************** 00002 00003 compar.c - 00004 00005 $Author: marcandre $ 00006 created at: Thu Aug 26 14:39:48 JST 1993 00007 00008 Copyright (C) 1993-2007 Yukihiro Matsumoto 00009 00010 **********************************************************************/ 00011 00012 #include "ruby/ruby.h" 00013 00014 VALUE rb_mComparable; 00015 00016 static ID cmp; 00017 00018 void 00019 rb_cmperr(VALUE x, VALUE y) 00020 { 00021 const char *classname; 00022 00023 if (SPECIAL_CONST_P(y)) { 00024 y = rb_inspect(y); 00025 classname = StringValuePtr(y); 00026 } 00027 else { 00028 classname = rb_obj_classname(y); 00029 } 00030 rb_raise(rb_eArgError, "comparison of %s with %s failed", 00031 rb_obj_classname(x), classname); 00032 } 00033 00034 static VALUE 00035 cmp_eq(VALUE *a) 00036 { 00037 VALUE c = rb_funcall(a[0], cmp, 1, a[1]); 00038 00039 if (NIL_P(c)) return Qfalse; 00040 if (rb_cmpint(c, a[0], a[1]) == 0) return Qtrue; 00041 return Qfalse; 00042 } 00043 00044 static VALUE 00045 cmp_failed(void) 00046 { 00047 return Qfalse; 00048 } 00049 00050 /* 00051 * call-seq: 00052 * obj == other -> true or false 00053 * 00054 * Compares two objects based on the receiver's <code><=></code> 00055 * method, returning true if it returns 0. Also returns true if 00056 * _obj_ and _other_ are the same object. 00057 */ 00058 00059 static VALUE 00060 cmp_equal(VALUE x, VALUE y) 00061 { 00062 VALUE a[2]; 00063 00064 if (x == y) return Qtrue; 00065 00066 a[0] = x; a[1] = y; 00067 return rb_rescue(cmp_eq, (VALUE)a, cmp_failed, 0); 00068 } 00069 00070 /* 00071 * call-seq: 00072 * obj > other -> true or false 00073 * 00074 * Compares two objects based on the receiver's <code><=></code> 00075 * method, returning true if it returns 1. 00076 */ 00077 00078 static VALUE 00079 cmp_gt(VALUE x, VALUE y) 00080 { 00081 VALUE c = rb_funcall(x, cmp, 1, y); 00082 00083 if (rb_cmpint(c, x, y) > 0) return Qtrue; 00084 return Qfalse; 00085 } 00086 00087 /* 00088 * call-seq: 00089 * obj >= other -> true or false 00090 * 00091 * Compares two objects based on the receiver's <code><=></code> 00092 * method, returning true if it returns 0 or 1. 00093 */ 00094 00095 static VALUE 00096 cmp_ge(VALUE x, VALUE y) 00097 { 00098 VALUE c = rb_funcall(x, cmp, 1, y); 00099 00100 if (rb_cmpint(c, x, y) >= 0) return Qtrue; 00101 return Qfalse; 00102 } 00103 00104 /* 00105 * call-seq: 00106 * obj < other -> true or false 00107 * 00108 * Compares two objects based on the receiver's <code><=></code> 00109 * method, returning true if it returns -1. 00110 */ 00111 00112 static VALUE 00113 cmp_lt(VALUE x, VALUE y) 00114 { 00115 VALUE c = rb_funcall(x, cmp, 1, y); 00116 00117 if (rb_cmpint(c, x, y) < 0) return Qtrue; 00118 return Qfalse; 00119 } 00120 00121 /* 00122 * call-seq: 00123 * obj <= other -> true or false 00124 * 00125 * Compares two objects based on the receiver's <code><=></code> 00126 * method, returning true if it returns -1 or 0. 00127 */ 00128 00129 static VALUE 00130 cmp_le(VALUE x, VALUE y) 00131 { 00132 VALUE c = rb_funcall(x, cmp, 1, y); 00133 00134 if (rb_cmpint(c, x, y) <= 0) return Qtrue; 00135 return Qfalse; 00136 } 00137 00138 /* 00139 * call-seq: 00140 * obj.between?(min, max) -> true or false 00141 * 00142 * Returns <code>false</code> if <i>obj</i> <code><=></code> 00143 * <i>min</i> is less than zero or if <i>anObject</i> <code><=></code> 00144 * <i>max</i> is greater than zero, <code>true</code> otherwise. 00145 * 00146 * 3.between?(1, 5) #=> true 00147 * 6.between?(1, 5) #=> false 00148 * 'cat'.between?('ant', 'dog') #=> true 00149 * 'gnu'.between?('ant', 'dog') #=> false 00150 * 00151 */ 00152 00153 static VALUE 00154 cmp_between(VALUE x, VALUE min, VALUE max) 00155 { 00156 if (RTEST(cmp_lt(x, min))) return Qfalse; 00157 if (RTEST(cmp_gt(x, max))) return Qfalse; 00158 return Qtrue; 00159 } 00160 00161 /* 00162 * The <code>Comparable</code> mixin is used by classes whose objects 00163 * may be ordered. The class must define the <code><=></code> operator, 00164 * which compares the receiver against another object, returning -1, 0, 00165 * or +1 depending on whether the receiver is less than, equal to, or 00166 * greater than the other object. If the other object is not comparable 00167 * then the <code><=></code> operator should return nil. 00168 * <code>Comparable</code> uses 00169 * <code><=></code> to implement the conventional comparison operators 00170 * (<code><</code>, <code><=</code>, <code>==</code>, <code>>=</code>, 00171 * and <code>></code>) and the method <code>between?</code>. 00172 * 00173 * class SizeMatters 00174 * include Comparable 00175 * attr :str 00176 * def <=>(anOther) 00177 * str.size <=> anOther.str.size 00178 * end 00179 * def initialize(str) 00180 * @str = str 00181 * end 00182 * def inspect 00183 * @str 00184 * end 00185 * end 00186 * 00187 * s1 = SizeMatters.new("Z") 00188 * s2 = SizeMatters.new("YY") 00189 * s3 = SizeMatters.new("XXX") 00190 * s4 = SizeMatters.new("WWWW") 00191 * s5 = SizeMatters.new("VVVVV") 00192 * 00193 * s1 < s2 #=> true 00194 * s4.between?(s1, s3) #=> false 00195 * s4.between?(s3, s5) #=> true 00196 * [ s3, s2, s5, s4, s1 ].sort #=> [Z, YY, XXX, WWWW, VVVVV] 00197 * 00198 */ 00199 00200 void 00201 Init_Comparable(void) 00202 { 00203 #undef rb_intern 00204 #define rb_intern(str) rb_intern_const(str) 00205 00206 rb_mComparable = rb_define_module("Comparable"); 00207 rb_define_method(rb_mComparable, "==", cmp_equal, 1); 00208 rb_define_method(rb_mComparable, ">", cmp_gt, 1); 00209 rb_define_method(rb_mComparable, ">=", cmp_ge, 1); 00210 rb_define_method(rb_mComparable, "<", cmp_lt, 1); 00211 rb_define_method(rb_mComparable, "<=", cmp_le, 1); 00212 rb_define_method(rb_mComparable, "between?", cmp_between, 2); 00213 00214 cmp = rb_intern("<=>"); 00215 } 00216