Reputation: 1416
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
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
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
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