Ruby on Steroids: The Magic of MetaProgramming — Fellowship of Spells
In part 1 of this journey, you were introduced to anatomy of magic(metaprogramming) and you saw some of the spells you can cast with the magic of metaprogramming. In this post, I will be showing you other forms of spells you can cast.
Fellowship of Spells
For us to become better magicians, we need to learn more spells. Let’s see how far we can go in the fellowship of spells.
define_method is used to define a method dynamically at runtime. In part 1 of this series, we saw how we can define methods dynamically using eval, class_eval or instance eval. The major problem with defining your method with this means is that it is prone to errors since your methods are defined using strings. A good time to use `define_method` against using explicitly defined methods is in a situation where you have to create a series of methods all of which have the same basic structure.
We all know that everything in ruby is an object, even classes. Ruby class is an instance of Class. That means every time we are defining a new class, we are basically calling Class.new behind the scene. Let’s see how this works.
Creating a class this way is a syntactic sugar for creating it this other way.
3. const_get & const_set
const_get is used to retrieve a constant with same name as the string or symbol passed as the argument to the `const_get` method. It can be used to load ruby classes from strings. It is the method behind ActiveSupport constantize method. const_set on the other hand can be used to create new constants or to update existing constants.
As you can see in the last example above, we can do a lot of neat things by combining const_set and Class.new. We can dynamically create different classes at runtime.
We just saw how we can get a constant dynamically using const_get. However what happens if we try to get a constant that do not exist? Well, const_missing method is called as a method of last resort, which by default throws a NameError. We can override this `const_missing` method with our own implementation.
Instances of the Binding class (binding objects) capture the environment bindings (variables, methods, and self) at any point of a Ruby program, so the bindings can be reused later, when the scope has changed. It is this binding objects that powers binding.pry. In fact pry gem just adds a pry method to the binding object. Let’s see how binding works.
Basically binding.pry effectively opens up a pry session with the current binding object. Check out this link for a deeper understanding of `binding` and/or `binding.pry`.
We often hear that a journey of a thousand miles starts with a step. That is also true in the world of magic. You are already making those steps and before long, you will become a full fledged magician. Till the next time we journey together, keep your finger crossed and practice your new spells.
Remember, without practice, you cannot become a master magician.