I am reading the Module
documentation but can't seem to understand their differences and which should be used where.
How is the eval
different than exec
?
I am reading the Module
documentation but can't seem to understand their differences and which should be used where.
How is the eval
different than exec
?
I'm going to answer a bit more than your question by including instance_{eval|exec}
in your question.
All variations of {instance|module|class}_{eval|exec}
change the current context, i.e. the value for self
:
class Array
p self # prints "Array"
43.instance_eval{ p self } # prints "43"
end
Now for the differences. The eval
versions accepts a string or a block, while the exec
versions only accept a block but allow you to pass parameters to it:
def example(&block)
42.instance_exec("Hello", &block)
end
example{|mess| p mess, self } # Prints "Hello" then "42"
The eval
version does not allow to pass parameters. It provides self
as the first parameter, although I can't think of a use for this.
Finally, module_{eval|exec}
is the same as the corresponding class_{eval|exec}
, but they are slightly different from instance_{eval|exec}
as they change what is the current opened class (i.e. what will be affected by def
) in different ways:
String.instance_eval{ def foo; end }
Integer.class_eval { def bar; end }
String.method_defined?(:foo) # => false
String.singleton_methods.include?(:foo) # => true
Integer.method_defined?(:bar) # => true
So obj.instance_{eval|exec}
opens the singleton class of obj
, while mod.{class|module}_{eval|exec}
opens mod
itself.
Of course, instance_{eval|exec}
are available on any Ruby object (including modules), while {class|module}_*
are only available on Module
(and thus Classes
)
self
instead), but I've edited my answer for completeness. –
Country mess
parameter coming from? –
Dimmick &block
, where "Hello"
is passed as the argument for mess
–
Gratian To answer your last question first, eval (in all its variations) is completely different from exec. exec $command
will start a new process to run the command you specify and then exit when that finishes.
class_eval
and module_eval
have the power to redefine classes and modules -- even those that you yourself did not write. For example, you might use class eval to add a new method that did not exist.
Fixnum.class_eval { def number; self; end }
7.number # returns '7'
class_eval
can be used to add instance methods, and instance_eval
can be used to add class methods (yes, that part is very confusing). A class method would be something like Thing.foo
-- you're literally calling the foo
method on the Thing
class. An instance method is like the example above, using class_eval
I've added a number
method to every instance of Fixnum
.
Okay, so that's the *_eval
class of methods. The exec methods are similar, but they allow you to look inside a class and execute a block of code as though it was defined as a method on that class. Perhaps you have a class that looks like this:
class Foo
@@secret = 'secret key'
@@protected = 'some secret value'
def protected(key)
if key == @@secret
return @@protected
end
end
end
The class Foo
is just a wrapper around some secret value, if you know the correct key. However, you could trick the class into giving you its secrets by executing a block inside the context of the class like so:
Foo.class_exec { @@secret = 'i'm a hacker' }
Foo.protected('i'm a hacker') #returns the value of @@protected because we overwrote @@secret
In general, with a lot of the tools in ruby, you could use any of these to solve a lot of problems. A lot of the time you probably won't even need to unless you want to monkey patch a class some library you use has defined (although that opens up a whole can of worms). Try playing around with them in irb and see which you find easier. I personally don't use the *_exec
methods as much as the *_eval
methods, but that's a personal preference of mine.
exec
and instance_exec
–
Country exec
explicitly at the beginning. exec
doesn't really have much in common with the eval
family of methods, so much as {instance|module|class}_exec
do. –
Tapis *_eval
vs *_exec
, not eval
vs exec
, but I might be wrong. –
Country To avoid ambiguity I'm going to call a method that belongs to (owned by) a singleton class a singleton method. The rest are instance methods. Although one might say that a singleton method of an object is an instance method of its singleton class.
tl;dr Use class_eval
/module_eval
on a class/module to define instance methods, and instance_eval
on a class/module to define class methods (or to be more precise, use instance_eval
to define singleton methods). Additionally you can use instance_eval
to access instance variables.
A terminology is a bit lacking in this case. ruby
maintains a stack of class references (cref
for short). When you open/reopen a class, the corresponding class reference is pushed to the stack. And the current class refernece affects where def
defines methods (to which class/module they're added).
Now, class_eval
/module_eval
and class_exec
/module_exec
are aliases.
The *_exec()
variants don't accept strings, and allow to pass arguments to the block. Since the *_eval()
variants are mainly used I'll focus on them.
class_eval
/module_eval
changes cref
and self
to the receiver (Thing
in Thing.module_eval(...)
):
rb_mod_module_eval()
-> specific_eval()
yield_under()
(for blocks)
eval_under()
(for strings)
instance_eval
changes cref
to the singleton class of the receiver, and self
to the receiver.
Let's see them in action:
class A
p self #=> A
@a = 1
def initialize
@b = 2
end
end
p A.instance_variables #=> [:@a]
p A.new.instance_variables #=> [:@b]
@a
on a class level adds an instance variable to the class A
as an object. I'm adding it here for completeness. But that's not how you add a class variable.
A.instance_eval do
p self #=> A
p @a #=> 1
def m() puts 'm' end
end
sclass = A.singleton_class
p sclass.instance_methods(false).include? :m #=> true
A.m #=> m
a = A.new
a.instance_eval do
p self #=> #<A:0x00007fc497661be8 @b=2>
p @b #=> 2
def m2() puts 'm2' end
end
sclass = a.singleton_class
p sclass.instance_methods(false).include? :m2 #=> true
a.m2 #=> m2
So, inside instance_eval
def
adds a singleton method to the receiver (an instance method to the singleton class of the receiver). For a class/module that means a class/module method. For other objects, a method that is available for that particular object.
A.class_eval do
p self #=> A
p @a #=> 1
def m() puts 'm' end
end
p A.instance_methods(false).include? :m #=> true
A.new.m #=> m
And, inside class_eval
def
adds an instance method to the receiver itself (the class/module). class_eval
is only available for classes/modules.
Also, when class_eval
is passed a block, constant/class variable lookup is not affected:
module A
C = 1
@@c = 1
class B
C = 2
@@c = 2
end
A::B.class_eval { p [C, @@c] } #=> [1, 1]
A::B.class_eval 'p [C, @@c]' #=> [2, 2]
end
The naming is confusing. I might guess that instance
in instance_eval
suggests that receiver is treated as an instance (allows to change things for a particular instance), and class
in class_eval
as a class (allows to change things for a class of objects).
© 2022 - 2024 — McMap. All rights reserved.