id:sumim:20100829:p1 の続き。
classbox.diff を当てた trunk のビルドができたので、本家の Classbox のテストコードの振る舞いを、Ruby版に書き直した結果と比べてみました。両者の挙動の違いには、おそらく、発表に対する質問にも出ていた local rebindings という機構の有無が効いてきているのだと思います。
▶ Ruby版 Classbox
module CB1 class A def foo; 10 end def bar; foo end end class B def foo; A.new.foo end end class C def foo; B.new.foo end end class D def foo; C.new.foo end end end module CB2 def foo; 20 end end module CB1 p A.new.foo #=> 10 p A.new.bar #=> 10 p D.new.foo #=> 10 overlay_module A, CB2 p A.new.foo #=> 20 p A.new.bar #=> 10 ; A#bar が呼ぶ #foo は元のまま p D.new.foo #=> 10 ; B#foo が呼ぶ A#foo も元のまま end
▶ Squeak Smalltalk版 Classbox を Ruby風に書き直したものと、本来期待される挙動
classbox CB1 import Classbox.system, [:Object] #A、B、C、D 定義でスーパークラスとして必要 class A def foo; 10 end def bar; foo end end class B def foo; A.new.foo end end class C def foo; B.new.foo end end class D def foo; C.new.foo end end end classbox CB2 import CB1, [:A, :D] #:A は、A#foo のすげ替えに必要。:D は後で D.new するのに必要。 class A def foo; 20 end end end classbox CB1 p A.new.foo #=> 10 p A.new.bar #=> 10 p D.new.foo #=> 10 end classbox CB2 p A.new.foo #=> 20 p A.new.bar #=> 20 ; CB2内では A#foo は置き換えられたものがコールされる p D.new.foo #=> 20 ; 同上 end
今回は import をメソッド風に、同じく Ruby 2.0 に追加予定の Traits機構を担う mixメソッドを真似たものに変えてみました。^^;
▶(例によって構文がないので、手続き的ですが―)実際の Squeak Smalltalk版 Classbox のコード例とその挙動
| cb1 cb2 | Classbox cleanTheSystem. cb1 := Classbox create: #CB1. cb1 import: #Object from: Classbox system. cb1 createClassNamed: #A. cb1 addMethod: 'foo ^10' for: #A. cb1 addMethod: 'bar ^self foo' for: #A. cb1 createClassNamed: #B. cb1 addMethod: 'foo ^A new foo' for: #B. cb1 createClassNamed: #C. cb1 addMethod: 'foo ^B new foo' for: #C. cb1 createClassNamed: #D. cb1 addMethod: 'foo ^C new foo' for: #D. cb2 := Classbox create: #CB2. cb2 import: #A from: cb1. cb2 import: #D from: cb1. cb2 addMethod: 'foo ^20' for: #A. World findATranscript: nil. Transcript cr; show: (cb1 evaluate: 'A new foo'). '=> 10 ' Transcript cr; show: (cb1 evaluate: 'A new bar'). '=> 10 ' Transcript cr; show: (cb1 evaluate: 'D new foo'). '=> 10 ' Transcript cr; show: (cb2 evaluate: 'A new foo'). '=> 20 ' Transcript cr; show: (cb2 evaluate: 'A new bar'). '=> 20 ' Transcript cr; show: (cb2 evaluate: 'D new foo'). '=> 20 '