As is my custom when learning a new language, I implement a basic custom Rational class in Ruby:

# implementation of a Rational number class in Ruby module MyRational class Rational attr_reader :numerator, :denominator def initialize(num, denom = 1) if denom == 0 raise "Denominator cannot be 0 for a rational number" end @numerator = num @denominator = denom normalize end # += etc all come for free when the basic operator is overloaded! def +(other) @numerator = @numerator * other.denominator + @denominator * other.numerator @denominator = @denominator * other.denominator normalize self end def -(other) @numerator = @numerator * other.denominator - @denominator * other.numerator @denominator = @denominator * other.denominator normalize self end def *(other) @numerator = @numerator * other.numerator @denominator = @denominator * other.denominator normalize self end def /(other) @numerator = @numerator * other.denominator @denominator = @denominator * other.numerator normalize self end def to_s if @denominator == 1 @numerator.to_s else @numerator.to_s + "/" + @denominator.to_s end end # generics class methods def self.+(f, s) n = f.numerator * s.denominator + f.denominator * s.numerator d = f.denominator * s.denominator Rational.new(n, d) end def self.-(f, s) n = f.numerator * s.denominator - f.denominator * s.numerator d = f.denominator * s.denominator Rational.new(n, d) end def self.*(f, s) n = f.numerator * s.numerator d = f.denominator * s.denominator Rational.new(n, d) end def self./(f, s) n = f.numerator * s.denominator d = f.denominator * s.numerator Rational.new(n, d) end private def gcd(x, y) if y == 0 x else gcd(y, x%y) end end def normalize() g = gcd(@numerator, @denominator) @numerator /= g @denominator /= g end end end

Taking it for a test spin:

irb(main):003:0> load "my_rational.rb" load "my_rational.rb" => true irb(main):004:0> x = MyRational::Rational.new(1,2) x = MyRational::Rational.new(1,2) => #<MyRational::Rational:0x007fd02a09bc88 @numerator=1, @denominator=2> irb(main):005:0> y = MyRational::Rational.new(3,4) y = MyRational::Rational.new(3,4) => #<MyRational::Rational:0x007fd02a0a21a0 @numerator=3, @denominator=4> irb(main):006:0> x += y x += y => #<MyRational::Rational:0x007fd02a09bc88 @numerator=5, @denominator=4> irb(main):007:0> puts x puts x 5/4 => nil irb(main):008:0> x -= y x -= y => #<MyRational::Rational:0x007fd02a09bc88 @numerator=1, @denominator=2> irb(main):009:0> puts x puts x 1/2 => nil irb(main):010:0> x *= y x *= y => #<MyRational::Rational:0x007fd02a09bc88 @numerator=3, @denominator=8> irb(main):011:0> puts x puts x 3/8 => nil irb(main):012:0> x /= y x /= y => #<MyRational::Rational:0x007fd02a09bc88 @numerator=1, @denominator=2> irb(main):013:0> puts x puts x 1/2 => nil irb(main):014:0> MyRational::Rational.+(x, y) MyRational::Rational.+(x, y) => #<MyRational::Rational:0x007fd02a0bad90 @numerator=5, @denominator=4> irb(main):015:0> puts MyRational::Rational.+(x, y) puts MyRational::Rational.+(x, y) 5/4 => nil irb(main):016:0> puts MyRational::Rational.-(x, y) puts MyRational::Rational.-(x, y) -1/4 => nil irb(main):017:0> puts MyRational::Rational.*(x, y) puts MyRational::Rational.*(x, y) 3/8 => nil irb(main):018:0> puts MyRational::Rational./(x, y) puts MyRational::Rational./(x, y) 2/3 => nil

Of course, operations like number op rational, rational op number, where “op” is an operation will not work. These could be added by extending the number classes, etc, and also adding support in the class methods, but perhaps there is a better way that I will learn when I improve my Ruby knowledge! For now, the more I use Ruby, the more I like it!