1 34 package org.jruby; 35 36 import org.jruby.exceptions.RaiseException; 37 import org.jruby.runtime.CallbackFactory; 38 import org.jruby.runtime.ThreadContext; 39 import org.jruby.runtime.builtin.IRubyObject; 40 41 44 public class RubyComparable { 45 public static RubyModule createComparable(Ruby runtime) { 46 RubyModule comparableModule = runtime.defineModule("Comparable"); 47 CallbackFactory callbackFactory = runtime.callbackFactory(RubyComparable.class); 48 comparableModule.defineFastMethod("==", callbackFactory.getFastSingletonMethod("equal", RubyKernel.IRUBY_OBJECT)); 49 comparableModule.defineFastMethod(">", callbackFactory.getFastSingletonMethod("op_gt", RubyKernel.IRUBY_OBJECT)); 50 comparableModule.defineFastMethod(">=", callbackFactory.getFastSingletonMethod("op_ge", RubyKernel.IRUBY_OBJECT)); 51 comparableModule.defineFastMethod("<", callbackFactory.getFastSingletonMethod("op_lt", RubyKernel.IRUBY_OBJECT)); 52 comparableModule.defineFastMethod("<=", callbackFactory.getFastSingletonMethod("op_le", RubyKernel.IRUBY_OBJECT)); 53 comparableModule.defineFastMethod("between?", callbackFactory.getFastSingletonMethod("between_p", RubyKernel.IRUBY_OBJECT, RubyKernel.IRUBY_OBJECT)); 54 55 return comparableModule; 56 } 57 58 62 63 66 public static int cmpint(IRubyObject val, IRubyObject a, IRubyObject b) { 67 if (val.isNil()) { 68 cmperr(a, b); 69 } 70 if (val instanceof RubyFixnum) { 71 return RubyNumeric.fix2int((RubyFixnum) val); 72 } 73 if (val instanceof RubyBignum) { 74 if (((RubyBignum) val).getValue().signum() == -1) { 75 return 1; 76 } 77 return -1; 78 } 79 80 final Ruby runtime = val.getRuntime(); 81 final ThreadContext tc = runtime.getCurrentContext(); 82 final RubyFixnum zero = RubyFixnum.one(runtime); 83 if (val.callMethod(tc, ">", zero).isTrue()) { 84 return 1; 85 } 86 if (val.callMethod(tc, "<", zero).isTrue()) { 87 return -1; 88 } 89 return 0; 90 } 91 92 95 public static void cmperr(IRubyObject recv, IRubyObject other) { 96 IRubyObject target; 97 if (other.isImmediate() || !(other.isNil() || other.isTrue() || other == recv.getRuntime().getFalse())) { 98 target = other.inspect(); 99 } else { 100 target = other.getType(); 101 } 102 103 throw recv.getRuntime().newArgumentError("comparison of " + recv.getType() + " with " + target + " failed"); 104 } 105 106 110 111 114 public static IRubyObject equal(IRubyObject recv, IRubyObject other) { 115 if (recv == other) { 116 return recv.getRuntime().getTrue(); 117 } 118 Ruby runtime = recv.getRuntime(); 119 IRubyObject result = null; 120 try { 121 result = recv.callMethod(runtime.getCurrentContext(), "<=>", other); 122 } catch (RaiseException e) { 123 return recv.getRuntime().getFalse(); 124 } 125 126 if (result.isNil()) { 127 return result; 128 } 129 130 return RubyBoolean.newBoolean(runtime, cmpint(result, recv, other) == 0); 131 } 132 133 136 public static RubyBoolean op_gt(IRubyObject recv, IRubyObject other) { 138 final Ruby runtime = recv.getRuntime(); 139 IRubyObject result = recv.callMethod(runtime.getCurrentContext(), "<=>", other); 140 141 if (result.isNil()) { 142 cmperr(recv, other); 143 } 144 145 return RubyBoolean.newBoolean(runtime, cmpint(result, recv, other) > 0); 146 } 147 148 151 public static RubyBoolean op_ge(IRubyObject recv, IRubyObject other) { 152 final Ruby runtime = recv.getRuntime(); 153 IRubyObject result = recv.callMethod(runtime.getCurrentContext(), "<=>", other); 154 155 if (result.isNil()) { 156 cmperr(recv, other); 157 } 158 159 return RubyBoolean.newBoolean(runtime, cmpint(result, recv, other) >= 0); 160 } 161 162 165 public static RubyBoolean op_lt(IRubyObject recv, IRubyObject other) { 166 final Ruby runtime = recv.getRuntime(); 167 IRubyObject result = recv.callMethod(runtime.getCurrentContext(), "<=>", other); 168 169 if (result.isNil()) { 170 cmperr(recv, other); 171 } 172 173 return RubyBoolean.newBoolean(runtime, cmpint(result, recv, other) < 0); 174 } 175 176 179 public static RubyBoolean op_le(IRubyObject recv, IRubyObject other) { 180 final Ruby runtime = recv.getRuntime(); 181 IRubyObject result = recv.callMethod(runtime.getCurrentContext(), "<=>", other); 182 183 if (result.isNil()) { 184 cmperr(recv, other); 185 } 186 187 return RubyBoolean.newBoolean(runtime, cmpint(result, recv, other) <= 0); 188 } 189 190 193 public static RubyBoolean between_p(IRubyObject recv, IRubyObject first, IRubyObject second) { 194 195 return recv.getRuntime().newBoolean(op_lt(recv, first).isFalse() && op_gt(recv, second).isFalse()); 196 } 197 } 198 | Popular Tags |