require 'test/minirunit' test_check "Test Number" test_ok(25.eql?(25)) test_ok(10000.eql?(10000)) test_ok(20.between?(15, 25)) test_ok(!(20.between?(10, 15))) test_ok(78.chr == 'N') n1 = 0b0101 n2 = 0b1100 test_equal(0, n1 & 0) test_equal(0b0100, n1 & n2) test_equal(n1, n1 & -1) test_equal(1, 3 & 10000000000000000000000000000000001) test_equal(1, 10000000000000000000000000000000001 & 3) test_equal(10000000000000000000000000000000001, 10000000000000000000000000000000001 & 10000000000000000000000000000000001) test_equal(-10000000000000000000000000000000002, ~10000000000000000000000000000000001) test_equal(0, 0[0]) test_equal([0,1,1], [3[2], 3[1], 3[0]]) test_equal([1,1,0], [-2[2], -2[1], -2[0]]) test_equal(1, -2[1000]) test_equal(1, (2 ** 100)[100]) test_equal(0, (2 ** 100)[101]) test_equal(0, (2 ** 100)[0]) test_equal(1, Integer.induced_from(1)) test_equal(1, Integer.induced_from(1.0)) test_exception(TypeError) { Integer.induced_from(:hello) } test_exception(TypeError) { Integer.induced_from("hello") } test_exception(TypeError) { Integer.induced_from(true) } test_equal(1, Fixnum.induced_from(1)) test_equal(1, Fixnum.induced_from(1.0)) test_equal(:hello.to_i, Fixnum.induced_from(:hello)) test_exception(TypeError) { Fixnum.induced_from("hello") } test_exception(TypeError) { Fixnum.induced_from(true) } test_exception(RangeError) { Fixnum.induced_from(1000000000000000000000000000000) } test_equal(1.0, Float.induced_from(1)) test_equal(1.0, Float.induced_from(1.0)) test_exception(TypeError) { Float.induced_from(:hello) } test_exception(TypeError) { Float.induced_from("hello") } test_exception(TypeError) { Float.induced_from(true) } # You can't freeze Fixnums... test_ok(! 303.freeze.frozen?) test_ok(! 303.taint.tainted?) # ... but you can apparently freeze Bignums and Floats. test_ok(1000000000000000000000000000000.freeze.frozen?) test_ok(1000000000000000000000000000000.taint.tainted?) test_ok(1.337.freeze.frozen?) test_ok(1.337.taint.tainted?) test_ok(! nil.taint.tainted?) test_ok(! nil.freeze.frozen?) test_equal(0, 1 ^ 1) test_equal(1005, 1000 ^ 5) test_equal(0, (10 ** 70) ^ (10 ** 70)) test_equal(1 + (10 ** 70), (10 ** 70) ^ 1) test_equal(10 ** 70, (10 ** 70) ^ 0) test_equal(-1, ~0) test_equal(-2, ~1) test_equal(1, 1 | 1) test_equal(1, 1 | 0) test_equal(10001, 10000 | 1) test_equal(1 + (10 ** 70), (10 ** 70) | 1) test_equal(1 + (10 ** 70), 1 | (10 ** 70)) test_equal(10 ** 70, (10 ** 70) | (10 ** 70)) test_equal(20, (256**20 - 1).size) test_equal(40, (256**40 - 1).size) test_exception(TypeError) { 20['x'] } test_equal(1, 0.object_id) test_equal(3, 1.object_id) test_equal(5, 2.object_id) test_equal(9, 4.object_id) test_equal(2, 5 / 2) test_equal(2, 5.div(2)) test_equal(1.object_id, 1.__id__) # Testing lexer's handling of numbers here test_exception(NameError) { Integer.new } test_exception(NameError) { Fixnum.new } test_exception(NameError) { Float.new } x = 1234 test_exception(TypeError) { def x.+(other) "fools" end } test_equal("8", 8.to_s) test_equal("10", 8.to_s(8)) class IntClass def to_int; 8; end end test_equal("10", 8.to_s(IntClass.new)) # Duck refers to duck typing. # If you include this module and override ==, implement it so that you FIRST check if # the other object is of the same class --> if so, compare equality as normal. If not, call # operands = self.coerce(other) and return operands[0] == operands[1] module DuckNumber include Comparable # the symbol representing the method which returns the number the object corresponds to NUMBER_METHOD = :score # override this if you want to use some other method to return the numeric presentation def get_number_method NUMBER_METHOD end private :get_number_method def coerce(other) case other when Integer [other, self.score] when Float [other, Float(self.score)] when DuckNumber [other.score, self.score] else raise "can not convert #{self.class.to_s} to #{other.class.to_s}" end end def to_int self.send(get_number_method) end def -@ -self.to_int end def +@ self.to_int end [:+, :-, :/, :%, :*, :<=>].each { |operator| module_eval <<-END_DUCK def #{operator.to_s}(other) operands = self.coerce(other) operands[1] #{operator.to_s} operands[0] end END_DUCK } end class DuckNumberImpl include DuckNumber attr_accessor :score, :foo end SCORE = 3 @duck = DuckNumberImpl.new @duck.score = SCORE @duck.foo = 12345 test_equal(SCORE, +@duck) test_equal(-SCORE, -@duck) test_equal(SCORE + 1, 1 + @duck) test_equal(SCORE + 1, @duck + 1) test_equal(SCORE - 1, @duck - 1) test_equal(1 - SCORE, -@duck + 1) test_equal(1 - SCORE, 1 - @duck) test_equal(SCORE + SCORE, @duck + @duck) test_ok(@duck > 1) test_ok(1 < @duck) test_ok(@duck >= 1) test_ok(1 <= @duck) # test Numeric#to_int test_equal(1234, 1234.to_int) # for Fixnum operations - fast version a = 0 10.times do |i| a+=i end test_equal(a,45) a = 0 10.upto(20) do |i| a+=i end test_equal(a,165) a = 0 20.downto(10) do |i| a+=i end test_equal(a,165) test_equal(0.next,1) # for Bignum operations - slow version big = 10000000000000000000 test_equal(big.class,Bignum) a = 0 big.times do |i| a+=i break if i > 10 end test_equal(a,66) a = 0 big.upto(big+10) do |i| a += i end test_equal(a,110000000000000000055) a = 0 big.downto(big-10) do |i| a += i end test_equal(a,109999999999999999945) test_equal(big.next,big + 1) # Fixnum a = 0 10.step(20) do |i| a+=i end test_equal(a,165) a = 0 10.step(20,3) do |i| a+=i end test_equal(a,58) a = 0 20.step(10,-3) do |i| a+=i end test_equal(a,62) # Float a = 0.0 10.0.step(12.0) do |i| a+=i end test_equal(a,33.0) a = 0.0 10.0.step(12.0,0.3) do |i| a+=i end test_equal(a,76.3) a = 0.0 12.0.step(10.0,-0.3) do |i| a+=i end test_equal(a,77.7) # no singleton methods on numerics [10.0, 10, 1000000000000000000000000000].each do |num| test_exception(TypeError) { class << num ; def amethod ; end ; end } test_exception(TypeError) { def num.amethod ; end } end#Creating a singleton from Fixnum should yield: "TypeError: no virtual class for Fixnum" test_exception(TypeError) { class << 10 ; end }