Metaprogramming-Ruby (Basic)
So basically, Metaprogramming is always an exaggerated topic for everyone. But what’s the fact is that it's been as simple as the Class-Object concept. In this story, I will be covering the basics of metaprogramming and how it works in the ruby.
What is Metaprogramming ?
Metaprogramming usually refers to the programming concept where we write programs that write the programs of their own when needed. Thus, metaprogramming is nothing but an automation of the program itself to rewrite a new program when required.
For example, when we create a method that can handle any number of arguments, it is metaprogramming as it adjusts itself for the number of arguments we provide. Thus, we similarly allow our program to automatically write more programs when we require some new task to be done and back to its original state.
Ruby Class Object Concept -
When we are familiar with Ruby’s class object concept it might be very easy to understand metaprogramming in Ruby. From the above diagram, it's quite clear that the BasicObject is the foremost class and all the classes inherit it.
class Book
def self.class_name
"I am Book Class"
end
def price
"Price $10"
end
end
p Book.class # Class
p Class.superclass # Module
p Module.superclass # Object
p Object.superclass # BasicObject
In this example, we have a Book class that has one class method(Only available to the class, not their objects)and one instance method(Available to all instance objects of the class). This example shows all the classes are related to BasicObject.
Finding Metaclasses in Ruby
In ruby, there are certain hidden classes for every object and class through which the whole concept of metaprogramming can be understood, these are the meta classes. When we create a class method or a singleton method(Method only available for the Specific Object), they just get attached to their hidden metaclass.
test = "I'm learning"
def test.something
self.upcase
end
p test.something
# I'M LEARNING
class Object
def metaclass_example
class << self
self
end
end
end
class Book
def price
p "instance method, self is: " + self.to_s
end
class << self
def class_name
p "class method, self is: " + self.to_s
end
end
end
book = Book.new
book.price
# "instance method, self is: #<Book:12z1ce4>"
Book.class_name
# "class method, self is: Book"
p "metaclass : self" + book.metaclass_example.to_s
# "metaclass : self #<Class:#<Book: 67gh672x>>"
In this example, we have added an instance method in the Object class of Ruby, which is the superclass of any Class created(here’s Book). In the Object instance method, we first referred to the self(Object) then we had to refer to the metaclass between the child classes(like Book). Thus, that’s wow means we have a class(<Class:#<Book: 67gh672x>>) between the Book and Object(superclass of the book). Let’s see one more magic :
p book.class.instance_methods false
# [:frontend]
p book.class.metaclass_example.instance_methods false
# [:backend]
p book.class.singleton_class.instance_methods false
# [:backend]
But, we can also use the singleton_class that Ruby has provided to get the hidden metaclass. More details are provided in this article.
To be continued
We will be learning more about the use of metaprogramming tools like send, define_method, method_missing, class_eval, etc. But if we had understood these simple logics it will be easier for us to better utilize these metaprogramming tools.