2012-01-22 6 views
11

私はRubyでメタプログラミングを学んでおり、method_missingとdefine_methodで欠落しているメソッドを定義しようとしています。私は予想外の動作をしており、誰かがこれを説明できるかどうか疑問に思っています。ここに私のクラスである:今Ruby:putsがto_aryを呼び出すのはなぜですか?

class X 
    def method_missing(m, *args, &block) 
    puts "method #{m} not found. Defining it." 
    self.class.send :define_method, m do 
     puts "hi from method #{m}" 
    end 
    puts "defined method #{m}" 
    end 
end 

、このコード:なぜRubyが呼んでいる:私は得ることはありません何

method some_method not found. Defining it. 
defined method some_method 

hi from method some_method 

method to_ary not found. Defining it. 
defined method to_ary 
#<X:0x007fcbc38e5030> 

最後の部分である:

x = X.new 

x.some_method 
puts 
x.some_method 
puts 
puts x 

は出力を生成しますto_aryを呼び出して呼び出しますか?なぜRubyはオブジェクトを配列に変換して印刷するのですか?

私の周りGoogleで検索し、これらの関連リンクを見つけた

これらも具体的プットがto_aryを呼ぶだろう理由についてmethod_missingとto_ary落とし穴についての話ではなく、 。

to_sを定義したときの動作は変更されません。

def to_s 
    "I'm an instance of X" 
end 

"プットのX" の出力は、次のとおりです

method to_ary not found. Defining it. 
defined method to_ary 
I'm an instance of X 

答えて

14

puts$stdout.putsと同義です。 $ stdoutがIOクラスなので、IO.putsのドキュメントを見て:

は、IO#印刷のように、IOSに与えられたオブジェクトを書き込みます。レコード セパレータ(通常は改行)を、改行シーケンスである で終了していないものの後に書き込みます。配列引数を指定して呼び出された場合、新しい行にそれぞれ 要素を書き込みます。

これは、putsメソッドが出力のいくつかの行を書き込むことを意図していることを意味します。したがって、オブジェクト上でto_aryメソッドを呼び出そうとし、to_aryが定義されている場合は、返されたArrayの各要素を新しい行に出力します。それ以外の場合はputsto_sメソッドを呼び出します。

to_ary Rubyのドキュメントでは、内部的な使用法は実際にはよく書かれていません(Matz氏はRubyプログラミング言語本でこれを指摘しています)。

メソッドprintおよびpは、to_aryを呼び出すことはありません。to_sのみを呼び出してください。

追記:興味深い、to_aryは本物Arrayオブジェクトではなく、each方法または他の何か定義するオブジェクトを返す必要があることを:

class Test 
    def to_ary 
    10.downto(1) 
    end 
end 

puts Test.new 

#TypeError: can't convert Test to Array (Test#to_ary gives Enumerator) 
#  from (irb):28:in `puts' 
#  from (irb):28:in `puts' 
#  from (irb):28 
+0

感謝を。私はエッセンスが "to_ary内部使用法は本当にRubyのドキュメントではよく文書化されていない"と思う:)私はちょうどIO.putsドキュメントを読む、彼らは明示的にto_aryを言及していない、これは私が考えるより明らかにする必要があります。 "Rubyプログラミング言語"の本を指してくれてありがとう、それをチェックするかもしれない。 –

関連する問題