3

the ruby book I'm reading has confused me a bit. If I do the following, I understand completely why the code throws an error;

class Person
  def show_name
    puts @name
  end
end

person = Person.new
person.show_name
Person.show_name   #(note the capital P) this line falls over

It throws an error stating that the Person class does not have a method called show_name, because it is an instance method. I understand this completely. The book then throws in this example;

class Class
  def add_accessor(accessor_name)
    self.class_eval %Q{attr_accessor :#{accessor_name}}
  end
end

class Person
end

person = Person.new
Person.add_accessor :name    #note the capital P
Person.add_accessor :age     #capital P here too

person.name = "Mikey"
person.age = 30

puts person.name

and goes on to state how cool it is that you can add methods to classes dynamically. What I don't understand is why I am suddenly allowed to call the "add_accessor" method as a class method (with a capital P) when the method itself isn't defined as such? I thought all class methods had to be declared like this?

class Math
  def self.PI
    3.141
  end
end

puts Math.PI

Is anyone able to enlighten me?

Mikey Hogarth
  • 4,672
  • 7
  • 28
  • 44

4 Answers4

2

Ruby classes are objects like everything else to. Your Person class is really an object of class Class, which in turn inherits from class Module. When you add a method to class Class as an instance method, you are providing a new method for all classes. If you had declared it with a def in Person, it would not be callable without an object. To add class methods for one class, but not all, you must prepend the method name with self or the name of the class:

class Person
    def instance_method
    end
    def self.class_method
    end
    def Person.other_class_method
    end
end

When you declare the method as self.class_method you are declaring your method to be a singleton method on the class object. self in a class or module declaration refers to the class object, which is why self. and Person. are the same. When dealing with Ruby, just remember everything is an object, everything has methods. There are no functions in Ruby either, despite appearances to the contrary. Methods and objects, always.

Linuxios
  • 34,849
  • 13
  • 91
  • 116
1

You're extending the Class class, and all of your classes, like Person, are instances of Class (Yes, classes are instances of the Class class. They're ordinary objects).

So when you call Person.add_accessor, you're calling the instance method Class#add_accessor.

Dominik Honnef
  • 17,937
  • 7
  • 41
  • 43
1

Look at this:

person.instance_of?(Person) #=> true
Person.instance_of?(Class)  #=> true

You have defined an instance method add_accessor for all the instances of the class Class, so Person class can use that method because it is an instance of Class.

I recommend yout to take a look at metaprogramming and Ruby Object Model.

Hoep this helps

Community
  • 1
  • 1
JCorcuera
  • 6,794
  • 2
  • 35
  • 29
0

because Person (with capital P ) is an instance of the class Class.

Nikolaus Gradwohl
  • 19,708
  • 3
  • 45
  • 61