The Ruby Facets Series
A couple of years ago I was working on a legacy enterprise Java project where the customers were obsessed with the production environment. They didn’t allow my team to deploy new versions of the apps we were developing. The most interesting thing was they didn’t allow us to work on the databases. I mean stuff like backups, performances tuning and so on.
One fine day their system administrators had a very great idea. They decided to physically move the databases to another machine without changing the IP addresses. Of course, they didn’t tell us because they were sure the applications wouldn’t have noticed anything. But you know: In theory, there is no difference between theory and practice. But, in practice, there is. Indeed, for a reason I ignore even today when they restored the databases, the NULL fields of all the tables were set to empty string. Nice.
Oddly enough, they called us complaining about our applications. How come our applications stopped working? Yes, I would have killed them but they created an interesting problem. We needed a script to restore to NULL all the empty strings on the databases. Of course, they were still paranoid about theproduction environment, so they asked for an SQL script they could inspect before running it.
Here enters Ruby. I needed a quick and dirty script to find all the empty strings on the databases. I wrote the script in a hurry and I was really missing a feature from my Perl days. I was thinking to save all the empty strings in a multi-level hash with the table name, field name, and other stuff that I don’t remember now. Well, the missing feature was autovivification. Now, generally speaking, I don’t miss it at all but, in that difficult situation, I couldn’t spend much time looking for a Ruby way. So I searched for a library that would have given me that feature. Here comes Ruby Facets.
I finally found this fantastic library that gave me the following feature:
It’s nice, isn’t it?
Now, I wanted to share with you this story because it gave me the opportunity to pave the way for a couple of considerations. It’s a little amount of code for a relatively simple problem, and I could have even written my script for empty strings using another technique. But:
- Why do I have to re-invent the wheel?
- Why should I miss the opportunity to read good code?
These two questions are enough to convince myself to dig into this library. The moment I met it, I was in love. If you add a long list of very respected contributors, the recipe for curiosity is done :)
Having explained the reasons behind my series of articles about the Ruby Facets, I can actually introduce the library itself. As you can read in the README, Ruby Facets is the premiere collection of general purpose method extensions and standard additions for the Ruby programming language. The collection of methods and general additions is quite large. Furthermore, it is divided in two different parts. There is a core part that provides a large number of extension for Ruby classes and modules like Array, Hash, Kernel etc. Then, there is a standard part that provides additional modules and classes.
One of the good aspects of the library is how you can require a feature. The facets library follows a very simple and intuitive pattern.
The latest example is the most useful, as it gives you the chance to get only what you really want. In general, each require of this type gives you just an extension but there are some reasonable exceptions like facets/array/before. This require pattern is great for libraries that extend existing classes, indeed, ActiveSupport follows more or less the same pattern for its core extensions.
Of course, the library is packaged as a gem, so the installation is a very straightforward process. You could start playing with it in just a second. Now, I want to show you a little trick I use to get familiar with libraries that add extensions to Ruby classes. The following will work only with Ruby 1.9.x as it uses the source_location method. The aforementioned method, citing the official documentation, returns the Ruby source filename and line number containing this method or nil if this method was not defined in Ruby. Such an awesome method! Take a look at the following examples to see how it works:
It works nicely and gives you the opportunity to do the following:
It may not be the best-looking method, but it works well for its purpose. I decided to reopen the
Class class because I wanted a simple way to query classes about the Ruby Facets library. I don’t reopen
Class ordinariliy, but it’s pretty awesome that I can do it at all!
facets_ext method works in the following way:
- gets all the instance methods of the receiver class
- map the array to an array of arrays with the symbol and the method location
- select only the ones related to the facets
- map only the symbols and sort them
The points 2 and 3 remind me of the schwartzian transform in some way. As you can see the method is not magic, it just gives us a quick way of exploring the library from the console:
I joined the lines to make the article more readable. So fun! In this way, you can explore the library from the console. Just paste the method
facets_ext in your .irbrc (or in your .pryrc if you, like me, use pry).
In the next articles I’m going to focus on the core extensions first, trying to be as comprehensive as possible. Some parts are going to be really exciting. By the way, if you have any suggestions about what I should focus on, they are more than welcome.