![](/style/images/good.png)
![](/style/images/bad.png)
Idiosyncratic Ruby: idiosyncratic_eval
source link: https://idiosyncratic-ruby.com/63-instance-eval.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
idiosyncratic_eval
When you get farther upwards the steep hill that is Ruby mastery, you will come across some powerful, yet slightly evil methods: instance_eval and class_eval¹. They allow you to execute code and define methods tied to a specific class, at the same time giving you access to outer scope variables through the Ruby block syntax. Their exact behavior varies, depending on the context they are used in. So what is the difference between all the evals?
¹ Also aliased as module_eval
Eval / Method Definition Comparison
In the following tables, you will find all combinations of defining a method and executing it in a different class context:
Class Scope
Definition Method
No eval
class_eval
instance_eval
def
instance
instance
class
define_method
instance
instance
instance
def self.
class
class
class
define_singleton_method
class
class
class
Class-Class Scope (class << self
)
Observations
While class_eval
behaves exactly as if it was in no eval-context at all, instance_eval
features a notable difference:
def inside instance_eval will define methods one class-level higher. So when instance_eval
is executed on instances, def
will create instance methods instead of singleton methods. And when it is run on classes, def
will create class methods instead of instance methods.
Another difference is that while class_eval
is defined on Module, instance_eval
lives in BasicObject allowing you to use it on any object, not only modules and classes. However, there is a simple way to use class_eval
for instances, too. You can explicitly use the object's singleton class (class << self
), which is a module:
o = Object.new # => #<Object:0x000055b6fdabf1f8>
o.singleton_class.class_eval do
def m
p self
end
end
o.m # => #<Object:0x000055b6fdabf1f8>
Best Practice
Overall, the behavior of instance_eval
is rather confusing and my recommendation is to avoid it and always use class_eval
. If you do not need closure access, consider using no eval at all.
Reference / Examples: Class-Level Scope
For reference, what follows is a list of snippets illustrating each eval-define combination.
Class / def
Defines method on instance-level
class C
def m
p self
end
end
C.new.m # => #<C:0x0000556efd3eb1a8>
Class / class_eval
+ def
Defines method on instance-level
class C
class_eval{
def m
p self
end
}
end
C.new.m # => #<C:0x0000556efd3eb1a8>
Class / instance_eval
+ def
Defines method on class-level
class C
instance_eval{
def m
p self
end
}
end
C.m # => C
Class / define_method
Defines method on instance-level
class C
define_method(:m){
p self
}
end
C.new.m # => #<C:0x0000556efd3eb1a8>
Class / class_eval
+ define_method
Defines method on instance-level
class C
class_eval{
define_method(:m){
p self
}
}
end
C.new.m # => #<C:0x0000556efd3eb1a8>
Class / instance_eval
+ define_method
Defines method on instance-level
class C
instance_eval{
define_method(:m){
p self
}
}
end
C.new.m # => #<C:0x0000556efd3eb1a8>
Class / def self.
Defines method on class-level
class C
def self.m
p self
end
end
C.m # => C
Class / class_eval
+ def self.
Defines method on class-level
class C
class_eval{
def self.m
p self
end
}
end
C.m # => C
Class / instance_eval
+ def self.
Defines method on class-level
class C
instance_eval{
def self.m
p self
end
}
end
C.m # => C
Class / define_singleton_method
Defines method on class-level
class C
define_singleton_method(:m){
p self
}
end
C.m # => C
Class / class_eval
+ define_singleton_method
Defines method on class-level
class C
class_eval{
define_singleton_method(:m){
p self
}
}
end
C.m # => C
Class / instance_eval
+ define_singleton_method
Defines method on class-level
class C
instance_eval{
define_singleton_method(:m){
p self
}
}
end
C.m # => C
Reference / Examples: Class-Class-Level Scope
Class-Class / def
Defines method on class-level
class C
class << self
def m
p self
end
end
end
C.m # => C
Class-Class / class_eval
+ def
Defines method on class-level
class C
class << self
class_eval{
def m
p self
end
}
end
end
C.m # => C
Class-Class / instance_eval
+ def
Defines method on class-class-level
class C
class << self
instance_eval{
def m
p self
end
}
end
end
C.singleton_class.m #=> #<Class:C>
Class-Class / define_method
Defines method on class-level
class C
class << self
define_method(:m){
p self
}
end
end
C.m # => C
Class-Class / class_eval
+ define_method
Defines method on class-level
class C
class << self
class_eval{
define_method(:m){
p self
}
}
end
end
C.m # => C
Class-Class / instance_eval
+ define_method
Defines method on class-level
class C
class << self
instance_eval{
define_method(:m){
p self
}
}
end
end
C.m # => C
Class-Class / def self.
Defines method on class-class-level
class C
class << self
def self.m
p self
end
end
end
C.singleton_class.m # => C
Class-Class / class_eval
+ def self.
Defines method on class-class-level
class C
class << self
class_eval{
def self.m
p self
end
end
}
end
C.singleton_class.m #=> #<Class:C>
Class-Class / instance_eval
+ def self.
Defines method on class-class-level
class C
class << self
instance_eval{
def self.m
p self
end
}
end
end
C.singleton_class.m #=> #<Class:C>
Class-Class / define_singleton_method
Defines method on class-class-level
class C
class << self
define_singleton_method(:m){
p self
}
end
end
C.singleton_class.m # => C
Class-Class / class_eval
+ define_singleton_method
Defines method on class-class-level
class C
class << self
class_eval{
define_singleton_method(:m){
p self
}
}
end
end
C.singleton_class.m #=> #<Class:C>
Class-Class / instance_eval
+ define_singleton_method
Defines method on class-class-level
class C
class << self
instance_eval{
define_singleton_method(:m){
p self
}
}
end
end
C.singleton_class.m #=> #<Class:C>
Also See
More Idiosyncratic Ruby
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK