Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: jruby/jruby
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: cd080915bcac
Choose a base ref
...
head repository: jruby/jruby
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 2a5b495ce4c9
Choose a head ref
  • 11 commits
  • 10 files changed
  • 1 contributor

Commits on Aug 8, 2017

  1. Unverified

    This user has not yet uploaded their public signing key.
    Copy the full SHA
    9fdb9e1 View commit details
  2. move (custom) Float conversion where its used - adjust accordingly

    preparing to be able to handle Java numbers while keeping compat
    kares committed Aug 8, 2017
    Copy the full SHA
    1859c05 View commit details
  3. Copy the full SHA
    0ccac04 View commit details
  4. Copy the full SHA
    e1ac89b View commit details
  5. Copy the full SHA
    0130d28 View commit details
  6. Copy the full SHA
    b29154b View commit details
  7. implement coerce for Java numbers; special care for Java's BigDecimal

    we're converting to Ruby but all basic num operations now simply work
    kares committed Aug 8, 2017
    Copy the full SHA
    9095c58 View commit details
  8. move and re-use (adjusted) toFloat conversion back to TypeConverter

    now same as MRI except maybe toFloat to be moved into RubyObject
    kares committed Aug 8, 2017
    Copy the full SHA
    3be564e View commit details
  9. Copy the full SHA
    0bb8410 View commit details
  10. Copy the full SHA
    d806cfe View commit details
  11. Copy the full SHA
    2a5b495 View commit details
