to_ary is used for implicit conversions, while to_a is used for explict conversions.

require 'pry'

class Row
  attr_accessor :items

  def initialize(*items)
    if items.is_a?(Array)
      @items = items
    end
  end

  # 显式转化
  def to_a
    puts "call to_a>>"
    @items
  end

  # 隐式转化
  def to_ary
    puts "call to_ary>>"
    @items
  end

  def inspect
    puts "call inspect>>"
  end
end

row1 = Row.new(1, 2, 3)

p row1
#call inspect>>
#


puts row1
# 1
# 2
# 3


row2 = Row.new(*row1)
#call to_a>>


a, b, c = row1
# call to_ary>>

to_ary allows an object to be treated as an array, whereas to_a actually tries to convert the parameter into an array.

to_ary can be useful for parallel assignment, whereas to_a is more suited for an actual conversion.

class A < Array
end

puts A[1, 2, 3].to_a.class
# Array
puts A[1, 2, 3].to_ary.class
# A

参考

https://stackoverflow.com/questions/9467395/whats-the-difference-between-to-a-and-to-ary

active_support/core_ext/array/wrap.rb

class Array
  def self.wrap(object)
    if object.nil?
      []
    elsif object.respond_to?(:to_ary)
      object.to_ary || [object]
    else
      [object]
    end
  end
end

Array.wrap 能保证返回的值总是可以迭代的, 并保留原值的类型, 也不会做其他 to_a 的隐式调用.