This is worth bearing. I don't have a problem with eval, only with string
eval. Given that:
For the eval line, I first tried explains.define_method, and it didn't work.
According to Philip, define_method is a private method, so you can't do that
from outside that object.
Assuming "explains" is a class or a module, you could always go inside the
object:
explains.module_eval do
define_method :foo ...
# More methods?
define_method :bar ...
end
See, I love those, because they can actually take blocks, not just strings.
Since I'd mostly just be passing a variable in through string interpolation,
anyway, it's not only faster, it's safer -- SQL injection is enough of a
problem, we don't need Ruby injection, too!
If it's only a one-off, and you find that eval to be too verbose, there's
always the send hack:
explains.send :define_method, ...
This works mostly because send doesn't check for whether a given method is
actually reachable at that point -- I think you need public_send for that.
Obviously, send is useful for more than just that...
The main legitimate solution I've found is cases like ActiveSupport's
String#constantize -- this is a case where it would take quite a lot more
Ruby to accomplish the same thing as a simple eval. And even here, it's
surrounded by sanity checks, and it's isolated, so that you never have to
know it's there (I didn't, till I looked at the source of constantize out of
curiosity).
And there's always the performance -- I consider evals to be acceptable when
run once, during program start (or at some arbitrary point after that). It's
still code smell, but constantize is an example where the alternative might
be worse. But I'd never call constantize in a Rails view.