I'm writing a multiple choice quiz where the user has to choose an answer by entering a letter from a to d. Each question prompt looks like this:
What is the last letter in alphabet?
(a) Y
(b) R
(c) Z
(d) Q
If the user enters anything else, I want to show a message and print the whole question again until the input is a, b, c or d.
Here's what I've tried: (simplified)
question = "What is the last letter in alphabet?\n(a) Y\n(b) R\n(c) Z\n(d) Q"
puts question
answer = gets.chomp.to_s
while answer > "d"
puts "Please enter a, b, c, or d"
puts
puts question
answer = gets.chomp.to_s
end
It works fine when entering e, f, g etc. but it doesn't catch input like ab, 1, Z, or when the user just presses enter.
Your approach doesn't work because answer > "d" compares both strings character-wise using their (Unicode) code points. To understand what this means, take a look at the Basic Latin chart: (it's equivalent to an ASCII table)

"d" has a codepoint of U+0064. Any smaller codepoint – i.e every character in the chart before "d" – is regarded smaller. This includes all (regular) digits, all (basic latin) uppercase letters and several symbols:
"0" > "d" #=> false
"Z" > "d" #=> false
You could add a lower bound like answer < "a" || answer > "d" but this would still allow all strings starting with one of the allowed characters, e.g.:
"apple" < "a" || "apple" > "d" #=> false
To actually limit the answer to the four allowed values, you have to compare the string to each of them. You could combine these comparisons:
answer == 'a' || answer == 'b' || answer == 'c' || answer == 'd'
use a loop over an array of allowed values:
['a', 'b', 'c', 'd'].any? { |letter| answer == letter }
check whether the array includes the answer:
['a', 'b', 'c', 'd'].include?(answer)
# or
%w[a b c d].include?(answer)
or use a regular expression to match a to d:
answer.match?(/\A[a-d]\z/)
Note that the examples above become true if answer is between a and d. You could either negate the condition via !(...):
while !(%w[a b c d].include?(answer))
# ...
end
or use until instead of while:
until %w[a b c d].include?(answer)
# ...
end