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

On 17 May 2011, at 02:20, John M. [email protected] wrote:

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
from :0

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:

String.instance_eval do
def test_method
“test”
end
end

class A; end
class B < String; end

A.test_method #=> NoMethodError
B.test_method #=> “test”

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs