RUBY

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.

1.  define_method

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.

2. Class.new

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.

Ever wondered why you call Person.new but define Person.initialize? It’s pretty simple. Here:

Obviously! This is the source for Person.new. You might not read C, but it’s pretty simple: it first allocates the space for the object using rb_obj_alloc, and then calls initialize using rb_obj_call_init.

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.

4. const_missing

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.

5. binding

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. Infact 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.

Conclusion

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.

Ikem Okonkwo

About Ikem Okonkwo

Ruby Evangelist, .NET Advocate. Trainer at @andela. Passionate about education and lifelong learning. Loves good food and soccer.