Perhaps the most powerful tool in the metaprogrammer's toolkit is the capability to create brand-new methods at runtime that are indistinguishable from the methods defined when the module is loaded.
Because method declarations are just another kind of command inside a Ruby script, they can actually be placed inside conditionals and invoked based on other program logic. Another programming language might force you to do something like this:
def error_messages if ENV["RAILS_ENV"] == "development" p "A very verbose error message" else p "A terse message" end end
But in Ruby, you can do this:
if ENV["RAILS_ENV"] == "development" def error_messages p "A very verbose error message" end else def error_messages p "A terse message" end end
The second code snippet example (the Ruby one) actually changes which version of the error_messages method is defined. The advantage of this is that it performs the conditional test once and only once, whereas the traditional version performs the conditional test every time the method is called. The downside is of the dynamic version is that it looks weird, and will take most programmers some extra time to figure out.
Ruby allows you to create methods with the module-level method define_method, which takes a symbol and a block as arguments.
There isn't anything you can do with define_method that can't be done another way. In particular, define_method is basically syntactic sugar for class_eval. As an example, take a ...