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: ArrayBecause === 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.newOutput:
a dog
some animal
not an animal
trueOne 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.5Branching 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 ...
endChallenge
EasyComplete 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)) }
This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Object Oriented Programming
1Classes and Objects
Working With FilesDefining ClassesInstance VariablesMethods and selfto_s and inspectRecap - Library Card7Polymorphism and Duck Typing
PolymorphismDuck TypingAbstract Methodscase and ClassesRecap - Payment Methods2Accessors and Self
Readers and WritersCustom Settersself in MethodsIdentity and EqualityRecap - Contact List8Special Methods
Equality and hashOperator MethodsIndexing and AppendingCustom CollectionsRecap - Fractions11Project: Library Management
Books and MembersBorrowing Books3Class Methods and Variables
Class MethodsClass Instance VariablesConstantsFactory MethodsRecap - Coupon CodesPractice on your own: Online Ruby compiler