## Ruby Koans

I decided to tackle a little Ruby language learning this weekend. So yesterday, I downloaded the Ruby Koans and went to work. The Koans were created by EdgeCase to help people learn Ruby. Basically, they are a set of unit tests that exercise aspects of Ruby. To begin, all of the tests fail. You have to write code or jump back and forth to the Interactive Ruby Shell (IRB) and get the results of the statements to make the asserts pass.

I went through and did 105 unit tests yesterday, each of them having several parts to them. Having messed around a little with Rails, I was familiar with using IRB and Rake and a little of the syntax. In my opinion, the way this is set up and builds upon itself is really helpful and is a great way to teach Ruby to n00bs. I really salute Jim Weirich and Joe O’Brien for their work in getting these together.

One of the exercises is to create a triangle method that takes three parameters (the sizes of the sides). You then have to decide what kind of triangle it is. After those tests pass, your next assignment is to prevent 0 length or negative sides as well as making sure your triangle validates.

I wrote all the code and passed all the tests except for the triangle validation test. I was having a serious brain cramp and could not remember how you ensured that you’ve gotten the correct sides for any triangle (and not just a right triangle), so I looked for someone else’s example of this code. I found this code:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
# Triangle Project Code. # Triangle analyzes the lengths of the sides of a triangle # (represented by a, b and c) and returns the type of triangle. # # It returns: # :equilateral if all sides are equal # :isosceles if exactly 2 sides are equal # :scalene if no sides are equal # # The tests for this method can be found in # about_triangle_project.rb # and # about_triangle_project_2.rb # def triangle(a, b, c) if a<=0 or b<=0 or c<=0 fail TriangleError, "Sides must all have length greater than 0." end myArray = [a,b,c] maxSide = myArray.max total = 0 myArray.each { |myEle| total += myEle } if total - maxSide <= maxSide fail TriangleError, "Sum of shortest two sides must be greater than length of longest side." end if a==b and a==c :equilateral elsif a!=b and b!=c and a!=c :scalene else :isosceles end end # Error class used in part 2. No need to change this code. class TriangleError < StandardError end |

Okay, I see. The smallest two sides added together need to be greater than the third side. However, I thought that the author of this code greatly over-complicated this process. We are always dealing with a fixed number of sides and the trick is to put them in order and then add away. I figured Ruby had a simple array sort (and they do), so I would place the sides into an array, sort it, and then add the 0 index and 1 index spot and make sure that it was greater than the 2 index spot. Case Closed and (in my opinion) a bit easier to read. Forgiving of course, that I didn’t pass messages in my exceptions, I personally like my code better (of course ðŸ˜‰ ). I also appreciate that Ruby doesn’t mind me putting ( and ) around my if conditions. I just feel safer for them to be contained ðŸ˜‰

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
# Triangle Project Code. # Triangle analyzes the lengths of the sides of a triangle # (represented by a, b and c) and returns the type of triangle. # # It returns: # :equilateral if all sides are equal # :isosceles if exactly 2 sides are equal # :scalene if no sides are equal # # The tests for this method can be found in # about_triangle_project.rb # and # about_triangle_project_2.rb # def triangle(a, b, c) # WRITE THIS CODE if (a <= 0 or b <= 0 or c<=0) raise TriangleError end sides = [a, b, c].sort if (sides[0] + sides[1] <= sides[2]) raise TriangleError end if (a==b and a==c) value = :equilateral else if (a==b or a==c or b==c) value = :isosceles else value = :scalene end end end # Error class used in part 2. No need to change this code. class TriangleError < StandardError end |

As I do these Koans, I’ve been making note of things I’d like to include in future blog entries about things I’ve enjoyed about the language and will be posting them in the near term.

Nathan Kelleyon August 16th, 2009I took Leon Gersing’s Koans talk at #devLink and worked on the all weekend. I especially enjoyed the Triangle koan. Here is how i did it. I intentionally refactored my if blocks into more “english style” statements. (Trying to not write C# in ruby)

def triangle(a, b, c)

raise TriangleError unless TriangleSideLengthsAreValid?(a,b,c)

return :equilateral if [a,b,c].uniq.length==1

return :isosceles if [a,b,c].uniq.length==2

return :scalene if [a,b,c].uniq.length==3

end

def TriangleSideLengthsAreValid?(a,b,c)

ax,bx,cx=[a,b,c].sort

return (ax+bx)>cx

end

I don’t think using .uniq on the array was cheating.