Metaprogramming in Ruby
in Code Code, Ruby, Metaprogramming
Recently, I developed a configuration DSL that would populate a database. I found myself writing a lot of repetitive code to handle the DSL syntax, and thought that this would be a good case to programatically generate the methods.
The basic syntax was of the form:
|
|
One of the requirements was to throw an error if the wrong type of argument was passed as a parameter. The initial approach was to add conditions to check for the type and range, but I found this to be extremely repetitive. Enter metaprogramming. This allowed me to generate a base function template, and automatically generate the code for that function based on some parameters. The C language has a very similar feature, where I’d define a repetitive block as a macro and call that macro multiple times with different parameters.
|
|
Obviously, the above snippet is a contrived example, but it serves to give you an idea of how to do something like this in C (the backslashes serve to continue the macro definition).
Ruby has the fantastic define_method
. With it, I could do exactly what I had
done in the C instance.
|
|
The accept_class and accept_range parameters serve to define the accepted type
and range of values that can be set in the DSL. The only limitation is that
since Ruby doesn’t have an explicit class for Boolean data types, we are limited
to verifying that the user entered true
or false
, by checking the range.
Certainly, this was a limited example, and it does hamper performance slightly due to the multiple checks, but it serves to demonstrate how you can follow the DRY principle and make a lot of code that is mostly common but differs in subtle ways.