Ancestor paths

ActiveRecord does this “trick”. For a normal object, this dump
routine:

def dump(name, obj)
puts “#{name}'s ancestors: #{obj.class.ancestors.inspect}”
puts “#{name}'s funky ancestors: #{(class << obj; self;
end).ancestors.inspect}”
end

produces the same list for ancestors and funky ancestors. For an
ActiveRecord Association, you get something like this:

temp’s ancestors: [ Cached::Queue <snip…>
ActiveRecord::Locking::Pessimistic, ActiveRecord::Locking::Optimistic,
ActiveRecord::Validations, Object, Socket::Constants,
InstanceExecMethods, Base64::Deprecated, Base64, Kernel]

temp’s funky ancestors:
[ActiveRecord::Associations::BelongsToAssociation,
ActiveRecord::Associations::AssociationProxy, Object, Socket::Constants,
InstanceExecMethods, Base64::Deprecated, Base64, Kernel]

Can someone tell me how this is done or point me to the code in active
record?

Thank you very much,
Perry

Perry S. wrote:

ActiveRecord does this “trick”. For a normal object, this dump
routine:
<>
Perry

FINALLY…

This simple program:

#!/usr/bin/env ruby

def dump(name, obj)
puts “#{name}'s class: #{obj.class}”
puts “#{name}'s ancestors: #{obj.class.ancestors.inspect}”
puts “#{name}'s meta ancestors: #{(class << obj; self;
end).ancestors.inspect}”
end

class Goofy
alias_method :proxy_respond_to?, :respond_to?
instance_methods.each { |m| undef_method m unless m =~
/(^__|^nil?$|^send$|proxy_)/ }

def initialize(o)
@target = o
end

def respond_to?(symbol, include_priv = false)
proxy_respond_to?(symbol, include_priv) ||
@target.respond_to?(symbol, include_priv)
end

private

def method_missing(method, *args, &block)
@target.send(method, *args, &block)
end
end

g = Goofy.new(“hi”)

dump(“g”, g)

Produces this output:

g’s class: String
g’s ancestors: [String, Enumerable, Comparable, Object, Kernel]
g’s meta ancestors: [Goofy, Object, Kernel]

Geeze that took me a long time to figure out.

Perry S. wrote:

g’s class: String
g’s ancestors: [String, Enumerable, Comparable, Object, Kernel]
g’s meta ancestors: [Goofy, Object, Kernel]

And, in my case, I added a method to String and to Object (the one in
String was more specific). But g.meth was going to the one in Object
instead of String. The reason is because it is not a missing method so
it doesn’t get proxied.