Send — Underrated Spell for Metaprogramming
We have always heard about metaprogramming in Ruby, but how we can implement it in our codes is something different. In the previous article, we went through two methods class_eval and instance_eval, which are some ways to implement the metaprogramming in our code. There are many more ways to implement metaprogramming but the Ruby has provided some easier ways to implement it. They are through using methods such as — send, method_missing, and define_method. Let us have a look at them.
Send — The caller method
The send method is used to invoke the other methods by passing its name as an argument, and other arguments as follows. Now, a question may arise if we can simply call any method on the object just with the ‘.’ then why need to invoke this through send? Let's see the syntax then we will have the answer for this question.
class Laptop
def which_brand(brand)
puts "#{brand}"
end
end
laptop = Laptop.new
laptop.send(:which_brand, "Macbook")
#Macbook
So, why need a send method if we can simply call any method of the object? Now, we are making a class for the Order which has a different method for their status. Another class UserOrder will initialize Order for the user with the status.
class Order
def initialize(status)
@status = status
end
def out_of_delivery
puts "Out of Delivery"
end
def in_transition
puts "In Transition"
end
def delivered
puts "Delivered"
end
def approved
puts "approved"
end
def status
@status
end
end
class UserOrder
def initialize(order)
@order = order
@status = @order.status
end
def order_status
if @status == "out_of_delivery"
@order.out_of_delivery
elsif @status == "in_transition"
@order.in_transition
elsif @status == "delivered"
@order.delivered
elsif @status == "approved"
@order.approved
end
end
end
UserOrder.new(Order.new("out_of_delivery")).order_status
#Out of Delivery
This is a simple example where the User Order status is displayed. Now have a look at changing it with the send method and try this again.
class UserOrder
def initialize(order)
@order = order
@status = @order.status
end
def order_status
@order.send(@status)
end
end
UserOrder.new(Order.new("in_transition")).order_status
#In Transition
Wow, we had changed the whole need for the if-else loop in the order_status method.
To be continued
We had given priority to the send method as it has been always underrated in writing the codes. Suppose many times in our code we require the worker to perform a certain job but with different models and the same set of attributes. We would go for the send method such that it will be DRY( Don’t Repeat Yourself), which means you have the same worker for both jobs. The send method is more magical than it seems. We will continue with method_missing and define_method in the upcoming stories.