Ruby:为什么要调用to_ary?

我正在学习Ruby中的元编程,我只是尝试通过method_missing和define_method定义缺失的方法。 我有一些意想不到的行为,我想知道是否有人可以解释这一点。 这是我的class级:

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 # 

我没有得到的是最后一部分:为什么Ruby在调用puts时调用to_ary? 为什么Ruby会尝试将我的对象转换为数组只是为了打印它?

我用Google搜索并发现了以下相关链接:

  • http://tenderlovemaking.com/2011/06/28/til-its-ok-to-return-nil-from-to_ary/
  • http://yehudakatz.com/2010/01/02/the-craziest-fing-bug-ive-ever-seen/

这些也讨论了method_missing和to_ary陷阱,但没有具体说明为什么puts会调用to_ary。

我还应该提一下,当我定义一个to_s时,行为不会改变,例如

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

然后输出“puts x”:

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

puts$stdout.puts的同义词。 $ stdout是一个IO类,所以请查看IO.puts的文档:

像IO#print一样将给定对象写入ios。 在任何尚未以换行序列结束的记录分隔符之后写入记录分隔符(通常是换行符)。 如果使用数组参数调用,则将每个元素写入新行。

这意味着puts方法旨在写几行输出。 因此,它尝试在对象上调用to_ary方法,如果定义了to_ary ,则在新行上打印返回的Array每个元素,否则调用to_s方法。

Ruby文档中没有详细记录to_ary内部用法(Matz在他的The Ruby Programming Language一书中指出了这一点)。

方法printp另一方面不要调用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