LoginSignup
0
0

More than 3 years have passed since last update.

【Ruby】論理演算子のリファクタリングの難しさ(正確性と可読性)

Last updated at Posted at 2020-10-03

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?メソッドを使ってみる

case1 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?メソッドを使ってみる

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などは通らない。

in?メソッド
input_number = gets.chomp
if input_number.in?(["0", "1", "2"])
 puts "入力された文字列は、0,1,2のうちどれかです"
else
  puts "それ以外の文字が含まれています!"
end
0
0
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0