2011-12-26 5 views
2

Rubyの代表団/プロキシ

class ArrayProxy < BasicObject 
    def initialize 
    @array = [] 
    end 

    def foo 
    puts 'foo' 
    end 

    def method_missing(*args, &block) 
    @array = @array.send(*args, &block) 
    end 

    def self.method_missing(*args, &block) 
    new.send(*args, &block) 
    end 
end 

はなぜ「foo」での呼び出しは、アレイに委任されていますか? method_missingため

ruby-1.9.2-p290 :018 > ArrayProxy.new << 1 
=> [1] 
ruby-1.9.2-p290 :019 > ArrayProxy << 1 
=> [1] 
ruby-1.9.2-p290 :020 > ArrayProxy.new.foo 
foo 
=> nil 
ruby-1.9.2-p290 :021 > ArrayProxy.foo 
NoMethodError: undefined method `foo' for []:Array 
+0

あなたのコードで '__send__'を試してください。そうするかもしれない。 – Linuxios

+0

これは、ドキュメントから行いました。名前がobj内の既存のメソッドと衝突する場合、__send__を使用できます。 'しかし、 'foo'はObjectのメソッドではありませんか?誰かが受け入れられた答えを明確にすることができますか? – Chris

+0

Btw、なぜ '@ array'を' method_missing'の中に割り当てますか? –

答えて

6

Linux_iOS.rb.cpp.c.lisp.m.shはBasicObjectは、インスタンスメソッドsendを定義していないとして、あなたが、その場合には__send__メソッドを使用する必要がありますコメントで述べたように:

でき
Object.instance_methods.grep /send/ 
# => [:send, :public_send, :__send__] 

BasicObject.instance_methods.grep /send/ 
# => [:__send__] 

ドキュメントによってBasicObjectについても証明されています。呼び出しの連鎖を以下にBasicObectクラスの結果でsendインスタンスメソッドの

不在:

# initial call 
ArrayProxy.foo 

# there's no class method 'foo', so we go to class 'method_missing' method 
ArrayProxy.method_missing :foo 

# inside class 'method_missing' we delegate call to new instance using 'send' 
ArrayProxy.new.send :foo 

# there is no instance method 'send' in ArrayProxy class (and its parent class 
# BasicObject) so instance 'method_missing' is called 
ArrayProxy.new.method_missing :send, :foo 

# instance 'method_missing' delegates call of 'send' method to @array 
@array.send :send, :foo 

# that is unfolded into regular call of 'send' on @array object 
@array.send :foo 

# and finally 'foo' is called for @array object 
@array.foo 
# => NoMethodError: undefined method `foo' for []:Array 
+0

偉大なステップスルー、ありがとう=] – Chris

0

署名がmethod_sym, *args, &blockあります。

私はあなたが(新しいArrayProxyをインスタンス化)クラスレベルmethod_missing宣言でnewを呼び出し、戻り値に送る呼びかけているとして、それは、アレイに送られていると思います。

なぜ@arrayを、method_missingのインスタンスレベル宣言で戻り値@array.send(*args, &block)に設定するのか、少し混乱します。

編集:これはむしろ奇妙な動作です。 @arrayからmethod_missingにコールを委任するのではなく、:fooArrayProxyのインスタンスに送信してfooを出力すると予想されます。

1

おそらくそれではなく、あなた自身の圧延、Rubyの標準ライブラリツールを使用する方が理にかなって?

Delegator class。 (私は1.9.3ドキュメントを指摘しましたが、1.8.xにもクラスが存在します)。

+0

必ずしもそうではありません。 'Delegator'を使うか、それをサブクラス化すると、' class'のようなメソッドは委譲されません。 'BasicObject'の最小限のメソッドセットは、' Delegator'が許すよりも多くのシナリオで元のオブジェクトに対して「スタンドイン」できるオブジェクトを作成することを可能にします。 – Kelvin

関連する問題