Menu
Coddy logo textTech

case and Classes

Part of the Object Oriented Programming section of Coddy's Ruby journey. Lesson 35 of 57.

case can branch on the class of a value. when Integer matches every integer, because case compares with ===, and Integer === 5 asks whether 5 is an Integer (is_a?):

def describe(value)
  case value
  when Integer then "integer #{value}"
  when Float then format("float %.2f", value)
  when String then "text of #{value.size} chars"
  when nil then "nothing"
  else "other: #{value.class}"
  end
end

[5, 2.5, "hi", nil, [1, 2]].each { |v| puts describe(v) }

Output:

integer 5
float 2.50
text of 2 chars
nothing
other: Array

Because === on a class follows is_a?, a when with a superclass matches its subclasses too. Order the branches from the most specific class to the most general one:

class Animal
end

class Dog < Animal
end

def kind(x)
  case x
  when Dog then "a dog"
  when Animal then "some animal"
  else "not an animal"
  end
end

puts kind(Dog.new)
puts kind(Animal.new)
puts kind("Rex")
puts Animal === Dog.new

Output:

a dog
some animal
not an animal
true

One when can list several classes, and the branches can do real work with the value, such as totalling a nested structure of mixed types:

def total(value)
  case value
  when Integer, Float then value
  when String then value.to_f
  when Array then value.sum { |v| total(v) }
  when Hash then total(value.values)
  else 0
  end
end

puts total([1, "2.5", { a: 3, b: [4, nil] }])

Output:

10.5

Branching on classes suits values whose classes you cannot give new methods, such as numbers, strings and arrays, or data from outside. For your own classes, prefer polymorphism: a new class then needs a new method, not a new branch in every case:

# your own classes: let each one answer
shape.area

# built-in values from outside: branch on the class
case value
when Integer then ...
when String then ...
end
challenge icon

Challenge

Easy

Complete the helper describe(value) in functions.rb with a case on the class of the value. It returns integer 5 (odd) or integer 4 (even), float 2.50 with two decimals, text "hi" (2 chars), list of 3: 1, a, 2.5 (the elements' to_s joined), nothing for nil and other Symbol for anything else. Symbols are the only other kind in the tests.

The supplied code turns each input line into a value (whole numbers, decimals, [a,b] lists, nil, :name symbols, or text) and prints describe for each.

Your code goes in functions.rb. main.rb holds the supplied input/output code and cannot be edited.

Try it yourself

require_relative 'functions'

# Supplied input/output code: keep it as it is
input = []
while (line = gets)
  input << line.chomp
end
def parse(text)
  return Integer(text) if text.match?(/\A-?\d+\z/)
  return Float(text) if text.match?(/\A-?\d+\.\d+\z/)
  return nil if text == "nil"
  return text[1..].to_sym if text.start_with?(":")
  return text[1...-1].split(",").map { |t| parse(t) } if text.start_with?("[")

  text
end

input.each { |line| puts describe(parse(line)) }
quiz iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

All lessons in Object Oriented Programming

Practice on your own: Online Ruby compiler