a.another_attribute = "A String"
a.another_attribute
# => "A String"
THe guy says:
"The first instance_eval is used to add class method has_attribute into
Object so that we can call it in all the inherited class."
I'm a little thrown off by this statement. First, Object itself is an
instance of class Class. Someone here even said before "Object is an
instance of Class". So "class Object end "implies that Object is an
instance of class, equivalent to: Object = Class.new. Hence, we can
invoke instance_eval on Object, since Object is an instance. What
confuses me here is has_attribute appears to be an instance method (e.g.
def a end) not class method (e.g. def self.a end). So why does guy say
we add class method has_attribute?
In fact, the difference between Object class and Class class is that
when you add methods to class Class, those methods become available to
any class that is created as well (since all classes created using class
construct inherit from Class) and you can use those methods within any
class. However, that's not what we do above. We extend Object above.
When you instantiate a class, you inherently create an object instance,
so that object instance should have available the methods defined in
Object. So then how can we access that method within a class, such as
that being done in class A above?
THe guy says:
"The first instance_eval is used to add class method has_attribute into
Object so that we can call it in all the inherited class."
I'm a little thrown off by this statement. First, Object itself is an
instance of class Class. Someone here even said before "Object is an
instance of Class". So "class Object end "implies that Object is an
instance of class, equivalent to: Object = Class.new. Hence, we can
invoke instance_eval on Object, since Object is an instance. What
confuses me here is has_attribute appears to be an instance method (e.g.
def a end) not class method (e.g. def self.a end). So why does guy say
we add class method has_attribute?
Well a class method called has_attribute has been added. I think this is just awkward phrasing - instance_eval is indeed invoked on Object. As to why that results in a class method, that's sort of what instance_eval does - there are lots of articles on instance_eval and class_eval etc. that go into the details
Basically, instance_eval invoked on Object creates a new class method
for the Object class (or for class Class? and if it is class Class, then
why bother invoking instance_eval it on Object?). The reason why I say
this is because that method is now available to class Class and all
classes created, since they all inherit from class Class when using the
class construct. The only logical explanation I can come up for this
behavior is that whenever you create a class method, the method is
automatically copied to class Class and therefore all classes inherit
from it. Correct? If so, then why use instance_eval on Object?
Example:
ruby-1.8.7-p330 :001 > class Object
ruby-1.8.7-p330 :002?> def self.a
ruby-1.8.7-p330 :003?> puts 'a'
ruby-1.8.7-p330 :004?> end
ruby-1.8.7-p330 :005?> end
ruby-1.8.7-p330 :006 > class A
ruby-1.8.7-p330 :007?> end
ruby-1.8.7-p330 :011 > Object.a
a
ruby-1.8.7-p330 :008 > A.a
a
This fails because @a is an instance method that does not have access to
class methods, even class methods of Object:
ruby-1.8.7-p330 :009 > @a = A.new
=> #<A:0x1069a3088>
ruby-1.8.7-p330 :010 > @a.a
NoMethodError: undefined method `a' for #<A:0x1069a3088>
from (irb):10