简体   繁体   中英

Understanding class_eval and instance_eval?

I'm confused as to when I should be using instance_eval and class eval .

I should or shouldn't use them?

Answer with simple examples on how to use them.

Thanks a lot.

The class_eval and instance_eval are both used to reopen an object and define additional behaviour.

They follows the open/closed principle .

class_eval

class_eval is used to define additional behaviour in the context of a class.

Let's use the following Person class:

class Person
  def initialize(name)
    @name = name
  end
end

Person.class_eval do
  def say_hello
    puts "Hello! I'm #{@name}"
  end
end

j = Person.new "John"
j.say_hello # Hello! I'm John

r = Person.new "Robert"
r.say_hello # Hello! I'm Robert

Both j and p can use a new method called say_hello that wasn't defined in the definition of the class Person , but on an extension of it.

instance_eval

instance_eval is used to define additional behavior in the context of a receiving object.

The previous example could be rewritten as:

class Person
  def initialize(name)
    @name = name
  end
end

j = Person.new "John"

j.instance_eval do
  def say_hello
    puts "Hello! I'm #{@name}"
  end
end

j.say_hello # Hello! I'm John

Since we used instance_eval on j , only the behavior of j has been redefined, in fact we can't use say_hello on another instance:

r = Person.new "Robert"
r.say_hello # undefined method `say_hello' for #<Person:0x00007fac43c15b28 @name="Robert"> (NoMethodError)

This is the opposite of class_eval .

Summary

  • class_eval allows you to open and redefine the behavior of a class in order to extend all instances of the class
  • instance_eval allows you to open and redefine the behavior of just an instance of a class

You should or shouldn't use them?

I'm of the idea that you shouldn't use them, because this can lead to code fragmentation.

But you have to use them when you want to add behavior on third parties code or when you want to add behavior dynamically.

Use ClassName.instance_eval to define a class method (one associated with the class object but not visible to instances). Use ClassName.class_eval to define an instance method (one that applies to all of the instances of ClassName).

Source: RubyMonk

instance_eval

One of the major differences between eval and instance_eval is that with instance_eval you have the choice of explicitly handling the context of self. As instance_eval is a method on Object it is scoped by the object you specify.

class_eval

class_eval is much simpler than instance_eval which works on metaclasses (or the singleton object). It works on the class as if you were opening it in a text editor and adding new state or behaviour to it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM