Metaprogramming is a programming technique in which programs have the ability to treat other programs as their data. It means that a program can be designed to read, generate, analyze or transform other programs, and even modify itself while running.
With this in mind, I am going to introduce you to the main methods and tools that Ruby offers us to focus on metaprogramming.
Possibly the method most related to metaprogramming that Ruby offers is the ability to run a method with a symbol or string:
First, let's set a problem that can be optimized with the send method:
In this case, given that for each status we have totally different actions, we find ourselves in need of establishing a case statement to handle each possibility. In this example, we only have four cases, but in any program that we are developing, we might need to have many more cases where it would be very complicated.
There is where send comes into play. Let's refactor that code using the send method:
This way we can reduce a huge amount of lines of code, making it much easier to understand. This also leads us to a possible problem, which is that if for some reason the status of the product can be manipulated, we could call send with a method that does not exist. That is where method_missing comes into play.
This method is executed by Ruby automatically when we call a method that does not exist or has not been defined:
Continuing with our example, suppose we have a new product with an unknown status for our system --- let's say 'in_review' --- that would throw the following error:
A possible solution to this case is to define `method_missing` in our class and let the user know that the system does not know how to act with this status in this way:
Another way to handle this type of problem is with define_method, which would allow us to define an answer without getting the error of the undefined method. We will explain this in the next section, the define_method.
The define_method is used to create methods at runtime.
Using this method, we can define a method and generate the response we want before falling into an error generated by Ruby, which we can see in this example:
This gives us infinite possibilities to manage our data in our application creating methods in the moments that we need them following some pattern that we define for our application.
This is more like an extra bonus. Something curious about Ruby is that each object has its own metaclass. In this example, we are going to manipulate them:
This is called a singleton method and essentially the only difference with a class method is that it only affects the instantiated object that we apply it to, and this is another way to write it:
Knowing these methods and techniques that Ruby offers us, we can greatly expand the range of possibilities when developing our applications. Applying this technique, we will usually be able to significantly reduce the amount of code we need to reach the same results or better.
You can learn more about our custom software development capabilities by navigating through our site and blog. Also, if you are interested in this topic, you may be a good fit for the FullStack Labs family. Why don't you take a look at the opportunities we have available here?
We’d love to learn more about your project.
Engagements start at $75,000.