Don't Repeat Yourself(同じ記述を繰り返さない)ことを突き詰めようとした結果、本来の目的が達成できないケースがあったため、記事として残しておきます。
要件定義
例えば、ある特定の文字列のみの入力を求めるとする。(下記の場合は、"0","1","2"のどれか1つの入力を、if文でjudgeしている。)
論理演算子を用いた記述
input_number = gets.chomp
sample_number = ["0","1","2"]
if input_number == "0" || input_number == "1" || input_number == "2"
puts "入力は、0,1,2のうちどれかです。"
else
puts "0,1,2以外の文字が入力されましています!"
end
論理演算子||(または)の箇所が長ったらしい…。なんとか簡潔にできないかと試行錯誤してみる。
between?メソッドを使ってみる
input_number = gets.chomp
sample_number = ["0","1","2"]
# 入力された文字列が"0"から"2"までの間かどうかを、真偽で返す。
t_or_f = input_number.between?("0", "2")
if t_or_f == true
puts "入力された文字列は、0,1,2のうちどれかです"
else
puts "それ以外の文字が含まれています!"
end
変数定義が1つ増えたが、仮に受け入れる文字列をもっと増やしたい場合には、論理演算子よりも追記・修正が少なくて済む。
リファクタリングはおしまい、と思いきや別の問題が発生することが分かった。
アルファベット等の関係ない文字列を含む場合はfalseとなるが、"0120"や"1.9"といった入力をtrueと返してしまうのだ。
次はどうだろうか。
any?メソッドとinclude?メソッドを使ってみる
input_number = gets.chomp
sample_number = ["0","1","2"]
# any?メソッド・・・どれか1つでも条件を満たすのであればtrue、すべて条件を満たさないのであればfalseを返す
# ブロック{}内の処理・・・sample_numberの配列内の要素をブロック引数nに代入。
# input_numberにブロック引数nが含まれて(includeされて)いるかを判断し、trueかfalseを繰り返し(この場合は3回)返している。
t_or_f = sample_number.any? {|n| input_number.include?(n)}
if t_or_f == true
puts "入力された文字列は、0,1,2のうちどれかです"
else
puts "それ以外の文字が含まれています!"
end
この場合は、入力された文字列が0,1,2いずれかを含んでいれば、必ずtrueを返してしまう。
(例:1234 => true, abc0120 => true)
結論
結局は、論理演算子||で入力を厳格に求めることが、一番確度が高い。
in?メソッド(※Rails限定)
Rubyオリジナルではなく、Rails内の拡張されたRubyには__in?メソッド__というものがある。
この場合、0,1,2のみ受け入れ、01などは通らない。
input_number = gets.chomp
if input_number.in?(["0", "1", "2"])
puts "入力された文字列は、0,1,2のうちどれかです"
else
puts "それ以外の文字が含まれています!"
end