Table of contents
1.
Introduction
2.
Conventional Programming and Metaprogramming
3.
Metaprogramming
4.
Metaprogramming with String Evaluations in Ruby
5.
Frequently Asked Questions
5.1.
What are Ruby lambdas?
5.2.
What is a singleton class in Ruby?
5.3.
Define yield in Ruby?
5.4.
What is meta class in Ruby?
5.5.
Why do we use blocks in Ruby?
6.
Conclusion
Last Updated: Mar 27, 2024

Metaprogramming with String Evaluations in Ruby

Author ANKIT MISHRA
0 upvote
Career growth poll
Do you think IIT Guwahati certified course can help you in your career?

Introduction

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 the tools you need to build scalable frontend and backend web apps. We will learn about these features in this tutorial, including rendering HTML templates, CRUD operations in databases, e-mails, live pages, WebSockets, task scheduling, and excellent online security.

Conventional Programming and Metaprogramming

In conventional programming, we create programming code that can take in, process, and output data. The program itself 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 to take in some data and return the desired outcome. However, when using metaprogramming, both the program and how it is executed become dynamic, allowing us 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, the exhibit would be a helpful example of the duality or interchangeability between code and data. 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; most of it is common. To avoid rewriting all these, we use Boilerplate code in Ruby Programming.

Metaprogramming

The word "metaprogramming" is much disputed. The terminological development is illustrated by the following definitions of metaprogramming: - "code that writes code,"  or "programs that write programs," or "the design of new abstractions integrated into the host language." 

But a problem arises in Ruby while using it in Ruby. This blog is to discuss and approach a suitable solution for it.

Metaprogramming with String Evaluations in Ruby

You are hoping to use define_method to create some metaprogramming code, but there is too much reflection occurring for your code to be understandable. It becomes difficult and nearly as annoying as having to write the code by hand. Now, the problem is, How should we tackle this issue to make this process easy.

By creating the definitions as strings and executing them as Ruby code using one of the eval methods, you can define new methods.

Here's an updated version of the define_method based metaprogramming code:

class Numeric
[['add', '+'], ['subtract', '-'],
['multiply', '*',], ['divide', '/']].each do |method, operator|
define_method("#{method}_2") do
method(operator).call(2)
end
end
end


The critical line of code, method(operator).call(2), isn't something you'd write

in everyday programming. You'd write something like this, self + 2 or smething like self / 2,

 depending upon the operator you would like to apply. By writing your method definitions as an strings, you can do metaprogramming that looks more like regular

programming:

class Numeric
[['add', '+'], ['subtract', '-'],
11.11 Metaprogramming with String Evaluations | 413
['multiply', '*',], ['divide', '/']].each do |method, operator|
module_eval %{ def #{method}_2
self.#{operator}(2)
end }
end
end
4.add_2 # => 6
10.divide_2 # => 5


With define_method, you can perform all of your metaprogramming, but the resulting code differs significantly from what you would typically write when programming normally. @foo=4 cannot set an instance variable; instead, instance_variable_set must be used (foo, 4).

As an alternative, a method definition can be created as a string and run as Ruby code. Although most interpreted languages contain a mechanism for parsing and running raw strings as code, this capability is typically overlooked or considered a risk. Ruby disproves this perception.

Module#module eval is the most used evaluation technique for metaprogramming. In a class or module context, this function runs a string as Ruby code. As if you had typed the string into the class or module declaration, any methods or class variables you declare within the string will be associated with the class or module. The resulting string resembles hand-typed code perfectly because of the variable substitutions.

The new function String#last is defined by the next four lines of code together.

class String
def last(n)
self[-n, n]
end
end
"Here's a string.".last(7) # => "string."
class String
define_method('last') do |n|
self[-n, n]
end
end
"Here's a string.".last(7) # => "string."
class String
module_eval %{def last(n)
self[-n, n]
end}
end
"Here's a string.".last(7) # => "string."
String.module_eval %{def last(n)
self[-n, n]
end}
"Here's a string.".last(7) # => "string."


Comparatively less people use the instance eval method than module eval. It functions exactly like module_eval, but it executes within a class instance rather than the class itself. It can be used to set instance variables or define singleton methods on a specific object.

Of course, calling define_method on a particular object is also an option.

The other evaluation strategy is a straightforward evaluation. This method executes a string in the same place as if you had written it as Ruby code:

class String
eval %{def last(n)
self[-n, n]
end}
end
"Here's a string.".last(7)


Use the eval methods with extreme caution to avoid being misled into running arbitrary Ruby code by a program's end-user. The only strings evaluated during metaprogramming, however, are ones you created yourself from hardcoded data. By the time your class is loaded and available to use, the eval calls have already been executed. Unless your eval statement uses strings from unreliable sources, you should be okay. This might occur if you're developing a custom class or changing an existing class in response to user input.

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. They can minimize repetition and even make coding less prone to errors when used correctly.

Conclusion

In this article, we have extensively discussed Metaprogramming with String Evaluations in ruby.
 

Recommended problems -

After reading about this blog, 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 DocumentationRuby By Coding NinjasRuby Documentation-BlockRuby FAQ, and  Ruby Archives.

Do upvote our blogs if you find them helpful and engaging!

Happy Learning!

Live masterclass