3 killer features that are coming in Ruby 2.0

Nov 05, 2012
72d86bb5aaaa1720ede338f4ad613344

Ruby 2.0 will be released on 2/24/2013, exactly 20 years after development on it began.

Akira Matsuda during his excellent talk at Rubyconf, brought to my attention 3 very interesting features that will make it more elegant than it already is, specially for Ruby on Rails applications.

Refinements

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.

Enter Refinements.

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.

Module#prepend

Consider the following example:

The way the current hierarchy works is in the following order:

  1. Implementing Class
  2. Module
  3. 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.

Enter Module#prepend.

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.

Lazy Enumerables

Currently, when you chain different operations on an Enumerable, like map, select and 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.

Warning

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.

Happy coding!

blog comments powered byDisqus