On May 23, 2005, at 2:30 PM, Markus wrote: > > On Mon, 2005-05-23 at 13:21, Jamis Buck wrote: > >> Markus, >> >> when x.has_many :y, the :y property is not an array. It's an object >> that walks and talks like an array. (Just try using x.y.find >> sometime--it doesn't work like the Array version, which bit me hard >> several times in the past.) >> > > I'd buy that except: > > 1) x.y.class.name == 'Array' > > 2) x.y.class == Array > > 3) x.y.class.ancestors == [].class.ancestors > > 4) as I mentioned, > > >>> Adding: >>> >>> class Array >>> def self.===(other) >>> other.is_a? self >>> end >>> end >>> >>> right above the code in question fixes it. >>> > > That's a little strong for duck typing, isn't it? I my book that's > somewhere past duct taping and well into bailing wire territory. I > admit is possible, but it seems unlikely... Indeed, truth is stranger than fiction. ;) Consider this snippet from AR's association_proxy.rb. (Here's where we're getting into some pretty black magic): alias_method :proxy_respond_to?, :respond_to? instance_methods.each { |m| undef_method m unless m =~ /(^__|^nil \?|^proxy_respond_to\?|^send)/ } def method_missing(symbol, *args, &block) load_target @target.send(symbol, *args, &block) end def respond_to?(symbol, include_priv = false) proxy_respond_to?(symbol, include_priv) || (load_target && @target.respond_to?(symbol, include_priv)) end It's proxying to an array, and undefining all the relevant methods on the proxy so that things like #class get passed to the proxy, too. Unfortunately, it looks like === doesn't get proxied, and I'm not sure why. Perhaps Ruby does some optimizing under the covers? At any rate, yah. It can be annoying. But you really are dealing with a proxy, and not an array. At least, not directly. - Jamis