Concept: Metaprogramming is writing programs that write programs! Sounds awesome right? Let's understand why metaprogramming is important. Take a look at the following code:
class Cryptocurrency
attr_accessor :name, :symbol, :current_price, :last_updated, :price_change_24h
def initialize(name:, symbol:, current_price:, last_updated:, price_change_24h:)
@name = name
@symbol = symbol
@current_price = current_price
@last_updated = last_updated
@price_change_24h = price_change_24h
end
end
In this situation I have a Cryptocurrency class that initializes with a hash of attributes from CoinGecko's API and it works just fine. But what if they decide to change its API, we wouldn't be able to even create Cryptocurrency objects and our app will crash.
Luckily there's a solution for this problem, but first let's take a look at the send
method. We can use it and simplify our code above with less code.
class Cryptocurrency
attr_accessor :name, :symbol, :current_price, :last_updated, :price_change_24h
def initialize(crypto_hash)
crypto_hash.each do |key, value|
self.send("#{key}=", value)
end
end
end
What is going on here?
self.send("#{key}=", value)
As we loop through each key value pair in our hash we use “message passing” to “send” a method to “self”.
How send
method would look a like:
self.name = value
self.name = "Bitcoin"
Now that we understand send
, we can get into dynamically setting getters and setters. Let's first remember that attr_accessor
is a class method just like attr_reader
and attr_writer
. So we can dynamically add getters or setters:
class Cryptocurrency
def initialize(hash)
crypto_hash.each do |key, value|
self.class.attr_accessor(key)
self.send("#{key}=", value)
end
end
end
By using Metaprogramming we can now get and set every attribute on an object instantiated from the Cryptocurrency class.
Reference:
Mass Assignment and Class Initialization
Top comments (0)