Ruby doesn’t have procedural module akin to Python or Perl module. Usually, one uses class methods as a typical way to mimic this functionality.Class methods in Ruby are also very handy for supporting instance methods with fabrics and other common-for-class functionality. This is clearly seen in ActiveRecord::Base with dozens of supportive class methods (e.g. #find, #create, #where).There are two standard approaches for defining class method in Ruby. The first one is the “def self.method” (let’s call it Style #1), and the second one is the “class << self” (let’s call it Style #2). Both of them have pros and cons. So, let’s take a look at them and try to decide which style is better and why.
Here is “def self.method” style:
# Style #1
class User < ActiveRecord::Base
And the same example for “class << self” style:
# Style #2
class User < ActiveRecord::Base
class << self
Pros of “def self.method” style
1. It’s shorter and easier to add one method
It’s obvious, that Style #1 is two lines shorter due to the “class << self; end” part. This difference is noticeable for one/two methods. Also, it’s easier to add first class method because you don’t have to type “class << self” wrapper.
2. More simple for newbies
Usually Style #2 looks more exotic than Style #1; and, at first, the “class << self” part looks a little bit awkward.
Pros of “class << self” style
1. Class and instance methods are separated
Glancing over class definition, in Style #1 it’s hard to say, whether it’s a class or instance method. You need to focus on name part. On the other side, in Style #2 indentation and “class << self” wrapper clearly says who is who.Another benefit of Style #2 – it’s easy to see amount of class and instance methods. They are not intermixed. Without clear separation it’s harder to work with class – you need to go over mix of methods and look for the required method.Of course, you can take convention, for grouping class methods in one place, but it’s another rule, which should be followed by all, and it’s so easy to violate it occasionally. With Style #2 is much harder to accidentally create another “class << self” scope.
2. Easier to add batch of methods
What I especially appreciate in Style #2 – it’s easiness of adding new class methods. While Writing a new method, you shouldn’t be focused on adding “self.”-part in name. Class and instance method definition have the same syntax.When I started my way in Ruby, it frustrated me a lot when I added class method and it didn’t work. And only then I realised that I actually forgot to add “self.”-prefix.I strongly believe that a programmer should focus more on what he does and less on various language quirks. And after I switched to Style #2, these kinds of errors just disappeared from everyday coding.
3. Simpler search of method definition
“grep”-ing for some method is simpler to always search by “def name” combination. Style #1 also requires search by “def self.name”. This item is not a showstopper, but I run into this issue from time to time while searching through a code of different gems.
4. Simpler refactoring
What is started as object-oriented class can turn out to be a procedural module with a bunch of functions. To refactor instance methods into class methods you just need to add “class << self” wrapper and adjust indentation, which can be easily done in any editor.On the other side, Style #1 requires to put “self.”-prefix in every method, which is tedious and can’t be archived with usual means.Also, there is a case when you go into the opposite direction. Thing, which started as procedural module use some common context and should be refactored into class with instance methods. And again Style #1 requires removing of “self.”-prefix from all names, when in Style #2 you just remove “class << self / end” wrapper and adjust indentation.
It’s clearly seen, that “class << self” style has much more benefits than more commonly used “def self.method”. For me, the most crucial part is clear separation between class and instance stuff – because it improves code readability. I also like that Style #2 removes one class of errors from my Ruby programming.Generally, we stick to the rules below while using it:
- Create “class << self” wrapper even for one method
- Put class-methods part at the top of the class
Following these rules will allow you to always find class-methods in a predictable place and in a predictable style.