Module#define_methodを抽象化する話

Jay Fields' Thoughts: Ruby: Dynamically Define Method

たとえば、インスタンス変数にメソッド名のシンボルを格納するような一連のメソッドがあるとする。

def failure
 self.state = :failure
end

def error
 self.state = :error
end

def success
 self.state = :success
end

これらはModule#define_methodでまとめられる。

[:failure, :error, :success].each do |method|
 define_method method do
    self.state = method
 end
end

しかし、このままだと読みづらいからModule#def_eachを定義して抽象化する。*1

class Module
 def def_each(*method_names, &block)
   method_names.each do |method_name|
     define_method method_name do
        instance_exec method_name, &block
     end
   end
 end
end

Module#def_eachを使うとさきほどのメソッド定義はこのように読みやすくなる。

def_each :failure, :error, :success do |method_name|
 self.state = method_name
end

まあ、ぶっちゃけ黒魔術っぽい記述を具象クラスからは削除して、抽象化したメソッドを使えば読みやすくなるよーって話だ。readabilityのためなら、既存のクラスにメソッドを追加することくらいいとわない。納得。

*1:原文だとClass#def_eachだがModule#def_eachにすべき。