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.
CodePudding user response:
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 classinstance_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.
CodePudding user response:
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).