# different version of PosRational, more suitable for unit testing class PosRational # initialize is special; immediately called on result # of PosRational.new def initialize(num,den=1) # default arguments if num < 0 || den <= 0 raise "PosRational received an inappropriate argument" end @num = num # fields created when you assign to them @den = den reduce end def to_s # override the standard to_s (to_string) method ans = @num.to_s if @den != 1 # everything true except false _and_ nil objects ans = ans + "/" + @den.to_s end return ans end # the documentation claims that the default version of inspect # uses to_s, but it doesn't seem to work that way .... def inspect to_s end def add r a = r.num # only works b/c of protected methods below b = r.den # only works b/c of protected methods below c = @num d = @den @num = (a * d) + (b * c) @den = b * d reduce self # convenient for stringing calls end # a functional addition, dynamic typing means now + works on rationals def + r ans = PosRational.new(@num,@den) ans.add(r) ans end attr_reader :num, :den protected :num, :den private def gcd(x,y) if x == y x elsif x < y gcd(x,y-x) else gcd(y,x) end end def reduce d = gcd(@num,@den) @num = @num / d @den = @den / d end end