Pramod
Pramod

Reputation: 1416

Class Methods in Object Class of Ruby

I was trying to implement my own attr_accessor method. I implemented that as follow.

class Object
  def my_attr_accessor(*args) # self.my_attr_accessor(*args)
    args.each do |arg|
      define_method "#{arg}" do
        return instance_variable_get("@#{arg}")
      end
      define_method "#{arg}=" do |val|
        instance_variable_set("@#{arg}", val)
      end
    end
  end
end

Then I created a class which calls the my_attr_accessor method.

class Runner 
  my_attr_accessor :name
end

test= Runner.new
test.name = "runner"
puts test.name

My question is even though I haven't explicitly defined self.my_attr_accessor method, it is acting as a class method. Can someone help me in figuring out how it's happening.

EDIT: Irrespective of making self.my_attr_accessor or my_attr_accessor in Object class, it works if I say my_attr_accessor within my Runner class. Why?

Upvotes: 3

Views: 121

Answers (3)

Jörg W Mittag
Jörg W Mittag

Reputation: 369420

This is called "inheritance". In Ruby, subclasses "inherit" methods from their superclasses. In other words, if you send a message to an object, Ruby will look up a method whose name matches the message in the class of the object, and if it can't find it, it will follow that classes' superclass pointer, and then that classes' superclass pointer, and so on, until it either finds a matching method or reaches a class which doesn't have a superclass.

Since Class is a subclass of Object (indirectly via Module), it inherits Object's methods.

[Note: inheritance is a fundamental concept in Ruby, you should probably go back and learn the fundamentals of Ruby before trying advanced reflective metaprogramming. In particular how the ancestry chain (the superclass pointers) are constructed and message dispatch works.]

Upvotes: 4

Thomas
Thomas

Reputation: 1633

Since everything is an instance of Object in ruby, you can call your method from anywhere:

class Object
  def my_attr_accessor(*args)
  end
end

puts self.class                           # => Object
puts self.is_a?(Object)                   # => true
puts self.respond_to?(:my_attr_accessor)  # => true

class Runner
  puts self.class                           # => Class
  puts self.is_a?(Object)                   # => true
  puts self.respond_to?(:my_attr_accessor)  # => true
  my_attr_accessor :name
end

Upvotes: 1

Shimu
Shimu

Reputation: 1147

You create a new Runner with Runner.new. So you have an instance of the Runner class.
Since you called my_attr_accessor in your class block, you have created the method .name on your instance. This is important. my_attr_accessor is a call to the method my_attr_accessor. And in the base class, i.e. in Object, Ruby finds this method and calls it.
Now, you can call test.name = "runner".

Upvotes: 0

Related Questions