Nov 05, 2012
Ruby 2.0 will be released on 2/24/2013, exactly 20 years after development on it began.
Refinements are, for a lack of a better explanation, scoped monkey patches.
Let's say that, for some imaginary reason, you want to make any String append a series of periods to all of its instances when calling to_s.
One way to do it, would be to monkey patch the String class, and just append the desired text by overriding its to_s method:
The problem with this solution is that, even though it works as intended, you changed the behavior on ALL the strings in your application.
By wrapping this behavior change in a module, and using the
refine keyword, we can be more specific on where we want this behavior to take place:
What happened here is that, only within the scope where we specified that we wanted to use the MonkeyPatch refinement for String with the
using keyword the strings are affected. Sweet! No more unexpected behavior modification.
Consider the following example:
The way the current hierarchy works is in the following order:
- Implementing Class
- Parent Class
But, what happens when you want to include a module where you want to alter the behavior of the method before its local implementation?
Rails introduced the hackey and unsafe
alias_method_chain solution by using multiple alias for the method. But, well, like I said, its hackey and unsafe.
When you use Module#prepend, the method definition in the module that you are prepending takes precedence over all the other definitions:
As you can see in the result, the code in the module is executed first. So now, you can wrap around methods with modules in a safe, clean way.
Currently, when you chain different operations on an Enumerable, like
take, ruby executes a loop on all the elements in order. For example:
Here, Ruby will go through all the elements in the range and take only those that are pair numbers, then, go through all the pair numbers and add 1 to all of them, and then, end up just taking the first 10 numbers in the array.
On my computer, this took 2.72 seconds.
Now, lets use the lazy enumerables and see what happens:
In this case, we call lazy on the original array, which it is now converted into an instance of
Enumerator::Lazy, then, we chain our operations like we normally would, but they won't be executed until you call
force on the Enumerator.
And check out the speed improvement. It is significant, it might actually make you consider using Ruby instead of SQL in some cases to filter out data.
Its also very similar to how
ActiveRecord::Relation where you can chain AREL statements and they will not be executed until you call
.all on it.
Everything here may look awesome, but, Akira did warn us that there's still time betwen now and the official Ruby 2.0 release next year. Any of these features can still be removed by then.
On the other side, you should start making sure today that your apps work with Ruby 2.0 so you don't suffer in the future. Rails ~> 3.2.8 is supposed to be 100% compatible with Ruby 2.0, if you get a chance, test your current apps with it and report any bugs that you may find.