Proc.newで冗長なコードを取りまとめ

「cp」と「mv」とメソッド名が2文字しか違わない以下の冗長なコードをまとめる方法として、Procオブジェクトを使ってみることにした。

if Options[:copy]
  Options[:events].each {|n|
    nikon.event(n).each {|photo|
      FileUtils.cp(photo[0],".",
                   {:verbose => Options[:verbose]})
    }
  }
elsif Options[:move]
  Options[:events].each {|n|
    nikon.event(n).each {|photo|
      FileUtils.mv(photo[0],".",
                   {:verbose => Options[:verbose]})
    }
}
if Options[:copy]
  f = Proc.new {|src,dest,opt| FileUtils.cp(src,dest,opt)}
elsif Options[:move]
  f = Proc.new {|src,dest,opt| FileUtils.mv(src,dest,opt)}
else
:(省略)
end

if f.class == Proc
  Options[:events].each {|n|
    nikon.event(n).each {|photo|
      f.call(photo[0],".",
             {:verbose => Options[:verbose]})
    }
  }
end

もっとすっきりするかと思ったけど、結局、重複感は残る。まあ、Procオブジェクトというのがあって、どうも関数オブジェクトとして扱えるらしいということが分かったのでよしとする。

と、思ったけど、別のやり方で、また変えてみた。

if Options[:copy] || Options[:move]
  f = Proc.new {|src,dest,opt|
    case
    when Options[:copy]
      FileUtils.cp(src,dest,opt)
    when Options[:move]
      FileUtils.mv(src,dest,opt)
    end
  }
  Options[:events].each {|n|
    nikon.event(n).each {|photo|
      f.call(photo[0],".",
             {:verbose => Options[:verbose]})
    }
  }
else
(省略)

うーん、あんまり変わらない。でも、制御構造の中で関数をスイッチしてfに代入しているこの方法のほうが、なんか処理の本質に近い気がする。