Ruby’s Method Lookup for attr_* Methods

Ruby’s attr_* methods are defined in the Module class as private instance methods. The Module class is not included in the ancestor hierarchy for a user-defined class, so it’s surprising that user-defined classes can access the attr_* methods at first glance.

class A; end
# Module is not one of A's ancestors
A.ancestors # => [A, Object, Kernel, BasicObject]
# No attr_* methods are available as private_instance_methods
A.private_instance_methods.grep /attr/ # => []

The attr_* methods work, so they’re obviously somewhere in A’s ancestor lookup hierarchy.

class Dog
  attr_reader :name
  def initialize
    @name = 'fido'
end # => 'fido'

The attr_reader method is called in the Dog class, so it needs to be defined somewhere in the singleton class ancestry chain, not the ancestor chain for the regular instance methods. It turns out that the Module class is in fact included in the singleton class ancestry chain.

class Dog; end
Dog.singleton_class.ancestors # => [Class, Module, Object, Kernel, BasicObject]
# attr_reader is defined in Module's singleton class
Dog.singleton_class.private_instance_methods.include?(:attr_reader) # => true

A user defined class has different ancestor hierarchies for the regular class and the singleton class. I didn’t know about this until I went on a method hunt for the attr_* methods. When you’re working with Ruby and something doesn’t make sense, keep digging and asking questions – this approach will answer your questions and help other concepts to fall into place.


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s