Ruby on Rails, or simply Ruby, is a full-stack web application framework that employs the MVC paradigm to create web pages, web services, and database-driven applications. Data is exchanged between services in the form of JSON and XML. It provides you with the tools that you need to build scalable frontend and backend web apps. Today we are going to discuss one application of Metaprogramming in Ruby when we start to code from scratch there is a lot to code to begin the program and most of it is common among all. To avoid rewriting all these we use Boilerplate code in Ruby Programming.
Conventional Programming and Metaprogramming
In conventional programming, we create programming code that can take in, process, and output data. is static, which means that all of the code stays the same while it is being executed, but the data is dynamic. Most people are familiar with this kind of programming. We create a function that can take in some data and return the desired outcome. However, when using metaprogramming, both the program and how it is executed become dynamic, giving us the ability to create functions that can both process and produce code. Code is essentially treated the same way as data. The wave-particle duality that particles, like electrons, exhibit would be a helpful example of the duality or interchangeability between code and data.
Avoiding Boilerplate Code
Although metaprogramming has a straightforward notion, there are many things we may accomplish with it. Below is a list of a few metaprogramming goals:
Code generation
Code completion
Code reflection
Now, You write a lot of repetitive code that even a trained monkey could write. You're annoyed that you have to complete this task on your own and frustrated that the repetitious code will overcrowd your class listings.
Ruby enjoys serving as the trained monkey who creates your repeated code every time. Using Module #define a method, you can define methods algorithmically.
Usually, the repetitive code is a bunch of similar methods. Suppose you need to write code like this:
class Catcher
def catcher(valof_many)
puts "Fetching #{valof_many ? valof_many : "all"}."
end
def fetching_one
catcher(1)
end
def fetch_ten
catcher(10)
end
def fetch_all
catcher(nil)
end
end
Without having to write it all out, you can specify this exact same code. Make a data structure containing the variations between the methods, and iterate over it, defining a method with define method each time:
class GeneratedCatcher
def catcher(valof_many)
puts "Fetching #{valof_many ? valof_many : "all"}."
end
[["one", 1], ["ten", 10], ["all", nil]].each do |name, number|
define_method(:"catch_#{name}") do
catch(number)
end
end
end
GeneratedFetcher.instance_methods - Object.instance_methods
# => [:fetch_one, :fetch, :fetch_ten, :fetch_all]
GeneratedFetcher.new.catch_one
# Fetching 1.
GeneratedFetcher.new.catch_all
# Fetching all.
This takes up less room in your class listing, is easier to type, and is less monkey-like coding. Instead of writing out an additional boilerplate, you can add to the data structure if you need to create more of these functions.
Writing original code has always been favoured by programmers over producing copies of existing code. We've always utilized tools to produce code since it would be time-consuming to type out manually, from lex and yacc to more recent applications like Hibernate and Cog.
Ruby programmers create code directly from Ruby rather than using an external tool.
There are two methods that have official approval. Using a defined method to construct a method whose implementation can make use of the local variables accessible at the moment it was declared is a more excellent approach. You cannot tell the difference between methods you wrote down by hand and methods whose code you wrote. If you are metaprogramming using string evaluations, as shown in the following example, they will appear in method lists and in generated RDoc documentation even produce the RDoc documentation and include it at the start of the created method
Metaprogramming is used in the built-in decorator methods that we have already examined. A method whose name and implementation are based on a string is defined by the attr_reader method, which accepts a string as an input. All of the code for the reader methods is factored out into attr_reader; you just need to provide the minimal portion that varies each time.
Frequently Asked Questions
What are Ruby lambdas?
A lambda is an object in Ruby that is comparable to a proc. A lambda returns to its calling procedure rather than exiting immediately, and unlike a proc, it needs a particular amount of arguments supplied to it.
What is a singleton class in Ruby?
A creational design pattern called singleton makes sure that there is only one object of its sort and gives all other code a single point of access to it.
Define yield in Ruby?
The Ruby keyword yield enables developers to provide arguments to blocks from the yield; there are no restrictions on the number of arguments that can be passed to a block.
What is meta class in Ruby?
Ruby automatically constructs a class to house just that function when you declare a singleton method on an object.
Why do we use blocks in Ruby?
Blocks, which resemble closures, have been a feature of the Ruby language since its beginning. When used correctly, they can minimize repetition and even make coding less prone to errors.
Conclusion
In this article, we have extensively discussed the Avoiding Boilerplate Code with Metaprogramming in Ruby.
After reading about this blog on Ruby, are you not feeling excited to read/explore more articles on the topic of Ruby? Don't worry; Coding Ninjas has you covered. To learn Ruby see Ruby Documentation, Ruby By Coding Ninjas, Ruby Documentation-Block, Ruby FAQ, andRuby Archives.
Do upvote our blogs if you find them helpful and engaging!