Why does instance_eval () define a class method when called in a class?

Foo = Class.new Foo.instance_eval do def instance_bar "instance_bar" end end puts Foo.instance_bar #=> "instance_bar" puts Foo.new.instance_bar #=> undefined method 'instance_bar' 

I understand that calling instance_eval on an object should allow you to define a variable or instance method for this object.

But in the above example, when you call it in the Foo class to define the instance_bar method, instance_bar becomes a class method that can be called using "Foo.instance_bar". It is clear that this code did not create an instance method, because Foo.new.instance_bar leads to an "undefined method" instance_bar ".

Why does instance_eval define a class method and not an instance method in this context?

+3
ruby class-method
May 23 '09 at 2:22
source share
2 answers

x.instance_eval changes your context, so self evaluates to x .

This allows you to do many things, including defining instance variables and instance methods, but only for x.

  x = Object.new y = Object.new # define instance variables for x and y x.instance_eval { @var = 1 } y.instance_eval { @var = 2 } # define an instance method for all Objects class Object def var @var end end x.var #=> 1 y.var #=> 2 

Ruby allows you to define instance methods for an object in several places. As usual, one defines them in the class, and these instance methods are distributed among all instances of this class (for example, def var above).

However, we can also define an instance method for only one object:

 # here one way to do it def x.foo "foo!" end # here another x.instance_eval do # remember, in here self is x, so bar is attached to x. def bar "bar!" end end 

Even if x and y have the same class, they do not share these methods, since they were defined only for x .

 x.foo #=> "foo!" x.bar #=> "bar!" y.foo #=> raises NoMethodError y.bar #=> raises NoMethodError 

Now in ruby ​​all objects, even classes. Class methods are only instance methods for this class object.

 # we have two ways of creating a class: class A end # the former is just syntatic sugar for the latter B = Class.new # we have do ways of defining class methods: # the first two are the same as for any other object def A.baz "baz!" end A.instance_eval do def frog "frog!" end end # the others are in the class context, which is slightly different class A def self.marco "polo!" end # since A == self in here, this is the same as the last one. def A.red_light "green light!" end # unlike instance_eval, class context is special in that methods that # aren't attached to a specific object are taken as instance methods for instances # of the class def example "I'm an instance of A, not A itself" end end # class_eval opens up the class context in the same way A.class_eval do def self.telegram "not a land shark" end end 

Remember once again that all these methods are A specific, B does not gain access to any of them:

 A.baz #=> "baz!" B.telegram #=> raises NoMethodError 

It’s important to distract from here that class is just the instance methods of an object of class Class

+7
May 23 '09 at 3:00 a.m.
source share

The purpose of instance_eval is to extend objects, but the purpose of class_eval is to extend classes. And since classes are also objects, you can use instance_eval for classes.

I assume that class extension is just more understandable in classic OOP. Dynamic languages ​​allow us to easily determine the behavior of individual objects. The fact that each object can have its own behavior adds a lot of flexibility when developing an application. For objects of the same class, there can be not only data. Two people differ not only in that they were born in different years, not only because they have different parents, but they can think differently and, therefore, behave differently.

The ability to change the behavior of each object is fundamental. It exists in many languages.

Thinking that instance_eval first thinks about objects. Then you will understand that classes are also objects - objects that are additionally designed to create new objects, to store descriptions of general behavior (methods). You can not only use the definition of a class, but you can also assign a class to a variable, pass a class as an argument, call a method in a class, program a class!

I would recommend articles written by Yehuda Katz and Yugui to dive deeper into it:

0
Apr 29 '14 at 7:36 on
source share



All Articles