What is the difference between class_eval, class_exec, module_eval and module_exec?
Solution 1:
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
)
Solution 2:
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.