The eval
method provides a simple way of evaluating a Ruby expression in a string. At first sight, eval
may appear to do the same job as the #{ }
delimiters in a double-quoted string. These two lines of code produce identical results:
eval.rb
puts( eval("1 + 2" ) ) #=> 3 puts( "#{1 + 2}" ) #=> 3
Sometimes, however, the results may not be what you are expecting. Look at the following, for instance:
eval_string.rb
exp = gets().chomp() #<= User enters 2*4 puts( eval( exp )) #=> 8 puts( "#{exp}" ) #=> 2*4
Let’s suppose you enter 2 * 4
, and this is assigned to exp
. When you evaluate exp
with eval
, the result is 8, but when you evaluate exp
in a double-quoted string, the result is "2*4"
. This is because anything read in by gets()
is a string and "#{exp}"
evaluates it as a string and not as an expression, whereas eval( exp )
evaluates a string as an expression. To force evaluation inside a string, you could place eval
in the string (though that, admittedly, might defeat the object of the exercise):
puts( "#{eval(exp)}" )
Here is another example. Try it, and follow the instructions when prompted:
eval2.rb
print("Enter a string method name (e.g. reverse or upcase):") # user enters: upcase methodname = gets().chomp() exp2 = "'Hello world'."<< methodname puts( eval( exp2 ) ) #=> HELLO WORLD puts( "#{exp2}" ) #=> 'Hello world'.upcase puts( "#{eval(exp2)}" ) #=> HELLO WORLD
The eval
method can evaluate strings spanning many lines, making it possible to execute an entire program embedded in a string:
eval3.rb
eval( 'def aMethod( x ) return( x * 2 ) end num = 100 puts( "This is the result of the calculation:" ) puts( aMethod( num ))' )
Look carefully at the previous code. It contains just one executable expression, which is a call to the eval()
method. Everything else, which at first sight looks like code, is in fact a single-quoted string that is passed as an argument to eval()
. The eval()
method “unpacks” the contents of the string and turns it into real Ruby code that is then executed. This is displayed:
This is the result of the calculation: 200
With all this eval
cleverness, let’s now see how easy it is to write a program that can itself write programs. Here it is:
eval4.rb
input = "" until input == "q" input = gets().chomp() if input != "q" then eval( input ) end end
This may not look like much, and yet this little program lets you both create and execute Ruby code from a prompt. Try it. Run the program, and enter the two methods shown here one line at a time (but don’t hitq to quit yet—you’ll be writing some more code in a moment):
def x(aStr); puts(aStr.upcase);end def y(aStr); puts(aStr.reverse);end
Note that you have to enter each whole method on a single line since the program evaluates every line as it is entered. I’ll explain how to get around that limitation later. Thanks to eval
, each method is turned into real, workable Ruby code. You can prove this by entering the following:
x("hello world") y("hello world")
Now, when you press enter after each line in the previous code, the expressions are evaluated, and they call the two methods, x()
and y()
, which you wrote a moment ago, resulting in this output:
HELLO WORLD dlrow olleh
That’s not bad for just five lines of code!