summaryrefslogtreecommitdiff
path: root/spec/ruby/core/rational
diff options
context:
space:
mode:
Diffstat (limited to 'spec/ruby/core/rational')
-rw-r--r--spec/ruby/core/rational/abs_spec.rb6
-rw-r--r--spec/ruby/core/rational/ceil_spec.rb45
-rw-r--r--spec/ruby/core/rational/comparison_spec.rb93
-rw-r--r--spec/ruby/core/rational/denominator_spec.rb14
-rw-r--r--spec/ruby/core/rational/div_spec.rb54
-rw-r--r--spec/ruby/core/rational/divide_spec.rb74
-rw-r--r--spec/ruby/core/rational/divmod_spec.rb42
-rw-r--r--spec/ruby/core/rational/equal_value_spec.rb39
-rw-r--r--spec/ruby/core/rational/exponent_spec.rb236
-rw-r--r--spec/ruby/core/rational/fdiv_spec.rb5
-rw-r--r--spec/ruby/core/rational/fixtures/rational.rb14
-rw-r--r--spec/ruby/core/rational/floor_spec.rb45
-rw-r--r--spec/ruby/core/rational/hash_spec.rb9
-rw-r--r--spec/ruby/core/rational/inspect_spec.rb14
-rw-r--r--spec/ruby/core/rational/integer_spec.rb13
-rw-r--r--spec/ruby/core/rational/magnitude_spec.rb6
-rw-r--r--spec/ruby/core/rational/marshal_dump_spec.rb11
-rw-r--r--spec/ruby/core/rational/minus_spec.rb51
-rw-r--r--spec/ruby/core/rational/modulo_spec.rb43
-rw-r--r--spec/ruby/core/rational/multiply_spec.rb65
-rw-r--r--spec/ruby/core/rational/numerator_spec.rb10
-rw-r--r--spec/ruby/core/rational/plus_spec.rb50
-rw-r--r--spec/ruby/core/rational/quo_spec.rb25
-rw-r--r--spec/ruby/core/rational/rational_spec.rb11
-rw-r--r--spec/ruby/core/rational/rationalize_spec.rb36
-rw-r--r--spec/ruby/core/rational/remainder_spec.rb5
-rw-r--r--spec/ruby/core/rational/round_spec.rb106
-rw-r--r--spec/ruby/core/rational/shared/abs.rb11
-rw-r--r--spec/ruby/core/rational/shared/arithmetic_exception_in_coerce.rb11
-rw-r--r--spec/ruby/core/rational/to_f_spec.rb16
-rw-r--r--spec/ruby/core/rational/to_i_spec.rb12
-rw-r--r--spec/ruby/core/rational/to_r_spec.rb26
-rw-r--r--spec/ruby/core/rational/to_s_spec.rb14
-rw-r--r--spec/ruby/core/rational/truncate_spec.rb71
-rw-r--r--spec/ruby/core/rational/zero_spec.rb14
35 files changed, 1297 insertions, 0 deletions
diff --git a/spec/ruby/core/rational/abs_spec.rb b/spec/ruby/core/rational/abs_spec.rb
new file mode 100644
index 0000000000..54099aa14d
--- /dev/null
+++ b/spec/ruby/core/rational/abs_spec.rb
@@ -0,0 +1,6 @@
+require_relative "../../spec_helper"
+require_relative 'shared/abs'
+
+describe "Rational#abs" do
+ it_behaves_like :rational_abs, :abs
+end
diff --git a/spec/ruby/core/rational/ceil_spec.rb b/spec/ruby/core/rational/ceil_spec.rb
new file mode 100644
index 0000000000..d5bdadf3b6
--- /dev/null
+++ b/spec/ruby/core/rational/ceil_spec.rb
@@ -0,0 +1,45 @@
+require_relative "../../spec_helper"
+
+describe "Rational#ceil" do
+ before do
+ @rational = Rational(2200, 7)
+ end
+
+ describe "with no arguments (precision = 0)" do
+ it "returns an Integer" do
+ @rational.ceil.should be_kind_of(Integer)
+ end
+
+ it "returns the truncated value toward positive infinity" do
+ @rational.ceil.should == 315
+ Rational(1, 2).ceil.should == 1
+ Rational(-1, 2).ceil.should == 0
+ end
+ end
+
+ describe "with a precision < 0" do
+ it "returns an Integer" do
+ @rational.ceil(-2).should be_kind_of(Integer)
+ @rational.ceil(-1).should be_kind_of(Integer)
+ end
+
+ it "moves the truncation point n decimal places left" do
+ @rational.ceil(-3).should == 1000
+ @rational.ceil(-2).should == 400
+ @rational.ceil(-1).should == 320
+ end
+ end
+
+ describe "with precision > 0" do
+ it "returns a Rational" do
+ @rational.ceil(1).should be_kind_of(Rational)
+ @rational.ceil(2).should be_kind_of(Rational)
+ end
+
+ it "moves the truncation point n decimal places right" do
+ @rational.ceil(1).should == Rational(3143, 10)
+ @rational.ceil(2).should == Rational(31429, 100)
+ @rational.ceil(3).should == Rational(157143, 500)
+ end
+ end
+end
diff --git a/spec/ruby/core/rational/comparison_spec.rb b/spec/ruby/core/rational/comparison_spec.rb
new file mode 100644
index 0000000000..c9db60d5c7
--- /dev/null
+++ b/spec/ruby/core/rational/comparison_spec.rb
@@ -0,0 +1,93 @@
+require_relative "../../spec_helper"
+require_relative 'fixtures/rational'
+
+describe "Rational#<=> when passed a Rational object" do
+ it "returns 1 when self is greater than the passed argument" do
+ (Rational(4, 4) <=> Rational(3, 4)).should equal(1)
+ (Rational(-3, 4) <=> Rational(-4, 4)).should equal(1)
+ end
+
+ it "returns 0 when self is equal to the passed argument" do
+ (Rational(4, 4) <=> Rational(4, 4)).should equal(0)
+ (Rational(-3, 4) <=> Rational(-3, 4)).should equal(0)
+ end
+
+ it "returns -1 when self is less than the passed argument" do
+ (Rational(3, 4) <=> Rational(4, 4)).should equal(-1)
+ (Rational(-4, 4) <=> Rational(-3, 4)).should equal(-1)
+ end
+end
+
+describe "Rational#<=> when passed an Integer object" do
+ it "returns 1 when self is greater than the passed argument" do
+ (Rational(4, 4) <=> 0).should equal(1)
+ (Rational(4, 4) <=> -10).should equal(1)
+ (Rational(-3, 4) <=> -1).should equal(1)
+ end
+
+ it "returns 0 when self is equal to the passed argument" do
+ (Rational(4, 4) <=> 1).should equal(0)
+ (Rational(-8, 4) <=> -2).should equal(0)
+ end
+
+ it "returns -1 when self is less than the passed argument" do
+ (Rational(3, 4) <=> 1).should equal(-1)
+ (Rational(-4, 4) <=> 0).should equal(-1)
+ end
+end
+
+describe "Rational#<=> when passed a Float object" do
+ it "returns 1 when self is greater than the passed argument" do
+ (Rational(4, 4) <=> 0.5).should equal(1)
+ (Rational(4, 4) <=> -1.5).should equal(1)
+ (Rational(-3, 4) <=> -0.8).should equal(1)
+ end
+
+ it "returns 0 when self is equal to the passed argument" do
+ (Rational(4, 4) <=> 1.0).should equal(0)
+ (Rational(-6, 4) <=> -1.5).should equal(0)
+ end
+
+ it "returns -1 when self is less than the passed argument" do
+ (Rational(3, 4) <=> 1.2).should equal(-1)
+ (Rational(-4, 4) <=> 0.5).should equal(-1)
+ end
+end
+
+describe "Rational#<=> when passed an Object that responds to #coerce" do
+ it "calls #coerce on the passed argument with self" do
+ rational = Rational(3, 4)
+
+ obj = mock("Object")
+ obj.should_receive(:coerce).with(rational).and_return([1, 2])
+
+ rational <=> obj
+ end
+
+ it "calls #<=> on the coerced Rational with the coerced Object" do
+ rational = Rational(3, 4)
+
+ coerced_rational = mock("Coerced Rational")
+ coerced_rational.should_receive(:<=>).and_return(:result)
+
+ coerced_obj = mock("Coerced Object")
+
+ obj = mock("Object")
+ obj.should_receive(:coerce).and_return([coerced_rational, coerced_obj])
+
+ (rational <=> obj).should == :result
+ end
+
+ it "does not rescue exception raised in other#coerce" do
+ b = mock("numeric with failed #coerce")
+ b.should_receive(:coerce).and_raise(RationalSpecs::CoerceError)
+
+ -> { Rational(3, 4) <=> b }.should raise_error(RationalSpecs::CoerceError)
+ end
+end
+
+describe "Rational#<=> when passed a non-Numeric Object that doesn't respond to #coerce" do
+ it "returns nil" do
+ (Rational <=> mock("Object")).should be_nil
+ end
+end
diff --git a/spec/ruby/core/rational/denominator_spec.rb b/spec/ruby/core/rational/denominator_spec.rb
new file mode 100644
index 0000000000..4687244893
--- /dev/null
+++ b/spec/ruby/core/rational/denominator_spec.rb
@@ -0,0 +1,14 @@
+require_relative "../../spec_helper"
+
+describe "Rational#denominator" do
+ it "returns the denominator" do
+ Rational(3, 4).denominator.should equal(4)
+ Rational(3, -4).denominator.should equal(4)
+
+ Rational(1, bignum_value).denominator.should == bignum_value
+ end
+
+ it "returns 1 if no denominator was given" do
+ Rational(80).denominator.should == 1
+ end
+end
diff --git a/spec/ruby/core/rational/div_spec.rb b/spec/ruby/core/rational/div_spec.rb
new file mode 100644
index 0000000000..d3adb9b536
--- /dev/null
+++ b/spec/ruby/core/rational/div_spec.rb
@@ -0,0 +1,54 @@
+require_relative "../../spec_helper"
+
+describe "Rational#div" do
+ it "returns an Integer" do
+ Rational(229, 21).div(82).should be_kind_of(Integer)
+ end
+
+ it "raises an ArgumentError if passed more than one argument" do
+ -> { Rational(3, 4).div(2,3) }.should raise_error(ArgumentError)
+ end
+
+ # See http://redmine.ruby-lang.org/issues/show/1648
+ it "raises a TypeError if passed a non-numeric argument" do
+ -> { Rational(3, 4).div([]) }.should raise_error(TypeError)
+ end
+end
+
+describe "Rational#div passed a Rational" do
+ it "performs integer division and returns the result" do
+ Rational(2, 3).div(Rational(2, 3)).should == 1
+ Rational(-2, 9).div(Rational(-9, 2)).should == 0
+ end
+
+ it "raises a ZeroDivisionError when the argument has a numerator of 0" do
+ -> { Rational(3, 4).div(Rational(0, 3)) }.should raise_error(ZeroDivisionError)
+ end
+
+ it "raises a ZeroDivisionError when the argument has a numerator of 0.0" do
+ -> { Rational(3, 4).div(Rational(0.0, 3)) }.should raise_error(ZeroDivisionError)
+ end
+end
+
+describe "Rational#div passed an Integer" do
+ it "performs integer division and returns the result" do
+ Rational(2, 1).div(1).should == 2
+ Rational(25, 5).div(-50).should == -1
+ end
+
+ it "raises a ZeroDivisionError when the argument is 0" do
+ -> { Rational(3, 4).div(0) }.should raise_error(ZeroDivisionError)
+ end
+end
+
+describe "Rational#div passed a Float" do
+ it "performs integer division and returns the result" do
+ Rational(2, 3).div(30.333).should == 0
+ Rational(2, 9).div(Rational(-8.6)).should == -1
+ Rational(3.12).div(0.5).should == 6
+ end
+
+ it "raises a ZeroDivisionError when the argument is 0.0" do
+ -> { Rational(3, 4).div(0.0) }.should raise_error(ZeroDivisionError)
+ end
+end
diff --git a/spec/ruby/core/rational/divide_spec.rb b/spec/ruby/core/rational/divide_spec.rb
new file mode 100644
index 0000000000..8f5ca1fdec
--- /dev/null
+++ b/spec/ruby/core/rational/divide_spec.rb
@@ -0,0 +1,74 @@
+require_relative "../../spec_helper"
+require_relative 'shared/arithmetic_exception_in_coerce'
+
+describe "Rational#/" do
+ it "calls #coerce on the passed argument with self" do
+ rational = Rational(3, 4)
+ obj = mock("Object")
+ obj.should_receive(:coerce).with(rational).and_return([1, 2])
+
+ rational / obj
+ end
+
+ it "calls #/ on the coerced Rational with the coerced Object" do
+ rational = Rational(3, 4)
+
+ coerced_rational = mock("Coerced Rational")
+ coerced_rational.should_receive(:/).and_return(:result)
+
+ coerced_obj = mock("Coerced Object")
+
+ obj = mock("Object")
+ obj.should_receive(:coerce).and_return([coerced_rational, coerced_obj])
+
+ (rational / obj).should == :result
+ end
+
+ it_behaves_like :rational_arithmetic_exception_in_coerce, :/
+end
+
+describe "Rational#/ when passed an Integer" do
+ it "returns self divided by other as a Rational" do
+ (Rational(3, 4) / 2).should eql(Rational(3, 8))
+ (Rational(2, 4) / 2).should eql(Rational(1, 4))
+ (Rational(6, 7) / -2).should eql(Rational(-3, 7))
+ end
+
+ it "raises a ZeroDivisionError when passed 0" do
+ -> { Rational(3, 4) / 0 }.should raise_error(ZeroDivisionError)
+ end
+end
+
+describe "Rational#/ when passed a Rational" do
+ it "returns self divided by other as a Rational" do
+ (Rational(3, 4) / Rational(3, 4)).should eql(Rational(1, 1))
+ (Rational(2, 4) / Rational(1, 4)).should eql(Rational(2, 1))
+
+ (Rational(2, 4) / 2).should == Rational(1, 4)
+ (Rational(6, 7) / -2).should == Rational(-3, 7)
+ end
+
+ it "raises a ZeroDivisionError when passed a Rational with a numerator of 0" do
+ -> { Rational(3, 4) / Rational(0, 1) }.should raise_error(ZeroDivisionError)
+ end
+end
+
+describe "Rational#/ when passed a Float" do
+ it "returns self divided by other as a Float" do
+ (Rational(3, 4) / 0.75).should eql(1.0)
+ (Rational(3, 4) / 0.25).should eql(3.0)
+ (Rational(3, 4) / 0.3).should eql(2.5)
+
+ (Rational(-3, 4) / 0.3).should eql(-2.5)
+ (Rational(3, -4) / 0.3).should eql(-2.5)
+ (Rational(3, 4) / -0.3).should eql(-2.5)
+ end
+
+ it "returns infinity when passed 0" do
+ (Rational(3, 4) / 0.0).infinite?.should eql(1)
+ (Rational(-3, -4) / 0.0).infinite?.should eql(1)
+
+ (Rational(-3, 4) / 0.0).infinite?.should eql(-1)
+ (Rational(3, -4) / 0.0).infinite?.should eql(-1)
+ end
+end
diff --git a/spec/ruby/core/rational/divmod_spec.rb b/spec/ruby/core/rational/divmod_spec.rb
new file mode 100644
index 0000000000..f0555294a3
--- /dev/null
+++ b/spec/ruby/core/rational/divmod_spec.rb
@@ -0,0 +1,42 @@
+require_relative "../../spec_helper"
+
+describe "Rational#divmod when passed a Rational" do
+ it "returns the quotient as Integer and the remainder as Rational" do
+ Rational(7, 4).divmod(Rational(1, 2)).should eql([3, Rational(1, 4)])
+ Rational(7, 4).divmod(Rational(-1, 2)).should eql([-4, Rational(-1, 4)])
+ Rational(0, 4).divmod(Rational(4, 3)).should eql([0, Rational(0, 1)])
+
+ Rational(bignum_value, 4).divmod(Rational(4, 3)).should eql([3458764513820540928, Rational(0, 1)])
+ end
+
+ it "raises a ZeroDivisionError when passed a Rational with a numerator of 0" do
+ -> { Rational(7, 4).divmod(Rational(0, 3)) }.should raise_error(ZeroDivisionError)
+ end
+end
+
+describe "Rational#divmod when passed an Integer" do
+ it "returns the quotient as Integer and the remainder as Rational" do
+ Rational(7, 4).divmod(2).should eql([0, Rational(7, 4)])
+ Rational(7, 4).divmod(-2).should eql([-1, Rational(-1, 4)])
+
+ Rational(bignum_value, 4).divmod(3).should eql([1537228672809129301, Rational(1, 1)])
+ end
+
+ it "raises a ZeroDivisionError when passed 0" do
+ -> { Rational(7, 4).divmod(0) }.should raise_error(ZeroDivisionError)
+ end
+end
+
+describe "Rational#divmod when passed a Float" do
+ it "returns the quotient as Integer and the remainder as Float" do
+ Rational(7, 4).divmod(0.5).should eql([3, 0.25])
+ end
+
+ it "returns the quotient as Integer and the remainder as Float" do
+ Rational(7, 4).divmod(-0.5).should eql([-4, -0.25])
+ end
+
+ it "raises a ZeroDivisionError when passed 0" do
+ -> { Rational(7, 4).divmod(0.0) }.should raise_error(ZeroDivisionError)
+ end
+end
diff --git a/spec/ruby/core/rational/equal_value_spec.rb b/spec/ruby/core/rational/equal_value_spec.rb
new file mode 100644
index 0000000000..ba40d29c3b
--- /dev/null
+++ b/spec/ruby/core/rational/equal_value_spec.rb
@@ -0,0 +1,39 @@
+require_relative "../../spec_helper"
+
+describe "Rational#==" do
+ it "returns the result of calling #== with self on the passed argument" do
+ obj = mock("Object")
+ obj.should_receive(:==).and_return(:result)
+
+ (Rational(3, 4) == obj).should_not be_false
+ end
+end
+
+describe "Rational#== when passed a Rational" do
+ it "returns true if self has the same numerator and denominator as the passed argument" do
+ (Rational(3, 4) == Rational(3, 4)).should be_true
+ (Rational(-3, -4) == Rational(3, 4)).should be_true
+ (Rational(-4, 5) == Rational(4, -5)).should be_true
+
+ (Rational(bignum_value, 3) == Rational(bignum_value, 3)).should be_true
+ (Rational(-bignum_value, 3) == Rational(bignum_value, -3)).should be_true
+ end
+end
+
+describe "Rational#== when passed a Float" do
+ it "converts self to a Float and compares it with the passed argument" do
+ (Rational(3, 4) == 0.75).should be_true
+ (Rational(4, 2) == 2.0).should be_true
+ (Rational(-4, 2) == -2.0).should be_true
+ (Rational(4, -2) == -2.0).should be_true
+ end
+end
+
+describe "Rational#== when passed an Integer" do
+ it "returns true if self has the passed argument as numerator and a denominator of 1" do
+ # Rational(x, y) reduces x and y automatically
+ (Rational(4, 2) == 2).should be_true
+ (Rational(-4, 2) == -2).should be_true
+ (Rational(4, -2) == -2).should be_true
+ end
+end
diff --git a/spec/ruby/core/rational/exponent_spec.rb b/spec/ruby/core/rational/exponent_spec.rb
new file mode 100644
index 0000000000..65fbf2ed1c
--- /dev/null
+++ b/spec/ruby/core/rational/exponent_spec.rb
@@ -0,0 +1,236 @@
+require_relative "../../spec_helper"
+
+describe "Rational#**" do
+ describe "when passed Rational" do
+ # Guard against the Mathn library
+ guard -> { !defined?(Math.rsqrt) } do
+ it "returns Rational(1) if the exponent is Rational(0)" do
+ (Rational(0) ** Rational(0)).should eql(Rational(1))
+ (Rational(1) ** Rational(0)).should eql(Rational(1))
+ (Rational(3, 4) ** Rational(0)).should eql(Rational(1))
+ (Rational(-1) ** Rational(0)).should eql(Rational(1))
+ (Rational(-3, 4) ** Rational(0)).should eql(Rational(1))
+ (Rational(bignum_value) ** Rational(0)).should eql(Rational(1))
+ (Rational(-bignum_value) ** Rational(0)).should eql(Rational(1))
+ end
+
+ it "returns self raised to the argument as a Rational if the exponent's denominator is 1" do
+ (Rational(3, 4) ** Rational(1, 1)).should eql(Rational(3, 4))
+ (Rational(3, 4) ** Rational(2, 1)).should eql(Rational(9, 16))
+ (Rational(3, 4) ** Rational(-1, 1)).should eql(Rational(4, 3))
+ (Rational(3, 4) ** Rational(-2, 1)).should eql(Rational(16, 9))
+ end
+
+ it "returns self raised to the argument as a Float if the exponent's denominator is not 1" do
+ (Rational(3, 4) ** Rational(4, 3)).should be_close(0.681420222312052, TOLERANCE)
+ (Rational(3, 4) ** Rational(-4, 3)).should be_close(1.46752322173095, TOLERANCE)
+ (Rational(3, 4) ** Rational(4, -3)).should be_close(1.46752322173095, TOLERANCE)
+ end
+
+ it "returns a complex number when self is negative and the passed argument is not 0" do
+ (Rational(-3, 4) ** Rational(-4, 3)).should be_close(Complex(-0.7337616108654732, 1.2709123906625817), TOLERANCE)
+ end
+ end
+ end
+
+ describe "when passed Integer" do
+ it "returns the Rational value of self raised to the passed argument" do
+ (Rational(3, 4) ** 4).should == Rational(81, 256)
+ (Rational(3, 4) ** -4).should == Rational(256, 81)
+ (Rational(-3, 4) ** -4).should == Rational(256, 81)
+ (Rational(3, -4) ** -4).should == Rational(256, 81)
+
+ (Rational(bignum_value, 4) ** 4).should == Rational(452312848583266388373324160190187140051835877600158453279131187530910662656, 1)
+ (Rational(3, bignum_value) ** -4).should == Rational(115792089237316195423570985008687907853269984665640564039457584007913129639936, 81)
+ (Rational(-bignum_value, 4) ** -4).should == Rational(1, 452312848583266388373324160190187140051835877600158453279131187530910662656)
+ (Rational(3, -bignum_value) ** -4).should == Rational(115792089237316195423570985008687907853269984665640564039457584007913129639936, 81)
+ end
+
+ # Guard against the Mathn library
+ guard -> { !defined?(Math.rsqrt) } do
+ it "returns Rational(1, 1) when the passed argument is 0" do
+ (Rational(3, 4) ** 0).should eql(Rational(1, 1))
+ (Rational(-3, 4) ** 0).should eql(Rational(1, 1))
+ (Rational(3, -4) ** 0).should eql(Rational(1, 1))
+
+ (Rational(bignum_value, 4) ** 0).should eql(Rational(1, 1))
+ (Rational(3, -bignum_value) ** 0).should eql(Rational(1, 1))
+ end
+ end
+ end
+
+ describe "when passed Bignum" do
+ # #5713
+ it "returns Rational(0) when self is Rational(0) and the exponent is positive" do
+ (Rational(0) ** bignum_value).should eql(Rational(0))
+ end
+
+ it "raises ZeroDivisionError when self is Rational(0) and the exponent is negative" do
+ -> { Rational(0) ** -bignum_value }.should raise_error(ZeroDivisionError)
+ end
+
+ it "returns Rational(1) when self is Rational(1)" do
+ (Rational(1) ** bignum_value).should eql(Rational(1))
+ (Rational(1) ** -bignum_value).should eql(Rational(1))
+ end
+
+ it "returns Rational(1) when self is Rational(-1) and the exponent is positive and even" do
+ (Rational(-1) ** bignum_value(0)).should eql(Rational(1))
+ (Rational(-1) ** bignum_value(2)).should eql(Rational(1))
+ end
+
+ it "returns Rational(-1) when self is Rational(-1) and the exponent is positive and odd" do
+ (Rational(-1) ** bignum_value(1)).should eql(Rational(-1))
+ (Rational(-1) ** bignum_value(3)).should eql(Rational(-1))
+ end
+
+ ruby_version_is ""..."3.4" do
+ it "returns positive Infinity when self is > 1" do
+ -> {
+ (Rational(2) ** bignum_value).infinite?.should == 1
+ }.should complain(/warning: in a\*\*b, b may be too big/)
+ -> {
+ (Rational(fixnum_max) ** bignum_value).infinite?.should == 1
+ }.should complain(/warning: in a\*\*b, b may be too big/)
+ end
+
+ it "returns 0.0 when self is > 1 and the exponent is negative" do
+ -> {
+ (Rational(2) ** -bignum_value).should eql(0.0)
+ }.should complain(/warning: in a\*\*b, b may be too big/)
+ -> {
+ (Rational(fixnum_max) ** -bignum_value).should eql(0.0)
+ }.should complain(/warning: in a\*\*b, b may be too big/)
+ end
+ end
+
+ ruby_version_is "3.4" do
+ it "raises an ArgumentError when self is > 1" do
+ -> {
+ (Rational(2) ** bignum_value)
+ }.should raise_error(ArgumentError)
+ -> {
+ (Rational(fixnum_max) ** bignum_value)
+ }.should raise_error(ArgumentError)
+ end
+
+ it "raises an ArgumentError when self is > 1 and the exponent is negative" do
+ -> {
+ (Rational(2) ** -bignum_value)
+ }.should raise_error(ArgumentError)
+ -> {
+ (Rational(fixnum_max) ** -bignum_value)
+ }.should raise_error(ArgumentError)
+ end
+
+ it "raises an ArgumentError when self is < -1" do
+ -> {
+ (Rational(-2) ** bignum_value)
+ }.should raise_error(ArgumentError)
+ -> {
+ (Rational(fixnum_min) ** bignum_value)
+ }.should raise_error(ArgumentError)
+ end
+
+ it "raises an ArgumentError when self is < -1 and the exponent is negative" do
+ -> {
+ (Rational(-2) ** -bignum_value)
+ }.should raise_error(ArgumentError)
+ -> {
+ (Rational(fixnum_min) ** -bignum_value)
+ }.should raise_error(ArgumentError)
+ end
+ end
+
+ # Fails on linux due to pow() bugs in glibc: http://sources.redhat.com/bugzilla/show_bug.cgi?id=3866
+ platform_is_not :linux do
+ ruby_version_is ""..."3.4" do
+ it "returns positive Infinity when self < -1" do
+ -> {
+ (Rational(-2) ** bignum_value).infinite?.should == 1
+ }.should complain(/warning: in a\*\*b, b may be too big/)
+ -> {
+ (Rational(-2) ** (bignum_value + 1)).infinite?.should == 1
+ }.should complain(/warning: in a\*\*b, b may be too big/)
+ -> {
+ (Rational(fixnum_min) ** bignum_value).infinite?.should == 1
+ }.should complain(/warning: in a\*\*b, b may be too big/)
+ end
+
+ it "returns 0.0 when self is < -1 and the exponent is negative" do
+ -> {
+ (Rational(-2) ** -bignum_value).should eql(0.0)
+ }.should complain(/warning: in a\*\*b, b may be too big/)
+ -> {
+ (Rational(fixnum_min) ** -bignum_value).should eql(0.0)
+ }.should complain(/warning: in a\*\*b, b may be too big/)
+ end
+ end
+ end
+ end
+
+ describe "when passed Float" do
+ it "returns self converted to Float and raised to the passed argument" do
+ (Rational(3, 1) ** 3.0).should eql(27.0)
+ (Rational(3, 1) ** 1.5).should be_close(5.19615242270663, TOLERANCE)
+ (Rational(3, 1) ** -1.5).should be_close(0.192450089729875, TOLERANCE)
+ end
+
+ it "returns a complex number if self is negative and the passed argument is not 0" do
+ (Rational(-3, 2) ** 1.5).should be_close(Complex(0.0, -1.8371173070873836), TOLERANCE)
+ (Rational(3, -2) ** 1.5).should be_close(Complex(0.0, -1.8371173070873836), TOLERANCE)
+ (Rational(3, -2) ** -1.5).should be_close(Complex(0.0, 0.5443310539518174), TOLERANCE)
+ end
+
+ it "returns Complex(1.0) when the passed argument is 0.0" do
+ (Rational(3, 4) ** 0.0).should == Complex(1.0)
+ (Rational(-3, 4) ** 0.0).should == Complex(1.0)
+ (Rational(-3, 4) ** 0.0).should == Complex(1.0)
+ end
+ end
+
+ it "calls #coerce on the passed argument with self" do
+ rational = Rational(3, 4)
+ obj = mock("Object")
+ obj.should_receive(:coerce).with(rational).and_return([1, 2])
+
+ rational ** obj
+ end
+
+ it "calls #** on the coerced Rational with the coerced Object" do
+ rational = Rational(3, 4)
+
+ coerced_rational = mock("Coerced Rational")
+ coerced_rational.should_receive(:**).and_return(:result)
+
+ coerced_obj = mock("Coerced Object")
+
+ obj = mock("Object")
+ obj.should_receive(:coerce).and_return([coerced_rational, coerced_obj])
+
+ (rational ** obj).should == :result
+ end
+
+ it "raises ZeroDivisionError for Rational(0, 1) passed a negative Integer" do
+ [-1, -4, -9999].each do |exponent|
+ -> { Rational(0, 1) ** exponent }.should raise_error(ZeroDivisionError, "divided by 0")
+ end
+ end
+
+ it "raises ZeroDivisionError for Rational(0, 1) passed a negative Rational with denominator 1" do
+ [Rational(-1, 1), Rational(-3, 1)].each do |exponent|
+ -> { Rational(0, 1) ** exponent }.should raise_error(ZeroDivisionError, "divided by 0")
+ end
+ end
+
+ # #7513
+ it "raises ZeroDivisionError for Rational(0, 1) passed a negative Rational" do
+ -> { Rational(0, 1) ** Rational(-3, 2) }.should raise_error(ZeroDivisionError, "divided by 0")
+ end
+
+ it "returns Infinity for Rational(0, 1) passed a negative Float" do
+ [-1.0, -3.0, -3.14].each do |exponent|
+ (Rational(0, 1) ** exponent).infinite?.should == 1
+ end
+ end
+end
diff --git a/spec/ruby/core/rational/fdiv_spec.rb b/spec/ruby/core/rational/fdiv_spec.rb
new file mode 100644
index 0000000000..118d93dbe7
--- /dev/null
+++ b/spec/ruby/core/rational/fdiv_spec.rb
@@ -0,0 +1,5 @@
+require_relative "../../spec_helper"
+
+describe "Rational#fdiv" do
+ it "needs to be reviewed for spec completeness"
+end
diff --git a/spec/ruby/core/rational/fixtures/rational.rb b/spec/ruby/core/rational/fixtures/rational.rb
new file mode 100644
index 0000000000..844d7f9820
--- /dev/null
+++ b/spec/ruby/core/rational/fixtures/rational.rb
@@ -0,0 +1,14 @@
+module RationalSpecs
+ class SubNumeric < Numeric
+ def initialize(value)
+ @value = Rational(value)
+ end
+
+ def to_r
+ @value
+ end
+ end
+
+ class CoerceError < StandardError
+ end
+end
diff --git a/spec/ruby/core/rational/floor_spec.rb b/spec/ruby/core/rational/floor_spec.rb
new file mode 100644
index 0000000000..8068aaf119
--- /dev/null
+++ b/spec/ruby/core/rational/floor_spec.rb
@@ -0,0 +1,45 @@
+require_relative "../../spec_helper"
+
+describe "Rational#floor" do
+ before do
+ @rational = Rational(2200, 7)
+ end
+
+ describe "with no arguments (precision = 0)" do
+ it "returns an integer" do
+ @rational.floor.should be_kind_of(Integer)
+ end
+
+ it "returns the truncated value toward negative infinity" do
+ @rational.floor.should == 314
+ Rational(1, 2).floor.should == 0
+ Rational(-1, 2).floor.should == -1
+ end
+ end
+
+ describe "with a precision < 0" do
+ it "returns an integer" do
+ @rational.floor(-2).should be_kind_of(Integer)
+ @rational.floor(-1).should be_kind_of(Integer)
+ end
+
+ it "moves the truncation point n decimal places left" do
+ @rational.floor(-3).should == 0
+ @rational.floor(-2).should == 300
+ @rational.floor(-1).should == 310
+ end
+ end
+
+ describe "with a precision > 0" do
+ it "returns a Rational" do
+ @rational.floor(1).should be_kind_of(Rational)
+ @rational.floor(2).should be_kind_of(Rational)
+ end
+
+ it "moves the truncation point n decimal places right" do
+ @rational.floor(1).should == Rational(1571, 5)
+ @rational.floor(2).should == Rational(7857, 25)
+ @rational.floor(3).should == Rational(62857, 200)
+ end
+ end
+end
diff --git a/spec/ruby/core/rational/hash_spec.rb b/spec/ruby/core/rational/hash_spec.rb
new file mode 100644
index 0000000000..528638056a
--- /dev/null
+++ b/spec/ruby/core/rational/hash_spec.rb
@@ -0,0 +1,9 @@
+require_relative "../../spec_helper"
+
+describe "Rational#hash" do
+ # BUG: Rational(2, 3).hash == Rational(3, 2).hash
+ it "is static" do
+ Rational(2, 3).hash.should == Rational(2, 3).hash
+ Rational(2, 4).hash.should_not == Rational(2, 3).hash
+ end
+end
diff --git a/spec/ruby/core/rational/inspect_spec.rb b/spec/ruby/core/rational/inspect_spec.rb
new file mode 100644
index 0000000000..edc5cffee9
--- /dev/null
+++ b/spec/ruby/core/rational/inspect_spec.rb
@@ -0,0 +1,14 @@
+require_relative "../../spec_helper"
+
+describe "Rational#inspect" do
+ it "returns a string representation of self" do
+ Rational(3, 4).inspect.should == "(3/4)"
+ Rational(-5, 8).inspect.should == "(-5/8)"
+ Rational(-1, -2).inspect.should == "(1/2)"
+
+ # Guard against the Mathn library
+ guard -> { !defined?(Math.rsqrt) } do
+ Rational(bignum_value, 1).inspect.should == "(#{bignum_value}/1)"
+ end
+ end
+end
diff --git a/spec/ruby/core/rational/integer_spec.rb b/spec/ruby/core/rational/integer_spec.rb
new file mode 100644
index 0000000000..be7476a9dd
--- /dev/null
+++ b/spec/ruby/core/rational/integer_spec.rb
@@ -0,0 +1,13 @@
+require_relative "../../spec_helper"
+describe "Rational#integer?" do
+ # Guard against the Mathn library
+ guard -> { !defined?(Math.rsqrt) } do
+ it "returns false for a rational with a numerator and no denominator" do
+ Rational(20).integer?.should be_false
+ end
+ end
+
+ it "returns false for a rational with a numerator and a denominator" do
+ Rational(20,3).integer?.should be_false
+ end
+end
diff --git a/spec/ruby/core/rational/magnitude_spec.rb b/spec/ruby/core/rational/magnitude_spec.rb
new file mode 100644
index 0000000000..f5f667edb1
--- /dev/null
+++ b/spec/ruby/core/rational/magnitude_spec.rb
@@ -0,0 +1,6 @@
+require_relative "../../spec_helper"
+require_relative 'shared/abs'
+
+describe "Rational#abs" do
+ it_behaves_like :rational_abs, :magnitude
+end
diff --git a/spec/ruby/core/rational/marshal_dump_spec.rb b/spec/ruby/core/rational/marshal_dump_spec.rb
new file mode 100644
index 0000000000..17a6107cd5
--- /dev/null
+++ b/spec/ruby/core/rational/marshal_dump_spec.rb
@@ -0,0 +1,11 @@
+require_relative '../../spec_helper'
+
+describe "Rational#marshal_dump" do
+ it "is a private method" do
+ Rational.should have_private_instance_method(:marshal_dump, false)
+ end
+
+ it "dumps numerator and denominator" do
+ Rational(1, 2).send(:marshal_dump).should == [1, 2]
+ end
+end
diff --git a/spec/ruby/core/rational/minus_spec.rb b/spec/ruby/core/rational/minus_spec.rb
new file mode 100644
index 0000000000..8aee85f9dd
--- /dev/null
+++ b/spec/ruby/core/rational/minus_spec.rb
@@ -0,0 +1,51 @@
+require_relative '../../spec_helper'
+require_relative 'shared/arithmetic_exception_in_coerce'
+
+describe "Rational#-" do
+ it_behaves_like :rational_arithmetic_exception_in_coerce, :-
+
+ it "calls #coerce on the passed argument with self" do
+ rational = Rational(3, 4)
+ obj = mock("Object")
+ obj.should_receive(:coerce).with(rational).and_return([1, 2])
+
+ rational - obj
+ end
+
+ it "calls #- on the coerced Rational with the coerced Object" do
+ rational = Rational(3, 4)
+
+ coerced_rational = mock("Coerced Rational")
+ coerced_rational.should_receive(:-).and_return(:result)
+
+ coerced_obj = mock("Coerced Object")
+
+ obj = mock("Object")
+ obj.should_receive(:coerce).and_return([coerced_rational, coerced_obj])
+
+ (rational - obj).should == :result
+ end
+end
+
+describe "Rational#- passed a Rational" do
+ it "returns the result of subtracting other from self as a Rational" do
+ (Rational(3, 4) - Rational(0, 1)).should eql(Rational(3, 4))
+ (Rational(3, 4) - Rational(1, 4)).should eql(Rational(1, 2))
+
+ (Rational(3, 4) - Rational(2, 1)).should eql(Rational(-5, 4))
+ end
+end
+
+describe "Rational#- passed a Float" do
+ it "returns the result of subtracting other from self as a Float" do
+ (Rational(3, 4) - 0.2).should eql(0.55)
+ (Rational(3, 4) - 2.5).should eql(-1.75)
+ end
+end
+
+describe "Rational#- passed an Integer" do
+ it "returns the result of subtracting other from self as a Rational" do
+ (Rational(3, 4) - 1).should eql(Rational(-1, 4))
+ (Rational(3, 4) - 2).should eql(Rational(-5, 4))
+ end
+end
diff --git a/spec/ruby/core/rational/modulo_spec.rb b/spec/ruby/core/rational/modulo_spec.rb
new file mode 100644
index 0000000000..23ed93e118
--- /dev/null
+++ b/spec/ruby/core/rational/modulo_spec.rb
@@ -0,0 +1,43 @@
+require_relative "../../spec_helper"
+
+describe "Rational#%" do
+ it "returns the remainder when this value is divided by other" do
+ (Rational(2, 3) % Rational(2, 3)).should == Rational(0, 1)
+ (Rational(4, 3) % Rational(2, 3)).should == Rational(0, 1)
+ (Rational(2, -3) % Rational(-2, 3)).should == Rational(0, 1)
+ (Rational(0, -1) % -1).should == Rational(0, 1)
+
+ (Rational(7, 4) % Rational(1, 2)).should == Rational(1, 4)
+ (Rational(7, 4) % 1).should == Rational(3, 4)
+ (Rational(7, 4) % Rational(1, 7)).should == Rational(1, 28)
+
+ (Rational(3, 4) % -1).should == Rational(-1, 4)
+ (Rational(1, -5) % -1).should == Rational(-1, 5)
+ end
+
+ it "returns a Float value when the argument is Float" do
+ (Rational(7, 4) % 1.0).should be_kind_of(Float)
+ (Rational(7, 4) % 1.0).should == 0.75
+ (Rational(7, 4) % 0.26).should be_close(0.19, 0.0001)
+ end
+
+ it "raises ZeroDivisionError on zero denominator" do
+ -> {
+ Rational(3, 5) % Rational(0, 1)
+ }.should raise_error(ZeroDivisionError)
+
+ -> {
+ Rational(0, 1) % Rational(0, 1)
+ }.should raise_error(ZeroDivisionError)
+
+ -> {
+ Rational(3, 5) % 0
+ }.should raise_error(ZeroDivisionError)
+ end
+
+ it "raises a ZeroDivisionError when the argument is 0.0" do
+ -> {
+ Rational(3, 5) % 0.0
+ }.should raise_error(ZeroDivisionError)
+ end
+end
diff --git a/spec/ruby/core/rational/multiply_spec.rb b/spec/ruby/core/rational/multiply_spec.rb
new file mode 100644
index 0000000000..87fb4de2b4
--- /dev/null
+++ b/spec/ruby/core/rational/multiply_spec.rb
@@ -0,0 +1,65 @@
+require_relative "../../spec_helper"
+require_relative 'shared/arithmetic_exception_in_coerce'
+
+describe "Rational#*" do
+ it "calls #coerce on the passed argument with self" do
+ rational = Rational(3, 4)
+ obj = mock("Object")
+ obj.should_receive(:coerce).with(rational).and_return([1, 2])
+
+ rational * obj
+ end
+
+ it "calls #* on the coerced Rational with the coerced Object" do
+ rational = Rational(3, 4)
+
+ coerced_rational = mock("Coerced Rational")
+ coerced_rational.should_receive(:*).and_return(:result)
+
+ coerced_obj = mock("Coerced Object")
+
+ obj = mock("Object")
+ obj.should_receive(:coerce).and_return([coerced_rational, coerced_obj])
+
+ (rational * obj).should == :result
+ end
+
+ it_behaves_like :rational_arithmetic_exception_in_coerce, :*
+end
+
+describe "Rational#* passed a Rational" do
+ it "returns self divided by other as a Rational" do
+ (Rational(3, 4) * Rational(3, 4)).should eql(Rational(9, 16))
+ (Rational(2, 4) * Rational(1, 4)).should eql(Rational(1, 8))
+
+ (Rational(3, 4) * Rational(0, 1)).should eql(Rational(0, 4))
+ end
+end
+
+describe "Rational#* passed a Float" do
+ it "returns self divided by other as a Float" do
+ (Rational(3, 4) * 0.75).should eql(0.5625)
+ (Rational(3, 4) * 0.25).should eql(0.1875)
+ (Rational(3, 4) * 0.3).should be_close(0.225, TOLERANCE)
+
+ (Rational(-3, 4) * 0.3).should be_close(-0.225, TOLERANCE)
+ (Rational(3, -4) * 0.3).should be_close(-0.225, TOLERANCE)
+ (Rational(3, 4) * -0.3).should be_close(-0.225, TOLERANCE)
+
+ (Rational(3, 4) * 0.0).should eql(0.0)
+ (Rational(-3, -4) * 0.0).should eql(0.0)
+
+ (Rational(-3, 4) * 0.0).should eql(0.0)
+ (Rational(3, -4) * 0.0).should eql(0.0)
+ end
+end
+
+describe "Rational#* passed an Integer" do
+ it "returns self divided by other as a Rational" do
+ (Rational(3, 4) * 2).should eql(Rational(3, 2))
+ (Rational(2, 4) * 2).should eql(Rational(1, 1))
+ (Rational(6, 7) * -2).should eql(Rational(-12, 7))
+
+ (Rational(3, 4) * 0).should eql(Rational(0, 4))
+ end
+end
diff --git a/spec/ruby/core/rational/numerator_spec.rb b/spec/ruby/core/rational/numerator_spec.rb
new file mode 100644
index 0000000000..2b9fe2ff5c
--- /dev/null
+++ b/spec/ruby/core/rational/numerator_spec.rb
@@ -0,0 +1,10 @@
+require_relative "../../spec_helper"
+
+describe "Rational#numerator" do
+ it "returns the numerator" do
+ Rational(3, 4).numerator.should equal(3)
+ Rational(3, -4).numerator.should equal(-3)
+
+ Rational(bignum_value, 1).numerator.should == bignum_value
+ end
+end
diff --git a/spec/ruby/core/rational/plus_spec.rb b/spec/ruby/core/rational/plus_spec.rb
new file mode 100644
index 0000000000..01df5f6719
--- /dev/null
+++ b/spec/ruby/core/rational/plus_spec.rb
@@ -0,0 +1,50 @@
+require_relative "../../spec_helper"
+require_relative 'shared/arithmetic_exception_in_coerce'
+
+describe "Rational#+" do
+ it "calls #coerce on the passed argument with self" do
+ rational = Rational(3, 4)
+ obj = mock("Object")
+ obj.should_receive(:coerce).with(rational).and_return([1, 2])
+
+ rational + obj
+ end
+
+ it "calls #+ on the coerced Rational with the coerced Object" do
+ rational = Rational(3, 4)
+
+ coerced_rational = mock("Coerced Rational")
+ coerced_rational.should_receive(:+).and_return(:result)
+
+ coerced_obj = mock("Coerced Object")
+
+ obj = mock("Object")
+ obj.should_receive(:coerce).and_return([coerced_rational, coerced_obj])
+
+ (rational + obj).should == :result
+ end
+
+ it_behaves_like :rational_arithmetic_exception_in_coerce, :+
+end
+
+describe "Rational#+ with a Rational" do
+ it "returns the result of subtracting other from self as a Rational" do
+ (Rational(3, 4) + Rational(0, 1)).should eql(Rational(3, 4))
+ (Rational(3, 4) + Rational(1, 4)).should eql(Rational(1, 1))
+
+ (Rational(3, 4) + Rational(2, 1)).should eql(Rational(11, 4))
+ end
+end
+describe "Rational#+ with a Float" do
+ it "returns the result of subtracting other from self as a Float" do
+ (Rational(3, 4) + 0.2).should eql(0.95)
+ (Rational(3, 4) + 2.5).should eql(3.25)
+ end
+end
+
+describe "Rational#+ with an Integer" do
+ it "returns the result of subtracting other from self as a Rational" do
+ (Rational(3, 4) + 1).should eql(Rational(7, 4))
+ (Rational(3, 4) + 2).should eql(Rational(11, 4))
+ end
+end
diff --git a/spec/ruby/core/rational/quo_spec.rb b/spec/ruby/core/rational/quo_spec.rb
new file mode 100644
index 0000000000..907898ad34
--- /dev/null
+++ b/spec/ruby/core/rational/quo_spec.rb
@@ -0,0 +1,25 @@
+require_relative "../../spec_helper"
+
+describe "Rational#quo" do
+ it "calls #coerce on the passed argument with self" do
+ rational = Rational(3, 4)
+ obj = mock("Object")
+ obj.should_receive(:coerce).with(rational).and_return([1, 2])
+
+ rational.quo(obj)
+ end
+
+ it "calls #/ on the coerced Rational with the coerced Object" do
+ rational = Rational(3, 4)
+
+ coerced_rational = mock("Coerced Rational")
+ coerced_rational.should_receive(:/).and_return(:result)
+
+ coerced_obj = mock("Coerced Object")
+
+ obj = mock("Object")
+ obj.should_receive(:coerce).and_return([coerced_rational, coerced_obj])
+
+ rational.quo(obj).should == :result
+ end
+end
diff --git a/spec/ruby/core/rational/rational_spec.rb b/spec/ruby/core/rational/rational_spec.rb
new file mode 100644
index 0000000000..482deab38d
--- /dev/null
+++ b/spec/ruby/core/rational/rational_spec.rb
@@ -0,0 +1,11 @@
+require_relative '../../spec_helper'
+
+describe "Rational" do
+ it "includes Comparable" do
+ Rational.include?(Comparable).should == true
+ end
+
+ it "does not respond to new" do
+ -> { Rational.new(1) }.should raise_error(NoMethodError)
+ end
+end
diff --git a/spec/ruby/core/rational/rationalize_spec.rb b/spec/ruby/core/rational/rationalize_spec.rb
new file mode 100644
index 0000000000..3db027d446
--- /dev/null
+++ b/spec/ruby/core/rational/rationalize_spec.rb
@@ -0,0 +1,36 @@
+require_relative '../../spec_helper'
+
+describe "Rational#rationalize" do
+ it "returns self with no argument" do
+ Rational(12,3).rationalize.should == Rational(12,3)
+ Rational(-45,7).rationalize.should == Rational(-45,7)
+ end
+
+ # FIXME: These specs need reviewing by somebody familiar with the
+ # algorithm used by #rationalize
+ it "simplifies self to the degree specified by a Rational argument" do
+ r = Rational(5404319552844595,18014398509481984)
+ r.rationalize(Rational(1,10)).should == Rational(1,3)
+ r.rationalize(Rational(-1,10)).should == Rational(1,3)
+
+ r = Rational(-5404319552844595,18014398509481984)
+ r.rationalize(Rational(1,10)).should == Rational(-1,3)
+ r.rationalize(Rational(-1,10)).should == Rational(-1,3)
+
+ end
+
+ it "simplifies self to the degree specified by a Float argument" do
+ r = Rational(5404319552844595,18014398509481984)
+ r.rationalize(0.05).should == Rational(1,3)
+ r.rationalize(0.001).should == Rational(3, 10)
+
+ r = Rational(-5404319552844595,18014398509481984)
+ r.rationalize(0.05).should == Rational(-1,3)
+ r.rationalize(0.001).should == Rational(-3,10)
+ end
+
+ it "raises ArgumentError when passed more than one argument" do
+ -> { Rational(1,1).rationalize(0.1, 0.1) }.should raise_error(ArgumentError)
+ -> { Rational(1,1).rationalize(0.1, 0.1, 2) }.should raise_error(ArgumentError)
+ end
+end
diff --git a/spec/ruby/core/rational/remainder_spec.rb b/spec/ruby/core/rational/remainder_spec.rb
new file mode 100644
index 0000000000..86ba4674e6
--- /dev/null
+++ b/spec/ruby/core/rational/remainder_spec.rb
@@ -0,0 +1,5 @@
+require_relative "../../spec_helper"
+
+describe "Rational#remainder" do
+ it "needs to be reviewed for spec completeness"
+end
diff --git a/spec/ruby/core/rational/round_spec.rb b/spec/ruby/core/rational/round_spec.rb
new file mode 100644
index 0000000000..ac3dcafe7b
--- /dev/null
+++ b/spec/ruby/core/rational/round_spec.rb
@@ -0,0 +1,106 @@
+require_relative '../../spec_helper'
+
+describe "Rational#round" do
+ before do
+ @rational = Rational(2200, 7)
+ end
+
+ describe "with no arguments (precision = 0)" do
+ it "returns an integer" do
+ @rational.round.should be_kind_of(Integer)
+ Rational(0, 1).round(0).should be_kind_of(Integer)
+ Rational(124, 1).round(0).should be_kind_of(Integer)
+ end
+
+ it "returns the truncated value toward the nearest integer" do
+ @rational.round.should == 314
+ Rational(0, 1).round(0).should == 0
+ Rational(2, 1).round(0).should == 2
+ end
+
+ it "returns the rounded value toward the nearest integer" do
+ Rational(1, 2).round.should == 1
+ Rational(-1, 2).round.should == -1
+ Rational(3, 2).round.should == 2
+ Rational(-3, 2).round.should == -2
+ Rational(5, 2).round.should == 3
+ Rational(-5, 2).round.should == -3
+ end
+ end
+
+ describe "with a precision < 0" do
+ it "returns an integer" do
+ @rational.round(-2).should be_kind_of(Integer)
+ @rational.round(-1).should be_kind_of(Integer)
+ Rational(0, 1).round(-1).should be_kind_of(Integer)
+ Rational(2, 1).round(-1).should be_kind_of(Integer)
+ end
+
+ it "moves the truncation point n decimal places left" do
+ @rational.round(-3).should == 0
+ @rational.round(-2).should == 300
+ @rational.round(-1).should == 310
+ end
+ end
+
+ describe "with a precision > 0" do
+ it "returns a Rational" do
+ @rational.round(1).should be_kind_of(Rational)
+ @rational.round(2).should be_kind_of(Rational)
+ # Guard against the Mathn library
+ guard -> { !defined?(Math.rsqrt) } do
+ Rational(0, 1).round(1).should be_kind_of(Rational)
+ Rational(2, 1).round(1).should be_kind_of(Rational)
+ end
+ end
+
+ it "moves the truncation point n decimal places right" do
+ @rational.round(1).should == Rational(3143, 10)
+ @rational.round(2).should == Rational(31429, 100)
+ @rational.round(3).should == Rational(157143, 500)
+ Rational(0, 1).round(1).should == Rational(0, 1)
+ Rational(2, 1).round(1).should == Rational(2, 1)
+ end
+
+ it "doesn't alter the value if the precision is too great" do
+ Rational(3, 2).round(10).should == Rational(3, 2).round(20)
+ end
+
+ # #6605
+ it "doesn't fail when rounding to an absurdly large positive precision" do
+ Rational(3, 2).round(2_097_171).should == Rational(3, 2)
+ end
+ end
+
+ describe "with half option" do
+ it "returns an Integer when precision is not passed" do
+ Rational(10, 4).round(half: nil).should == 3
+ Rational(10, 4).round(half: :up).should == 3
+ Rational(10, 4).round(half: :down).should == 2
+ Rational(10, 4).round(half: :even).should == 2
+ Rational(-10, 4).round(half: nil).should == -3
+ Rational(-10, 4).round(half: :up).should == -3
+ Rational(-10, 4).round(half: :down).should == -2
+ Rational(-10, 4).round(half: :even).should == -2
+ end
+
+ it "returns a Rational when the precision is greater than 0" do
+ Rational(25, 100).round(1, half: nil).should == Rational(3, 10)
+ Rational(25, 100).round(1, half: :up).should == Rational(3, 10)
+ Rational(25, 100).round(1, half: :down).should == Rational(1, 5)
+ Rational(25, 100).round(1, half: :even).should == Rational(1, 5)
+ Rational(35, 100).round(1, half: nil).should == Rational(2, 5)
+ Rational(35, 100).round(1, half: :up).should == Rational(2, 5)
+ Rational(35, 100).round(1, half: :down).should == Rational(3, 10)
+ Rational(35, 100).round(1, half: :even).should == Rational(2, 5)
+ Rational(-25, 100).round(1, half: nil).should == Rational(-3, 10)
+ Rational(-25, 100).round(1, half: :up).should == Rational(-3, 10)
+ Rational(-25, 100).round(1, half: :down).should == Rational(-1, 5)
+ Rational(-25, 100).round(1, half: :even).should == Rational(-1, 5)
+ end
+
+ it "raise for a non-existent round mode" do
+ -> { Rational(10, 4).round(half: :nonsense) }.should raise_error(ArgumentError, "invalid rounding mode: nonsense")
+ end
+ end
+end
diff --git a/spec/ruby/core/rational/shared/abs.rb b/spec/ruby/core/rational/shared/abs.rb
new file mode 100644
index 0000000000..3d64bcc1a0
--- /dev/null
+++ b/spec/ruby/core/rational/shared/abs.rb
@@ -0,0 +1,11 @@
+require_relative '../../../spec_helper'
+
+describe :rational_abs, shared: true do
+ it "returns self's absolute value" do
+ Rational(3, 4).send(@method).should == Rational(3, 4)
+ Rational(-3, 4).send(@method).should == Rational(3, 4)
+ Rational(3, -4).send(@method).should == Rational(3, 4)
+
+ Rational(bignum_value, -bignum_value).send(@method).should == Rational(bignum_value, bignum_value)
+ end
+end
diff --git a/spec/ruby/core/rational/shared/arithmetic_exception_in_coerce.rb b/spec/ruby/core/rational/shared/arithmetic_exception_in_coerce.rb
new file mode 100644
index 0000000000..f4cf70d147
--- /dev/null
+++ b/spec/ruby/core/rational/shared/arithmetic_exception_in_coerce.rb
@@ -0,0 +1,11 @@
+require_relative '../fixtures/rational'
+
+describe :rational_arithmetic_exception_in_coerce, shared: true do
+ it "does not rescue exception raised in other#coerce" do
+ b = mock("numeric with failed #coerce")
+ b.should_receive(:coerce).and_raise(RationalSpecs::CoerceError)
+
+ # e.g. Rational(3, 4) + b
+ -> { Rational(3, 4).send(@method, b) }.should raise_error(RationalSpecs::CoerceError)
+ end
+end
diff --git a/spec/ruby/core/rational/to_f_spec.rb b/spec/ruby/core/rational/to_f_spec.rb
new file mode 100644
index 0000000000..d0da49d377
--- /dev/null
+++ b/spec/ruby/core/rational/to_f_spec.rb
@@ -0,0 +1,16 @@
+require_relative "../../spec_helper"
+
+describe "Rational#to_f" do
+ it "returns self converted to a Float" do
+ Rational(3, 4).to_f.should eql(0.75)
+ Rational(3, -4).to_f.should eql(-0.75)
+ Rational(-1, 4).to_f.should eql(-0.25)
+ Rational(-1, -4).to_f.should eql(0.25)
+ end
+
+ it "converts to a Float for large numerator and denominator" do
+ num = 1000000000000000000000000000000000048148248609680896326399448564623182963452541226153892315137780403285956264146010000000000000000000000000000000000048148248609680896326399448564623182963452541226153892315137780403285956264146010000000000000000000000000000000000048148248609680896326399448564623182963452541226153892315137780403285956264146009
+ den = 2000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+ Rational(num, den).to_f.should == 500.0
+ end
+end
diff --git a/spec/ruby/core/rational/to_i_spec.rb b/spec/ruby/core/rational/to_i_spec.rb
new file mode 100644
index 0000000000..520a380b2a
--- /dev/null
+++ b/spec/ruby/core/rational/to_i_spec.rb
@@ -0,0 +1,12 @@
+require_relative "../../spec_helper"
+
+describe "Rational#to_i" do
+ it "converts self to an Integer by truncation" do
+ Rational(7, 4).to_i.should eql(1)
+ Rational(11, 4).to_i.should eql(2)
+ end
+
+ it "converts self to an Integer by truncation" do
+ Rational(-7, 4).to_i.should eql(-1)
+ end
+end
diff --git a/spec/ruby/core/rational/to_r_spec.rb b/spec/ruby/core/rational/to_r_spec.rb
new file mode 100644
index 0000000000..34f16d7890
--- /dev/null
+++ b/spec/ruby/core/rational/to_r_spec.rb
@@ -0,0 +1,26 @@
+require_relative "../../spec_helper"
+
+describe "Rational#to_r" do
+ it "returns self" do
+ a = Rational(3, 4)
+ a.to_r.should equal(a)
+
+ a = Rational(bignum_value, 4)
+ a.to_r.should equal(a)
+ end
+
+ it "raises TypeError trying to convert BasicObject" do
+ obj = BasicObject.new
+ -> { Rational(obj) }.should raise_error(TypeError)
+ end
+
+ it "works when a BasicObject has to_r" do
+ obj = BasicObject.new; def obj.to_r; 1 / 2.to_r end
+ Rational(obj).should == Rational('1/2')
+ end
+
+ it "fails when a BasicObject's to_r does not return a Rational" do
+ obj = BasicObject.new; def obj.to_r; 1 end
+ -> { Rational(obj) }.should raise_error(TypeError)
+ end
+end
diff --git a/spec/ruby/core/rational/to_s_spec.rb b/spec/ruby/core/rational/to_s_spec.rb
new file mode 100644
index 0000000000..24e30778e5
--- /dev/null
+++ b/spec/ruby/core/rational/to_s_spec.rb
@@ -0,0 +1,14 @@
+require_relative "../../spec_helper"
+
+describe "Rational#to_s" do
+ it "returns a string representation of self" do
+ # Guard against the Mathn library
+ guard -> { !defined?(Math.rsqrt) } do
+ Rational(1, 1).to_s.should == "1/1"
+ Rational(2, 1).to_s.should == "2/1"
+ end
+ Rational(1, 2).to_s.should == "1/2"
+ Rational(-1, 3).to_s.should == "-1/3"
+ Rational(1, -3).to_s.should == "-1/3"
+ end
+end
diff --git a/spec/ruby/core/rational/truncate_spec.rb b/spec/ruby/core/rational/truncate_spec.rb
new file mode 100644
index 0000000000..728fca34ea
--- /dev/null
+++ b/spec/ruby/core/rational/truncate_spec.rb
@@ -0,0 +1,71 @@
+require_relative "../../spec_helper"
+
+describe "Rational#truncate" do
+ before do
+ @rational = Rational(2200, 7)
+ end
+
+ describe "with no arguments (precision = 0)" do
+ it "returns an integer" do
+ @rational.truncate.should be_kind_of(Integer)
+ end
+
+ it "returns the truncated value toward 0" do
+ @rational.truncate.should == 314
+ Rational(1, 2).truncate.should == 0
+ Rational(-1, 2).truncate.should == 0
+ end
+ end
+
+ describe "with an explicit precision = 0" do
+ it "returns an integer" do
+ @rational.truncate(0).should be_kind_of(Integer)
+ end
+
+ it "returns the truncated value toward 0" do
+ @rational.truncate(0).should == 314
+ Rational(1, 2).truncate(0).should == 0
+ Rational(-1, 2).truncate(0).should == 0
+ end
+ end
+
+ describe "with a precision < 0" do
+ it "returns an integer" do
+ @rational.truncate(-2).should be_kind_of(Integer)
+ @rational.truncate(-1).should be_kind_of(Integer)
+ end
+
+ it "moves the truncation point n decimal places left" do
+ @rational.truncate(-3).should == 0
+ @rational.truncate(-2).should == 300
+ @rational.truncate(-1).should == 310
+ end
+ end
+
+ describe "with a precision > 0" do
+ it "returns a Rational" do
+ @rational.truncate(1).should be_kind_of(Rational)
+ @rational.truncate(2).should be_kind_of(Rational)
+ end
+
+ it "moves the truncation point n decimal places right" do
+ @rational.truncate(1).should == Rational(1571, 5)
+ @rational.truncate(2).should == Rational(7857, 25)
+ @rational.truncate(3).should == Rational(62857, 200)
+ end
+ end
+
+ describe "with an invalid value for precision" do
+ it "raises a TypeError" do
+ -> { @rational.truncate(nil) }.should raise_error(TypeError, "not an integer")
+ -> { @rational.truncate(1.0) }.should raise_error(TypeError, "not an integer")
+ -> { @rational.truncate('') }.should raise_error(TypeError, "not an integer")
+ end
+
+ it "does not call to_int on the argument" do
+ object = Object.new
+ object.should_not_receive(:to_int)
+ -> { @rational.truncate(object) }.should raise_error(TypeError, "not an integer")
+ end
+ end
+end
diff --git a/spec/ruby/core/rational/zero_spec.rb b/spec/ruby/core/rational/zero_spec.rb
new file mode 100644
index 0000000000..af7fb391ac
--- /dev/null
+++ b/spec/ruby/core/rational/zero_spec.rb
@@ -0,0 +1,14 @@
+require_relative "../../spec_helper"
+describe "Rational#zero?" do
+ it "returns true if the numerator is 0" do
+ Rational(0,26).zero?.should be_true
+ end
+
+ it "returns true if the numerator is 0.0" do
+ Rational(0.0,26).zero?.should be_true
+ end
+
+ it "returns false if the numerator isn't 0" do
+ Rational(26).zero?.should be_false
+ end
+end