27 changes: 21 additions & 6 deletions core/src/main/java/org/jruby/RubyInteger.java
Original file line number Diff line number Diff line change
@@ -607,8 +607,7 @@ public IRubyObject pred(ThreadContext context) {
*/
@JRubyMethod(name = "gcd")
public IRubyObject gcd(ThreadContext context, IRubyObject other) {
checkInteger(context, other);
return f_gcd(context, this, RubyRational.intValue(context, other));
return f_gcd(context, this, RubyInteger.intValue(context, other));
}

// MRI: rb_int_fdiv_double and rb_int_fdiv in one
@@ -632,20 +631,36 @@ public IRubyObject fdiv(ThreadContext context, IRubyObject y) {
*/
@JRubyMethod(name = "lcm")
public IRubyObject lcm(ThreadContext context, IRubyObject other) {
checkInteger(context, other);
return f_lcm(context, this, RubyRational.intValue(context, other));
return f_lcm(context, this, RubyInteger.intValue(context, other));
}

/** rb_gcdlcm
*
*/
@JRubyMethod(name = "gcdlcm")
public IRubyObject gcdlcm(ThreadContext context, IRubyObject other) {
checkInteger(context, other);
other = RubyRational.intValue(context, other);
other = RubyInteger.intValue(context, other);
return context.runtime.newArray(f_gcd(context, this, other), f_lcm(context, this, other));
}

static IRubyObject intValue(ThreadContext context, IRubyObject num) {
IRubyObject i;
if (( i = RubyInteger.toInteger(context, num) ) == null) {
throw context.runtime.newTypeError("not an integer");
}
return i;
}

static IRubyObject toInteger(ThreadContext context, IRubyObject num) {
if (num instanceof RubyInteger) return num;
if (num instanceof RubyNumeric && !num.callMethod(context, "integer?").isTrue()) {
return null;
}
if (num instanceof RubyString) return null; // do not want String#to_i
if (num.respondsTo("to_i")) return num.callMethod(context, "to_i");
return null;
}

@JRubyMethod(name = "digits")
public RubyArray digits(ThreadContext context) {
return digits(context, RubyFixnum.newFixnum(context.getRuntime(), 10));
56 changes: 17 additions & 39 deletions core/src/main/java/org/jruby/RubyNumeric.java
Original file line number Diff line number Diff line change
@@ -216,20 +216,14 @@ public static byte num2chr(IRubyObject arg) {
*
*/
public static long num2long(IRubyObject arg) {
if (arg instanceof RubyFixnum) {
return ((RubyFixnum) arg).getLongValue();
} else {
return other2long(arg);
}
return arg instanceof RubyFixnum ? ((RubyFixnum) arg).getLongValue() : other2long(arg);
}

private static long other2long(IRubyObject arg) throws RaiseException {
if (arg instanceof RubyFloat) return float2long((RubyFloat) arg);
if (arg instanceof RubyBignum) return RubyBignum.big2long((RubyBignum) arg);
if (arg.isNil()) {
throw arg.getRuntime().newTypeError("no implicit conversion from nil to integer");
} else if (arg instanceof RubyFloat) {
return float2long((RubyFloat)arg);
} else if (arg instanceof RubyBignum) {
return RubyBignum.big2long((RubyBignum) arg);
}
return arg.convertToInteger().getLongValue();
}
@@ -265,42 +259,26 @@ public static IRubyObject dbl2ival(Ruby runtime, double val) {
*
*/
public static double num2dbl(IRubyObject arg) {
Ruby runtime = arg.getRuntime();

if (arg instanceof RubyBoolean || arg instanceof RubyNil) {
throw runtime.newTypeError("can't convert " + arg.inspect() + " into Float");
}

if (arg instanceof RubyFloat) {
return ((RubyFloat) arg).getDoubleValue();
} else if (arg instanceof RubyBignum) {
if (runtime.getBignum().searchMethod("to_f").isBuiltin()) {
return ((RubyBignum) arg).getDoubleValue();
}
} else if (arg instanceof RubyRational) {
if (runtime.getRational().searchMethod("to_f").isBuiltin()) {
return ((RubyRational) arg).getDoubleValue();
}
}

IRubyObject val = numericToFloat(runtime, arg);
return ((RubyFloat) val).getDoubleValue();
}

private static IRubyObject numericToFloat(Ruby runtime, IRubyObject num) {
if (!(num instanceof RubyNumeric)) {
throw runtime.newTypeError("can't convert " + num.getType() + " into Float");
final Ruby runtime = arg.getRuntime();
if (arg instanceof RubyFixnum && !runtime.isFixnumReopened()) {
return ((RubyFixnum) arg).getDoubleValue();
}

if (num instanceof RubyFloat) {
return num;
if (arg instanceof RubyBignum && runtime.getBignum().searchMethod("to_f").isBuiltin()) {
return ((RubyBignum) arg).getDoubleValue();
}
if (arg instanceof RubyRational && runtime.getRational().searchMethod("to_f").isBuiltin()) {
return ((RubyRational) arg).getDoubleValue();
}

if (num instanceof RubyFixnum && !runtime.isFixnumReopened()) {
return ((RubyFixnum) num).to_f();
if (arg instanceof RubyBoolean || arg instanceof RubyString || arg.isNil()) {
throw runtime.newTypeError("can't convert " + arg.inspect() + " into Float");
}

return TypeConverter.convertToType(num, runtime.getFloat(), "to_f");
IRubyObject val = TypeConverter.convertToType(arg, runtime.getFloat(), "to_f");
return ((RubyFloat) val).getDoubleValue();
}

/** rb_dbl_cmp (numeric.c)
@@ -793,8 +771,8 @@ public IRubyObject divmod(ThreadContext context, IRubyObject other) {
/** num_fdiv */
@JRubyMethod(name = "fdiv")
public IRubyObject fdiv(ThreadContext context, IRubyObject other) {
RubyFloat flote = this.convertToFloat();
return sites(context).op_quo.call(context, flote, flote, other);
RubyFloat value = convertToFloat();
return sites(context).op_quo.call(context, value, value, other);
}

/** num_modulo
17 changes: 6 additions & 11 deletions core/src/main/java/org/jruby/RubyRandom.java
Original file line number Diff line number Diff line change
@@ -38,6 +38,8 @@
import org.jruby.util.Random;
import org.jruby.util.TypeConverter;

import static org.jruby.util.TypeConverter.toFloat;

/**
* Implementation of the Random class.
*/
@@ -487,8 +489,8 @@ private static IRubyObject randomRand(ThreadContext context, IRubyObject vmax, R
double mid = 0.5;
double r;
if (Double.isInfinite(max)) {
double min = floatValue(context, range.begin) / 2.0;
max = floatValue(context, range.end) / 2.0;
double min = floatValue(context, toFloat(context.runtime, range.begin)) / 2.0;
max = floatValue(context, toFloat(context.runtime, range.end)) / 2.0;
scale = 2;
mid = max + min;
max -= min;
@@ -533,15 +535,8 @@ private static IRubyObject randomRand(ThreadContext context, IRubyObject vmax, R
}

// c: float_value
private static double floatValue(ThreadContext context, IRubyObject v) {
final double x;
if (v instanceof RubyFloat) {
x = ((RubyFloat) v).getDoubleValue();
} else if (v instanceof RubyNumeric) {
x = ((RubyNumeric) v).convertToFloat().getDoubleValue();
} else {
throw context.runtime.newTypeError(v, context.runtime.getFloat());
}
private static double floatValue(ThreadContext context, RubyFloat v) {
final double x = v.getDoubleValue();
checkFloatValue(context, x);
return x;
}
37 changes: 15 additions & 22 deletions core/src/main/java/org/jruby/RubyRational.java
Original file line number Diff line number Diff line change
@@ -214,18 +214,19 @@ static void intCheck(ThreadContext context, IRubyObject num) {
if (num instanceof RubyFixnum || num instanceof RubyBignum) return;
if (!(num instanceof RubyNumeric) || !num.callMethod(context, "integer?").isTrue()) {
Ruby runtime = num.getRuntime();
throw runtime.newTypeError("can't convert "
+ num.getMetaClass().getName() + " into Rational");
throw runtime.newTypeError("can't convert " + num.getMetaClass().getName() + " into Rational");
}
}

/** nurat_int_value
*
*/
static IRubyObject intValue(ThreadContext context, IRubyObject num) {
intCheck(context, num);
if (!(num instanceof RubyInteger)) num = num.callMethod(context, "to_f");
return num;
IRubyObject i;
if (( i = RubyInteger.toInteger(context, num) ) == null) {
throw context.runtime.newTypeError("can't convert " + num.getMetaClass().getName() + " into Rational");
}
return i;
}

/** nurat_s_canonicalize_internal
@@ -337,7 +338,7 @@ public static IRubyObject convert(ThreadContext context, IRubyObject clazz, IRub
*/
@JRubyMethod(name = "convert", meta = true, visibility = Visibility.PRIVATE)
public static IRubyObject convert(ThreadContext context, IRubyObject recv, IRubyObject a1) {
if (a1.isNil()) {
if (a1 == context.nil) {
throw context.runtime.newTypeError("can't convert nil into Rational");
}

@@ -349,7 +350,7 @@ public static IRubyObject convert(ThreadContext context, IRubyObject recv, IRuby
*/
@JRubyMethod(name = "convert", meta = true, visibility = Visibility.PRIVATE)
public static IRubyObject convert(ThreadContext context, IRubyObject recv, IRubyObject a1, IRubyObject a2) {
if (a1.isNil() || a2.isNil()) {
if (a1 == context.nil || a2 == context.nil) {
throw context.runtime.newTypeError("can't convert nil into Rational");
}

@@ -371,7 +372,7 @@ private static IRubyObject convertCommon(ThreadContext context, IRubyObject recv
} else if (a1 instanceof RubyString) {
a1 = str_to_r_strict(context, a1);
} else {
if (a1 instanceof RubyObject && responds_to_to_r(context, a1)) {
if (a1 instanceof RubyObject && sites(context).respond_to_to_r.respondsTo(context, a1, a1)) {
a1 = f_to_r(context, a1);
}
}
@@ -383,28 +384,23 @@ private static IRubyObject convertCommon(ThreadContext context, IRubyObject recv
}

if (a1 instanceof RubyRational) {
if (a2.isNil() || (k_exact_p(a2) && f_one_p(context, a2))) return a1;
if (a2 == context.nil || (k_exact_p(a2) && f_one_p(context, a2))) return a1;
}

if (a2.isNil()) {
if (a1 instanceof RubyNumeric && !f_integer_p(context, a1).isTrue()) return a1;
if (a2 == context.nil) {
if (!(a1 instanceof RubyNumeric && f_integer_p(context, a1).isTrue())) {
return TypeConverter.convertToType(context, a1, context.runtime.getRational(), sites(context).to_r_checked);
}
return newInstance(context, recv, a1);
} else {
if (a1 instanceof RubyNumeric && a2 instanceof RubyNumeric &&
if ((a1 instanceof RubyNumeric && a2 instanceof RubyNumeric) &&
(!f_integer_p(context, a1).isTrue() || !f_integer_p(context, a2).isTrue())) {
return f_div(context, a1, a2);
}
return newInstance(context, recv, a1, a2);
}
}

private static boolean responds_to_to_r(ThreadContext context, IRubyObject obj) {
return respond_to_to_r.respondsTo(context, obj, obj);
}

// TODO: wasn't sure whether to put this on NumericSites, here for now - should move
static final RespondToCallSite respond_to_to_r = new RespondToCallSite("to_r");

/** nurat_numerator
*
*/
@@ -1192,9 +1188,6 @@ public IRubyObject marshal_load(ThreadContext context, IRubyObject arg) {
IRubyObject num = load.size() > 0 ? load.eltInternal(0) : context.nil;
IRubyObject den = load.size() > 1 ? load.eltInternal(1) : context.nil;

intCheck(context, num);
intCheck(context, den);

// MRI: nurat_canonicalize, negation part
if (canonicalizeShouldNegate(context, num, den)) {
num = f_negate(context, num);
65 changes: 65 additions & 0 deletions core/src/main/java/org/jruby/javasupport/ext/JavaLang.java
Original file line number Diff line number Diff line change
@@ -31,6 +31,7 @@
import org.jruby.anno.JRubyClass;
import org.jruby.anno.JRubyMethod;
import org.jruby.anno.JRubyModule;
import org.jruby.ext.bigdecimal.RubyBigDecimal;
import org.jruby.internal.runtime.methods.JavaMethod;
import org.jruby.javasupport.Java;
import org.jruby.javasupport.JavaClass;
@@ -62,6 +63,7 @@ public static void define(final Ruby runtime) {
Throwable.define(runtime);
Runnable.define(runtime);
Character.define(runtime);
Number.define(runtime);
Class.define(runtime);
ClassLoader.define(runtime);
// Java::byte[].class_eval ...
@@ -307,6 +309,63 @@ protected final IRubyObject doYield(ThreadContext context, Block block, IRubyObj

}

@JRubyClass(name = "Java::JavaLang::Number")
public static class Number {

static RubyClass define(final Ruby runtime) {
final RubyModule Number = Java.getProxyClass(runtime, java.lang.Number.class);
Number.defineAnnotatedMethods(Number.class);
return (RubyClass) Number;
}

@JRubyMethod(name = "to_f")
public static IRubyObject to_f(final ThreadContext context, final IRubyObject self) {
java.lang.Number val = (java.lang.Number) self.toJava(java.lang.Number.class);
return context.runtime.newFloat(val.doubleValue());
}

@JRubyMethod(name = { "to_i", "to_int" })
public static IRubyObject to_i(final ThreadContext context, final IRubyObject self) {
java.lang.Number val = (java.lang.Number) self.toJava(java.lang.Number.class);
if (val instanceof java.math.BigInteger) { // NOTE: should be moved into its own?
return RubyBignum.newBignum(context.runtime, (java.math.BigInteger) val);
}
if (val instanceof java.math.BigDecimal) { // NOTE: should be moved into its own?
return RubyBignum.newBignum(context.runtime, ((java.math.BigDecimal) val).toBigInteger());
}
return context.runtime.newFixnum(val.longValue());
}

@JRubyMethod(name = "integer?")
public static IRubyObject integer_p(final ThreadContext context, final IRubyObject self) {
java.lang.Number val = (java.lang.Number) self.toJava(java.lang.Number.class);
return context.runtime.newBoolean(val instanceof Integer || val instanceof Long ||
val instanceof Short || val instanceof Byte ||
val instanceof java.math.BigInteger);
}

@JRubyMethod(name = "coerce")
public static IRubyObject coerce(final ThreadContext context, final IRubyObject self, final IRubyObject type) {
java.lang.Number val = (java.lang.Number) self.toJava(java.lang.Number.class);

// NOTE: a basic stub that always coverts Java numbers to Ruby ones (for simplicity)
// gist being this is not expected to be used heavily, if so should get special care
final IRubyObject value;
if (val instanceof java.math.BigDecimal) {
final RubyClass klass = context.runtime.getClass("BigDecimal");
if (klass == null) { // user should require 'bigdecimal'
throw context.runtime.newNameError("uninitialized constant BigDecimal", "BigDecimal");
}
value = new RubyBigDecimal(context.runtime, klass, (java.math.BigDecimal) val);
}
else {
value = convertJavaToUsableRubyObject(context.runtime, val);
}
return context.runtime.newArray(type, value);
}

}

@JRubyClass(name = "Java::JavaLang::Character")
public static class Character {

@@ -330,6 +389,12 @@ private static char to_char(final IRubyObject num) {
return (java.lang.Character) num.toJava(java.lang.Character.TYPE);
}

@JRubyMethod(name = "to_i")
public static IRubyObject to_i(final ThreadContext context, final IRubyObject self) {
java.lang.Character c = (java.lang.Character) self.toJava(java.lang.Character.class);
return context.runtime.newFixnum(c);
}

}

@JRubyClass(name = "Java::JavaLang::Class")
1 change: 1 addition & 0 deletions core/src/main/java/org/jruby/runtime/JavaSites.java
Original file line number Diff line number Diff line change
@@ -381,6 +381,7 @@ public static class RationalSites {
public final CallSite remainder = new FunctionalCachingCallSite("remainder");
public final CallSite op_cmp = new FunctionalCachingCallSite("<=>");
public final CheckedSites to_r_checked = new CheckedSites("to_r");
public final RespondToCallSite respond_to_to_r = new RespondToCallSite("to_r");
}

public static class RangeSites {
Loading