概要
Receive policies instead of data
前提
Confident Rubyではメソッド内の処理を次のように分類しています。
・Collecting Inputs(引数チェック、変換など)
・Performing Work(主処理)
・Delivering Output(戻り値に関わる処理)
・Handling Failure(例外処理)
当記事は上記のうち、Collecting Inputsに関する話です。
詳細
状況
異なるクライアントのメソッドが異なる方法で潜在的なエッジケースを取り扱う場合。
例えば、ある呼び出し元のファイルを削除するメソッドは、存在しないファイルを削除しようとして
警告を欲するかもしれない。
他のメソッドはファイルがなくても無視したいかもしれない。
概要
エッジケースの方針を決定できるブロックやProcを受け取る
理由
特定の呼び元がエッジケースをどのように扱うか、最適な決定できる。
エッジケースに対して引数を追加することもできるが、インターフェースの動作を知るには
メソッド定義を参照する必要がある。
サンプルコード仕様
文字列を大文字小文字交互に変換するstripeメソッドを作成します。
サンプルコード1では空文字の場合に任意の処理を実行できるように、yieldでブロックを受け取るようにします。
サンプルコード2では複数のエッジケースを扱えるようにオプションでProcを渡します。
サンプルコード1
yieldを活用して、空文字に対して処理無し・例外の発生を自由に選択できるようになっています。
class String def stripe if empty? if block_given? yield end end updowns = %w(upcase downcase) index = 1 chars.reduce([]) do |ret, char| ret << char.send(updowns[index % 2]) index += 1 ret end.join end end ret = "hogehoge".stripe puts ret ret = "".stripe puts ret.empty? begin ret = "".stripe { fail "String is empty" } rescue => e puts e end
出力
hOgEhOgE true String is empty
サンプルコード1
オプションでProc(lambda)を複数渡すことができるようにします。
class String def stripe(options = {}) empty_policy = options.fetch(:on_empty) { -> { }} # nothing single_char_policy = options.fetch(:on_single) { -> (x) {}} # nothing empty_policy.call if empty? single_char_policy.call(self) if size == 1 updowns = %w(upcase downcase) index = 1 chars.reduce([]) do |ret, char| ret << char.send(updowns[index % 2]) index += 1 ret end.join end end ret = "hogehoge".stripe puts ret ret = "".stripe puts ret.empty? begin ret = "".stripe({on_empty: -> { fail 'String is Empty' }}) rescue => e puts e end begin ret = "a".stripe({on_single: -> (x) { fail "String(#{x}) is Single" }}) rescue => e puts e end
hOgEhOgE true String is Empty String(a) is Single