This seems to be a popular interview question. It indeed requires advanced knowledge of ruby.
You have a class with a class method. Write a module that, when included, will override that class method.
Explanation of the problem
Now classic way of mixing in class methods is this (and it doesn’t solve the problem, of course).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
|
When modules are included or extended into a class, its methods are placed right above this class’ methods in inheritance chain. This means that if we were to call super
in that class method, it would print “module”. But we don’t want to touch original class definition, we want to alter it from outside.
So, can we do something?
Good for us, ruby has a concept of “open classes”. This means that we can change virtually everything in the app, even some 3rd-party libraries. Every class can be “opened” and new methods can be added to it, or old methods can be redefined. Let’s look how it works.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
The second class definition does not overwrite previous one, it opens and alters it. In this case, it happened to define a method with the same name. This resulted in old method being overwritten by the new one. This works with any classes, even base library classes.
1 2 3 4 5 6 7 8 9 |
|
Or the same code can be rewritten as
1 2 3 4 5 6 7 8 9 |
|
Applying the knowledge
Let’s start with simpler things, like overriding an instance method.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
|
Modules have a special callback that gets called every time a module is included in a class. We can use that to call class_eval on that class and redefine a method.
Replacing a class method is done in a similar way.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
|
The only difference here is that we call instance_eval instead of class_eval. This can be a very confusing part. In short, class_eval creates instance methods and instance_eval creates class methods.