「 Selfish: Ruby で Self 的プロトタイプベース!」の変更案
keita_yamaguchiさんのSelf関連の記事とても楽しく読まさせてもらっています。
さて、http://d.hatena.ne.jp/keita_yamaguchi/20080811/1218445378の記事なんですが、こうするとよりSelfに近いんじゃないかなと思うのですがどうでしょう?
やってることは、データの入っているslotは単純にデータを入れるのではなくreader兼setterのProcオブジェクトを入れるというものです。readerかsetterかはsetする値を指定するか否かで変わります。こうすることで、代入に=なんていう邪悪な記号が出てこないし、setterのメソッドチェーンも出来てうれしいのではないかなと思います。その代わり、効率が落ちますけど・・・。
追記1: 私の操作ミスで2回トラックバックが行ってしまいました。keita_yamaguchiさん申し訳ありません。
追記2: このパッチを当てると、1.9系じゃないと動かなくなります。ブロックのオプショナル引数を使いたいからです。
セッションはこんな感じになります。
require 'lib/selfish.rb' a = _(:x => 1) # p a.x # => 1 p a.x 2 # => #<Selfish::Object:0x1001b084 @slots={:x=>2}> p a.x # => 2 p _(:sum => proc {|s| s.x + s.y}, :x => 1, :y => 2).sum # => 3 p _(:_parent => _(:sum => proc {|s| s.x + s.y}), :x => 1, :y => 2).sum # => 3
パッチです
diff -uprN selfish.rb.org selfish.rb --- selfish.rb.org 2008-08-12 20:47:20.500000000 +0900 +++ selfish.rb 2008-08-12 22:11:33.468750000 +0900 @@ -26,9 +26,14 @@ module Selfish visited << self if @slots.has_key?(selector) if @slots[selector].kind_of?(Proc) - [ @slots[selector] ] # method slot + cont = @slots[selector].call(nil) + if cont.kind_of?(Proc) then + [ cont ] # method slot + else + [ @slots[selector] ] # data slot + end else - [ proc{ slots[selector] } ] # data slot + [ proc{ slots[selector] } ] # Literal end else parent_lookup(selector, visited) @@ -50,21 +55,27 @@ module Selfish end module SlotInterface + UNDEF_VALUE = [:undef] attr_reader :slots # Adds new slot. def add_slot(name, val=nil) - # data slot - @slots[name.to_sym] = val - # slot writer - @slots[:"#{name}="] = proc {|s, val| s.slots[name] = val } + # data reader/writer + @slots[name.to_sym] = ->(s, v = UNDEF_VALUE) { + if v == UNDEF_VALUE then + val + else + s.slots[name] = v + s + end + } end # Returns parents. def parents @slots.keys.select{|name| name.to_s =~ /\A_.*[^=]\Z/ - }.map{|name| @slots[name]} + }.map{|name| @slots[name].call(nil)} end end