13

私はRubyでメタプログラミングを学んでおり、method_missingとdefine_methodを介して欠落しているメソッドを定義しようとしています。予期しない動作が発生しているので、誰かがこれを説明できるかどうか疑問に思っています。これが私のクラスです:

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

さて、このコード:

x = X.new

x.some_method
puts
x.some_method
puts
puts x

出力を生成します:

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>

私が得られないのは最後の部分です:なぜRubyはputsの呼び出しでto_aryを呼び出すのですか?Rubyがオブジェクトを印刷するためだけに配列に変換しようとするのはなぜですか?

私はグーグルで調べて、これらの関連リンクを見つけました:

これらはmethod_missingとto_aryの落とし穴についても話しますが、putsがto_aryを呼び出す理由については特に話しません。

また、to_sを定義しても、動作は変わらないことにも言及する必要があります。

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

「putsx」の出力は次のようになります。

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

1 に答える 1

16

putsの同義語です$stdout.puts。$ stdoutはIOクラスなので、IO.putsのドキュメントを参照してください。

IO#printと同様に、指定されたオブジェクトをiosに書き込みます。まだ改行シーケンスで終わっていないレコード区切り文字(通常は改行)を書き込みます。配列引数を指定して呼び出された場合、各要素を新しい行に書き込みます。

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

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

一方、メソッドは呼び出さずprint、のみを呼び出します。pto_aryto_s

補足:興味深いことに、オブジェクト定義メソッドなどではなく、to_ary実際のオブジェクトを返す必要があります。Arrayeach

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
于 2012-01-22T11:44:20.873 に答える