Chapter 10 - Comparable and Enumerable

Exercise 1: Comparing grades

We need a Ruby class to represent student letter grades from “A” through “F”. If you’re not familiar with the system, grades consist of the letters “A”, “B”, “C”, “D”, and “F”, with “A” being the best, and “F” being the worst.

The class will need letter and letter= accessor methods for the letter grade. The letter= method should validate the letter being assigned, and raise an exception if it’s not “A”, “B”, “C”, “D”, or “F”. It should also include an initialize method, so that we can pass a letter to Grade.new and have it assigned to the letter attribute.

We also need to be able to compare grades with the <, >, and == operators. An “A” grade should be considered “greater than” a “C” grade, an “F” grade should be “less than” a “D” grade, etc.

class Grade

  include Comparable

  VALID_LETTERS =  ["A", "B", "C", "D", "F"]

  attr_reader :letter

  def initialize(letter)
    self.letter = letter
  end

  def letter=(value)
    unless VALID_LETTERS.include?(value)
      raise "#{value} is not a valid grade letter"
    end

    @letter = value
  end

  def <=>(other)
    if other.letter < letter
      return -1
    elsif other.letter > letter
      return 1
    else
      return 0
    end
  end

end

a_grade = Grade.new("A")
b_grade = Grade.new("B")
c_grade = Grade.new("C")
d_grade = Grade.new("D")
f_grade = Grade.new("F")

puts "a_grade > c_grade: #{a_grade > c_grade}"
puts "f_grade < d_grade: #{f_grade < d_grade}"
puts "b_grade > a_grade: #{b_grade > a_grade}"
puts "a_grade == a_grade: #{a_grade == a_grade}"

The above code outputs:

a_grade > c_grade: true
f_grade < d_grade: true
b_grade > a_grade: false
a_grade == a_grade: true