# ## 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:

```# 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
# and
#
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 😉

```# 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
# and
#
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 + sides <= sides)
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 Kelley  on August 16th, 2009

I 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. #### Pete  on August 16th, 2009

Nathan,

That’s really awesome. You are definitely right, your code is much more the “Ruby way” than mine. I don’t think that uniq is cheating, that is a very clever solution to the problem in my opinion.

Thanks for dropping by and moreso for sharing that code with me! #### Greg Malcolm  on August 17th, 2009

For a moment there I thought I was looking at my code as the downloaded example, but then I remembered that I didn’t check any answers into github.

I saw Nathan’s solution while at Devlink. I highly approve of its brevity 😀 #### Pete  on August 17th, 2009

Greg,

Thanks for commenting. I wish I could have been at Devlink, but I didn’t waste the entire weekend, anyway! Happy belated congratulations on becoming an American citizen, btw. #### Pete on Software  on August 17th, 2009

[…] post is an extension of my last post on the Ruby Koans. Today, I tackled the next Ruby Koan on the block, which was to score dice throws […] #### Brian Genisio  on September 22nd, 2009

I am also doing the ruby koans. I was so proud of my solution, that I needed to share… sorry if I am gloating. Here is what I came up with:

def triangle(a, b, c)
sides = [a,b,c].sort
raise TriangleError if sides.select{|x| x 0
raise TriangleError if sides + sides <= sides
[:equilateral, :isosceles, :scalene][sides.uniq.size – 1]
end #### Kay  on July 26th, 2010

I just did the triangle scenario and my code is as follows:

def triangle(a,b,c)
if (a<=0 or b<=0 or c<=0)
begin
raise TriangleError
end
elsif (a==b and a==c)
return :equilateral
elsif
(a==b or a==c or b==c)
return :isosceles
else
:scalene
end
end #### Alexxey  on August 26th, 2010

def triangle(a, b, c)
a,b,c=[a, b, c].sort
raise TriangleError if a=a+b

case [a, b, c].uniq.length
when 1
:equilateral
when 2
:isosceles
else
:scalene
end
end #### Pascal Van Hecke  on September 3rd, 2010

Shorter code is definitely not better, but combining my own TriangleError and Brian Genisio’s Array you can write it in 2 lines:

def triangle(a, b, c)
raise TriangleError, “Triangle error” if (a <= 0 || b <= 0 || c = (a+b+c))
[:equilateral, :isosceles, :scalene][[a,b,c].uniq.size – 1]
end

Who performs better 😉 #### Jared Hodgkins  on November 7th, 2010

This is my modifications to Brian’s post since I was having issues with his TriangleError

def triangle(a, b, c)
sides = [a,b,c].sort
raise TriangleError unless sides.each{|x| x > 0}
raise TriangleError if sides + sides <= sides
[:equilateral, :isosceles, :scalene][sides.uniq.size – 1]
end #### Chad  on December 22nd, 2010

Here was my solution to part 1 & 2 of the Triangle Koan, triangle.rb:

def triangle(a, b, c)
abc = [a, b, c]
side1, side2, side3 = abc.sort #sorts them from smallest to biggest side
raise TriangleError if side1 + side2 <= side3 # checks for triangle inequality (take the two smallest sides and add them, combined they need to be larger than the biggest side)
abc.each {|x| raise TriangleError if x <= 0 } #checks to see if any sides are smaller or equal to zero

if (a == b && a ==c)
:equilateral
elsif (a == b || b == c || a == c)
:isosceles
else
:scalene
end
end #### Shannon  on February 6th, 2011

a, b, c = [a, b, c].sort
raise TriangleError unless a > 0 && a + b > c

if a != b && b != c && c != a then
:scalene
elsif a == b && b == c then
:equilateral
else
:isosceles
end #### Chris Pelatari  on February 20th, 2011

``` def triangle(a, b, c) raise TriangleError unless valid_triangle?(a,b,c) [:equilateral, :isosceles, :scalene][[a,b,c].uniq.size - 1] end```

``` ```

```def valid_triangle?(a,b,c) ax,bx,cx = [a,b,c].sort ax + bx > cx end ```