Tuesday, December 28, 2010

Harness the Power of an Object's Singleton Class

There are a few blog's discussing what the Singleton Class is in ruby.  For a pretty good explanation see this one.  However, I always like to discuss a practical example that demonstrates how you might use it to improve your code when the opportunity comes up like yesterday.

I was writing a small script to produce some reports on log files that were all text files with some having been zipped and others not depending on their current status.  For the zipped files I wanted to be able to open the files and examine their contents just like the existing files that weren't zipped.  An example glob would be:

=> ["2010-09-13.access.log", "2010-09-14.access.log", "2010-09-15.access.log", "2010-09-16.access.log.gz"]

The main focus of the script should be to examine the files in a directory and then loop through each line of the file. The gist below gets us started:


This feels like a clunky way to solve the problem.  Because a gzip file is temporarily opened, the name of the file is changed.  The second part of the problem requires us to keep track of whether to gzip the file when we are done or not.  We have created 2 separate variables (gzip and use_file) that we have to maintain now to handle the logic.

Since the reference to the file in this case is just a String, we could monkey patch it and add methods that would help us clean up the code in the previous gist.  This would be an improvement for sure but a better way to solve the problem would be to create a mixin to encapsulate the necessary logic and then create a singleton class like so:


Using this technique we have cleaned up the block focusing on the file looping considerably.  We have also created a more extensible solution should we encounter other files types in the future.  This method also avoids the problematic alternative solution of opening up a Ruby standard class (in this case String) to achieve the same result.

This is just another example of how flexible Ruby is compared to other languages so embrace the fact you can create a Singleton class and harness its power.