how instance_eval on Object class creating class methods and not instance methods?

Hey all,

I am a little confused about a tutorial I read. Here's an example below taken from the tutorial:

Object.instance_eval do    def has_attribute( *attrs )        attrs.each do | attr |            self.class_eval %Q{                 def #{attr}=(val)                     instance_variable_set("@#{attr}", val)                 end

                def #{attr}                     instance_variable_get("@#{attr}")                 end            }        end    end end

class A    has_attribute :my_attribute, :another_attribute end

a = A.new

puts a.methods - Object.methods # => ["my_attribute", my_attribute=", "another_attribute", "another_attribute="]

a.my_attribute = 1 a.my_attribute # => 1

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?

Thanks for response

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

Fred.

I think you are just confused by the overloaded use of the words objct and class as opposed to the ruby classes named Object and Class.

This diagram / project might help clarify

http://objectgraph.rubyforge.org/dotOG.html

From

http://objectgraph.rubyforge.org/

Max

Let me see if I fully understand this.

This:

Object.instance_eval   def a    puts 'a'   end end

is equivalent to this:

class Object   def self.a    puts 'a'   end end

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

ruby-1.8.7-p330 :015 > @a = Object.new => #<Object:0x1064fcf98> ruby-1.8.7-p330 :016 > @a.a

Thanks for response

It's not defining it on Class, it's defining it on the Object class. Every class inherits from Object, so every class inherits that class method.

If you define it on a different class, it will belong to that class and its descendants: