method_missingをdefine_methodに置き換える話

Jay Fields' Thoughts: Ruby: Replace method_missing with dynamic method definitions

Decoratorオブジェクトはメソッドをコンストラクタで指定されたオブジェクトに丸投げする委譲オブジェクトだ。
そこに存在しないメソッドを投げてみると…

method_missingを使って実装されたやつはこんな感じでエラーメッセージにDecoratorの文字すら出てこないからデバッグが困難だ。m9(^Д^)プギャー

class Decorator
  def initialize(subject)
    @subject = subject
  end

  def method_missing(sym, *args, &block)
    @subject.send sym, *args, &block
  end
end

d = Decorator.new [1]
d.length                        # => 1
d.not_exist
# ~> -:7:in `method_missing': undefined method `not_exist' for [1]:Array (NoMethodError)
# ~> 	from -:13:in `<main>'

method_missingではなくてコンストラクタに渡された時点のメソッドをdefine_methodで動的に登録するとエラーメッセージにDecoratorが出てくる。やっぱ俺こっちのが好きだ。

class Decorator
  def initialize(subject)
    subject.public_methods(false).each do |meth|
      (class << self; self; end).class_eval do
        define_method meth do |*args|
          subject.send meth, *args
        end
      end
    end
  end
end

d = Decorator.new [1]
d.length                        # => 1
d.not_exist
# ~> -:15:in `<main>': undefined method `not_exist' for [1]:Decorator (NoMethodError)