true/falseとnilの違いの有用なケース

 最近久しぶりにrubyをよく書いている。
で、ちょっと特殊だけどnilとfalseの組み合わせで有用なケースがあったので記載しておく^^


で、先に書いておくと
if/unless等では、falseとnilは等価であるが、他の方法(case whenやnil?等)ではfalseとnilは区別できることです


想定:ログ解析スクリプト


 で有用なケースというのは、ログ解析にrubyで簡単なフィルタを作成したのですが
最初は入力値のパターンが「2パターン(なのでtrue/falseを使用)」のみで十分と判断してたのですが、
なんやかんやで「3パターン」必要じゃない?ってなりました。


で、仕方ないので結構書きなおすかと思ったのですが、nilを追加することで入力「3パターン」を最小の変更で対応できました

[入力 true/false] -> [出力 "pass"/"fail"]

 で、簡単に書くと最初は以下みたいなコード書いてました。
最初入力パラメータを、true/falseを想定してたので、途中でif/unlessの条件分岐がいくつか入れてしましました><

flags = [false, true] #入力
result = []           #出力

flags.each{|flg|

  # if/unlessで条件チェックした処理があり
  puts 17 unless flg
  puts 42 if flg


  # で結果を出力
  if flg
    result << "pass"
  else
    result << "fail"
  end
}

                     #=> 17 42
p result             #=> ["fail", "pass"]
[入力 true/false/nil] -> [出力 "pass"/"fail"/"todo"]


 で、入力「3パターン」にnilを追加して、以下のような対応しました。
で新しく増えたパターンは意味的にfalseに近いのでnilを使用*1、途中のif/unlessをそのまま流用。


で途中はfalse/nilは一緒の意味で使いたいけど、出力は分別したいので、caseで分岐。
ってか、caseで分岐できることを確認できたので、nilを入力パターンの追加ケースの値に選びましたとさ><

flags = [false, true, nil] #入力
result = []                #出力

flags.each{|flg|

  # if/unlessで条件チェックした処理があり
  puts 17 unless flg
  puts 42 if flg


  # で結果を出力
  case flg
  when true
    result << "pass"
  when false
    result << "fail"
  when nil
    result << "todo"
  end
}

                     #=> 17 42 17
p result             #=> ["fail", "pass", "todo"]


と、途中のif/unlessの条件チェック部分を書き換えることなく入力/出力2パターンから、3パターンに修正が出来ましたとさ^^

結論

設計は確りと><、*2

P.S. 23:15


今回if/unlessにおいてfalseと等価なものが必要であり、nilがそうであったので使用しました。
が、trueと等価なものが必要であったケースを想定して、よく考えると、一杯あります。ってかfalseとnil以外ですね><

  • if/unlessにおいて
    • falseと等価
    • trueと等価
      • falseとnil以外( 42, [ ], "ruby", { }, などなど


なのでtrueとif/unlessにおいて等価なパターンはいくらでも増やせますね


(はいそんなケースは最初の設計が狂っていたということです><


[入力 true/false/nil/42/"ruby"] -> [出力 "pass"/"fail"/"todo"/"num"/"pyhton"]
flags = [false, true, nil, 42, "ruby"] #入力
result = []                #出力

flags.each{|flg|

  # if/unlessで条件チェックした処理があり
  puts 17 unless flg
  puts 42 if flg


  # で結果を出力
  case flg
  when true
    result << "pass"
  when false
    result << "fail"
  when nil
    result << "todo"
  when 42
    result << "num"
  when "ruby"
    result << "python"
  end
}

                     #=> 17 42 17 42 42
p result             #=> ["fail", "pass", "todo", "num", "python"]

*1:もしtrue側のパターン増やさないと行けない場合は、true/falseを入れ替えて対応しなくてはいけなかったでしょう

*2:下手にboolなんて使うものでもないですね