# CSE413 Autumn 2012 # Introduction to Ruby # (Credits: Dan Grossman, CSE 413, Au11) # This file defines a basic class. # We will also show various Ruby-isms directly in the irb REPL class Rat # initialize is special: immediately called on result of Rat.new def initialize(num,den=1) # default arguments if den == 0 raise "Rat received an inappropriate argument" elsif den < 0 @num = - num # fields created when you assign to them @den = - den else @num = num @den = den end reduce # implicit self and implicit zero arguments end def print STDOUT.print @num if @den != 1 # everything true except false _and_ nil objects STDOUT.print "/" puts @den # a method inherited from Kernel, adds a newline end end def print2 # using some unimportant syntax and a slightly different algorithm d = "" d = "/" + @den.to_s if den != 1 puts(@num.to_s + d) end def print3 # using things like Racket's quasiquote and unquote puts("#{@num}#{if @den==1 : "" else "/" + @den.to_s end}") end def add r # mutate self in-place 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 = Rat.new(@num,@den) ans.add r ans end protected # there is very common sugar for this (attr_reader) # the better way: # attr_reader :num, :den # protected :num, :den def num @num end def den @den end private def gcd(x,y) if x == y x elsif x < y gcd(x,y-x) else gcd(y,x) end end def reduce if @num == 0 @den = 1 else d = gcd(@num.abs, @den) # notice method call on number @num = @num / d @den = @den / d end end end # you can define methods outside a class; they are just part of the main # class (which is available in the REPL) def double1 x x + x # sugar for x.+(x) end def double2 x x * 2 # sugar for x.*(2) end # What type of things do our double methods take? # Duck typing: anything that can respond to + or multiply by 2 # ok = double1(Rat.new(1,2)) # not_ok = double2 (Rat.new(1,2)) # we could make this work # add more methods to Rat (anywhere by anyone) # class Rat # def * i # if i != 2 # raise "Rat only knows how to double" # end # self.+(self) # self method call (first self necessary for syntax) # end # end #now_ok = double2(Rat.new(1,2)) # but this still does not work (would need to replace Fixnum's *) def double3 x 2 * x # sugar for 2.*(x) end # double3(Rat.new(1,2)) # another useful (?) example: + and * and - on arrays # arrays are very common and have _lots_ of methods