Today we’re going to discuss one of those highly-controversial hot topics in Ruby (if there can be such a thing as a “hot topic” in programming languages)–the eval function.
What does eval do? Quite simply, you pass in some Ruby code in a string, and it’ll evaluate it. Observe:
eval "puts 2+2" # => 4
eval "'hello world!'.upcase # => HELLO WORLD
Clearly, this is useful stuff–you can pass in arbitrary code, even assemble your strings on the fly for truly complicated code.
But, eval is a dangerous tool–because it can execute arbitrary code. For example, if you have some code like this:
input = # ... read from some form
eval input
# ...
Some clever script kiddie will send the input system 'rm -rf *', you can kiss your application goodbye. And your family photo-collection. And your MP3 collection. And your hard-drive.
Some people brand eval as an “evil,” “insidious,” “destructive” function. Which is true–it has destructive potential. That’s why you need to sanitize your input. Don’t just send it as-is. Don’t risk it.
On the other hand, eval has a lot of tricky uses for things you might not otherwise be able to do. For example, how would you create a generic “shutdown hook” system for your Ruby application? other programming languages have pointers–in .NET, for example, you can accumulate a collection of pointers, and run those. What can you do in Ruby? You can accumulate a collection of strings to eval!
shutdown_hooks = ["Logger.write 'normal termination'", "Logger.close", "DatabaseConnector.close"]
Voila! You can iterate through them and execute them, just like any set of pointers in other languages.
To recap:
- eval is merely a tool. It can be used, and abused, like any tool.
- Use eval as necessary, but avoid it if possible.
- Sanitize your input! Don’t risk it! Script kiddies abound!
In other programming languages, one of the concerns raised with reflection is that it’s a “heavy” process. How does Ruby stack up? If you know, share it in the comments!
what about Procs
I’m still very confused about procs. :)