c_extensions/c_coercion.rb
tests/_examples/c_extensions/c_coercion.rb in the metorex repository.
# A C extension comparing and coercing numbers the way MRI's numeric
# functions do, and reading C shorts and chars out of Ruby values.
require "tmpdir"
require_relative "build_helper"
class Pairing
def initialize(answer)
@answer = answer
end
def coerce(other)
@answer.respond_to?(:call) ? @answer.call(other) : @answer
end
end
class Signed
def initialize(sign)
@sign = sign
end
def >(other)
@sign > other
end
def <(other)
@sign < other
end
end
directory = Dir.mktmpdir
require(build_extension("c_coercion.c", "c_coercion", directory))
coercion = CCoercion.new
report { coercion.compare_error(1, nil) }
report { coercion.compare_error("a", 2.5) }
report { coercion.compare_error(:a, :b) }
report { coercion.compare_error([], Object.new) }
report { coercion.divide_error }
p([coercion.sign(5), coercion.sign(-5), coercion.sign(0), coercion.sign(2**70), coercion.sign(-(2**70)), coercion.sign(2**70 - 2**70)])
p([coercion.sign(Signed.new(1)), coercion.sign(Signed.new(-1)), coercion.sign(Signed.new(0)), coercion.sign(1.5)])
report { coercion.sign(nil) }
p(coercion.binary(2, Pairing.new([10, 5])))
report { coercion.binary(2, Object.new) }
report { coercion.binary(2, nil) }
report { coercion.binary(2, Pairing.new([1])) }
report { coercion.binary(2, Pairing.new(nil)) }
p(coercion.compared(2, Pairing.new([1, 3])))
p(coercion.compared(2, Pairing.new(nil)))
p(coercion.compared(2, Object.new))
p(coercion.related(2, Pairing.new([1, 3])))
report { coercion.related(2, Pairing.new(nil)) }
report { coercion.related(2, Pairing.new(->(_) { [Object.new, 1] })) }
p([coercion.integer("42"), coercion.integer(3.9)])
report { coercion.integer("forty") }
p([coercion.short_of(32767), coercion.short_of(-32768), coercion.short_of(4.9)])
report { coercion.short_of(32768) }
report { coercion.short_of(-32769) }
p([coercion.character("Abc"), coercion.character(0xa7c), coercion.character(-1)])
report { coercion.character("") }
p([coercion.single_bit(0), coercion.single_bit(8), coercion.single_bit(-8), coercion.single_bit(6), coercion.single_bit(2**70), coercion.single_bit(2**70 + 1)])
p(coercion.long_long_size)
FileUtils.rm_rf(directory)
Output:
ArgumentError: comparison of Integer with nil failed
ArgumentError: comparison of String with 2.5 failed
ArgumentError: comparison of Symbol with :b failed
ArgumentError: comparison of Array with Object failed
ZeroDivisionError: divided by 0
[1, -1, 0, 1, -1, 0]
[1, -1, 0, 1]
ArgumentError: comparison of Integer with 2 failed: comparator returned nil
15
TypeError: Object can't be coerced into Integer
TypeError: nil can't be coerced into Integer
TypeError: coerce must return [x, y]
TypeError: coerce must return [x, y]
-1
nil
nil
true
ArgumentError: comparison of Integer with Pairing failed: coercion was not possible
NoMethodError: undefined method '<' for an instance of Object
[42, 3]
ArgumentError: invalid value for Integer(): "forty"
[32767, -32768, 4]
RangeError: integer 32768 too big to convert to 'short'
RangeError: integer -32769 too small to convert to 'short'
[65, 124, 255]
TypeError: no implicit conversion of String into Integer
[0, 1, 1, 0, 1, 0]
8