Ruby Pills: Dynamic Method Inclusion
Ruby Metaprogramming
Ruby is an amazing programming language in many aspects, especially regarding metaprogramming! The fact that everything is an object, give to the programmer the ability to manipulate methods and closures, the inheritance chain classes, callbacks, have modules with common code, and a lot of other nice things!
In this Ruby Pill, I’ll cover 3 module callbacks (included
, extended
and method_added
), to dynamically add methods to a class.
Some Module Callbacks
Let’s take a module with the 3 callbacks that we’ll use:
module Example
def self.included(base); end
def self.extended(base); end
def self.method_added(method_name); end
end
Despite the descriptive names, follows a summary of each method:
- included(base): executed after you include the module. If you add some method here, it will be an instance method of your class.
-
extended(base): executed after you extend the module. If you add some method here, it will be a class method of your class.
In both cases, base refers to the class where you include/extend the module.
- method_added(method_name): Here you can put the code to be executed after you’ve been added a method in your class.
Adding Methods Dynamically
Here is our module with its callbacks and implementations:
module Example
def self.included(base)
add_new_method(base)
end
def self.extended(base)
add_new_method(base)
end
def self.method_added(method_name)
puts "Adding #{method_name.inspect}"
end
private
def self.add_new_method(base)
base_name = base.name
define_method("#{base_name.downcase}_new_method") do |value|
"Method added in #{base_name} class => Value passed: #{value}"
end
end
end
The magic is inside our add_new_method
private method. It’s called inside included
and extended
callbacks, passing the base
variable, that is our class. Using define_method
method, we add a new method called <CLASS_NAME>_new_method
.
To see them in action, we could use it like this:
class Wow
include Example
end
puts Wow.new.wow_new_method(:wow)
# => Adding :wow_new_method
# => Method added in Wow class => Value passed: :wow
class Cool
extend Example
end
puts Cool.cool_new_method(:cool)
# => Adding :cool_new_method
# => Method added in Cool class => Value passed: :cool
Cool! Besides add new instance/class methods to our classes, we can see the message of the method_added
callback after each one is added!
Final Thoughts
This only scratches some of Ruby capabilities! There’s a world of possibilities, methods, and callbacks to use if you want to take a deep dive on Ruby metaprogramming!
One thing that you should be aware of is that how much more you use this kind of Ruby features, your code can become too slow, so be careful!
Did you already know about these module callbacks?
Let me know if you liked this post! If you have any suggestions or critics, post a comment below!