Evaluating Alternative Decorator Implementations In Ruby
これの最後の delegate を使ったサンプルが Ruby 1.8 だと素直に動かなかった。
Ruby の delegate ライブラリについてはとりあえずここを読めば分かると思う。
Rubyist Magazine - 標準添付ライブラリ紹介 【第 6 回】 委譲
問題
test_delegator.rb
class Coffee
def cost
2
end
end
require 'delegate'
class Decorator < SimpleDelegator
def class
__getobj__.class
end
end
class Milk < Decorator
def cost
super + 0.4
end
end
coffee = Coffee.new
puts Milk.new(coffee).cost
irb(main):001:0> RUBY_VERSION
=> "1.8.7"
irb(main):002:0> load 'test_delegator.rb'
2
irb(main):001:0> RUBY_VERSION
=> "1.9.3"
irb(main):002:0> load 'test_delegator.rb'
2.4
最後の結果が違うのに注目すれば良いのだけど、要点は
- (Simple)Delegator を継承したクラス(この場合は Decorator)で
class
メソッドを__getobj__.class
とオーバーライドした場合 - 移譲先オブジェクトのメソッドをオーバーライド(Milk#cost)しても、Ruby 1.8 だとオーバーライドがうまく動作しない
という感じ。
ソースを追ったら Delegator クラスの initialize の中で self.class.ancestors のメソッドを再定義しているのがダメっぽい。
1.9 からは別実装になってるので、問題無く動作する。
解決策
力技だけど、1.9 のソースを持ってきて、1.8 以下の時はそっちを使うようにした。
もっと良い解決策
Ruby のバージョンをあげる