Oh god the book is gonna make me do metaprogramming. Here is what I currently believe metaprogramming is: Programming about programming. So I am thinking of things like terraform, code that builds code. The book defines it as writing programs that write programs. That's what I was meant, swear it.
Metaprogramming
Rails has a framework called ActiveRecord which uses Metaprogramming to build classes that link to database tables.
class Department < ActiveRecord::Base
has_many :employees
has_one :manager
end
has_many
and has_one
are Ruby methods that add all the instance variables and methods needed to establish the respective relationships.
Open Classes
The first invocation of class
defines a class, once a class is already defined, subsequent invocations modify that class. This can be shown in the following example:
class NilClass
def blank?
true
end
end
class String
def blank?
self.size == 0
end
end
["", "person", nil].each do |element|
puts element unless element.blank?
end
Ruby's open classes allow direct modification of /any/ class, which is a very big shotgun aimed directly at your feet. In this case, it means we can call our each method with the do block and no matter what the element type is, we can call blank?
because we added that method to the possible types in the array. Open classes allow for hype-specific modifications to fit business demands.
method_missing
This language is nuts. Because of open classes and the ability to overwrite anything, you can use the method_missing
method which is called when a piece of code tries to invoke a method that doesn't exist.
method_missing
takes in the name of the attempted class, and its arguments as parameters. You can override the logic of method_missing
to create a sort of "catch-all" method.
class Roman
def self.method_missing name, *args
roman = name.to_s
roman.gsub!("IV", "IIII")
roman.gsub!("IX", "VIIII")
roman.gsub!("XL", "XXXX")
roman.gsub!("XC", "LXXXX")
(roman.count("I") +
roman.count("V") * 5 +
roman.count("X") * 10 +
roman.count("L") * 50 +
roman.count("C") * 100)
end
end
puts Roman.X
puts Roman.XC
puts Roman.XII
puts Roman.X
# 10 -> 90 -> 12 -> 10
It is difficult to find a use for this that outweighs losing out on the method_missing
functionality, and it is a bit hacky and I can see this being a thorn in a production codebase, but it is cool and fun nonetheless.