KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jruby > RubyComparable


1 /***** BEGIN LICENSE BLOCK *****
2  * Version: CPL 1.0/GPL 2.0/LGPL 2.1
3  *
4  * The contents of this file are subject to the Common Public
5  * License Version 1.0 (the "License"); you may not use this file
6  * except in compliance with the License. You may obtain a copy of
7  * the License at http://www.eclipse.org/legal/cpl-v10.html
8  *
9  * Software distributed under the License is distributed on an "AS
10  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
11  * implied. See the License for the specific language governing
12  * rights and limitations under the License.
13  *
14  * Copyright (C) 2001-2004 Jan Arne Petersen <jpetersen@uni-bonn.de>
15  * Copyright (C) 2002 Benoit Cerrina <b.cerrina@wanadoo.fr>
16  * Copyright (C) 2004 Anders Bengtsson <ndrsbngtssn@yahoo.se>
17  * Copyright (C) 2004 Stefan Matthias Aust <sma@3plus4.de>
18  * Copyright (C) 2005 Charles O Nutter <headius@headius.com>
19  * Copyright (C) 2006 Miguel Covarrubias <mlcovarrubias@gmail.com>
20  * Copyright (C) 2006 Thomas E Enebo <enebo@acm.org>
21  *
22  * Alternatively, the contents of this file may be used under the terms of
23  * either of the GNU General Public License Version 2 or later (the "GPL"),
24  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
25  * in which case the provisions of the GPL or the LGPL are applicable instead
26  * of those above. If you wish to allow use of your version of this file only
27  * under the terms of either the GPL or the LGPL, and not to allow others to
28  * use your version of this file under the terms of the CPL, indicate your
29  * decision by deleting the provisions above and replace them with the notice
30  * and other provisions required by the GPL or the LGPL. If you do not delete
31  * the provisions above, a recipient may use your version of this file under
32  * the terms of any one of the CPL, the GPL or the LGPL.
33  ***** END LICENSE BLOCK *****/

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 /** Implementation of the Comparable module.
42  *
43  */

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     /* ================
59      * Utility Methods
60      * ================
61      */

62
63     /** rb_cmpint
64      *
65      */

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     /** rb_cmperr
93      *
94      */

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     /* ================
107      * Module Methods
108      * ================
109      */

110
111     /** cmp_equal (cmp_eq inlined here)
112      *
113      */

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     /** cmp_gt
134      *
135      */

136     // <=> may return nil in many circumstances, e.g. 3 <=> NaN
137
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     /** cmp_ge
149      *
150      */

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     /** cmp_lt
163      *
164      */

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     /** cmp_le
177      *
178      */

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     /** cmp_between
191      *
192      */

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