method_missing と instance_eval を使った Decorator

Kernel#method_missing を使ってみたいです。

method_missing は、任意のクラスに対してメソッドが呼び出されたとき、対象のメソッドがそのクラスのクラス階層のどこにも実装されてなかった場合に呼び出されるメソッド、だそうです。Perl の AUTOLOAD に似ています。

そこで、method_missing を使った Decorator パターンを実装してみました。Dog オブジェクトを渡すとその犬が強くなる StrongDog です。

dog = Dog.new('ポチ')
sdog = StrongDog.new(dog)

dog.bark
sdog.bark

という風に使います。すると、

ポチ: わんわん
ポチ+1: brrr...
ポチ+1: わんわん

という風な結果が返ります。Decorator の StrongDog でくるむと +1 されて(ロングソード+1、のようなイメージです)、威勢がよくなります。クラスの実装は以下のようにしてみました。

class Dog
  attr :name
  def initialize(name)
    @name = name
  end

  def bark
    puts "#@name: わんわん"
  end
end

class StrongDog
  def initialize(dog)
    @dog = dog
    @dog.name << "+1"
  end

  def method_missing(method_id)
    puts "#{@dog.name}: brrr..."
    @dog.instance_eval(method_id.id2name)
  end
end

StrongDog#bark は実装していないので、それが呼び出されると method_missing が呼び出され、前処理を挟んだあと @dog に同名のメソッドに処理を転送します。

instance_eval の理解がまだ不完全ですが、なんとなく使ってみたらうまくいきました。