Define Methods Dynamically in Ruby
In Ruby, it's common to see new methods defined dynamically or on the fly for your class. And who doesn't want to have a piece of that metaprogramming?
An Example
For example, I just finished an exercism code exercise where I felt like there was a fair bit of code duplication. I had a bunch of convenience functions that would show the conversion of a time in earth time to a time specific to a planet. So, the API required something that looked something like this:
class SpaceAge
def on_earth
seconds_on_planet :earth
end
def on_mercury
seconds_on_planet :mercury
end
def on_venus
seconds_on_planet :venus
end
# ...
end
Feeling that this might be an excessive number of similarly pattern methods, I considered ways that the API might stay in tact but the effort of maintenance of these many functions might be decreased.
define_method
We could collapse these methods quite a bit in the visual code by defining them dynamically, using define_method
:
class SpaceAge
def self.on_planets(*planets)
planets.each do |planet|
define_method "on_#{planet}" do
seconds_on_planet planet
end
end
end
on_planets :earth, :mercury, :venus, :mars, :jupiter, :saturn, :uranus, :neptune
end
The exact same code would be generated. It's better! But it's worse! It's actually less readable than before. on_planets
as a new helper API might be nice. But, we're not currently using this anywhere else. The code is probably more maintainable, but it's also more stiff. Previously, each of the methods was separate and therefore separately modifiable and customizable. Now, there's one implementation of an "on_#{planet}" method. This could be easier/harder to deal with, depending. I think the readability is better because of the smaller amount of code, but the readability is worse because of the increased complexity and eye parsing required. In the end, for my code, I stayed with the original solution for its 5-star readability.
But the ability to define methods dynamically is super awesome. When do you find yourself using this super power?