Ruby programmers are very flexible (and permissive) when talking about Ruby code indentation. Most of rubyists I know prefer to indent with two spaces instead of tabs (soft tabs in some editors). There are even some style guides and code conventions published for the language, but none of them is official and they talk too little about code indentation practices.
Things go even worse when we have to choose how to indent private, protected and public sections of classes. Programmers and projects I’ve seen so far seem to adopt different styles. I’ll try to summarize them here:
1. Indent as a new block
This is the most common pattern I see out there. Some programmers prefer to treat sections created by access modifiers as new blocks and indent them:
class MyClass def the_public_method # ... end private def first_private_method # ... end def second_private_method # ... end protected def the_protected_method # ... end end
Pros:
- Visibility: easy to see if a method has a non-standard access modifier (non-public in most cases).
- Produces a very readable code.
- Used in the rails codebase (mainly older code).
Cons:
- Semantically wrong: access modifiers do not create new scopes. They are simple method calls. Deeper explanation in the next item.
- Methods inside the same scope with different indentation levels.
- (opinion) One more level of indentation. When you have classes inside modules it starts being a problem: “indentation hell” :-). Your code ends up using its 80 columns very fast and you start having to break lines more often.
2. No indentation
Ruby access modifiers are simple method calls. The Module class (from which Ruby classes inherit) has the private, protected and public methods, that when called with no arguments, simply change the visibility of subsequent defined methods. You may confirm this by testing that the following code works:
class MyClass self.send(:private) def the_private_method # ... end def another_private_method # ... end end
Try to call any of these methods in an instance of the MyClass
class and you will confirm they are private.
Because access modifiers are simple method calls, they don’t create a new scope. Semantically speaking, they shouldn’t create another level of indentation. This is even advocated by one of the most important Ruby style guides.
class MyClass def the_public_method # ... end private def first_private_method # ... end def second_private_method # ... end protected def the_protected_method # ... end end
Because of its correctness, this was my preferred style until recently, when I found the next ones.
Pros:
- It is semantically correct: method calls don’t create new scopes, then method calls shouldn’t increase indentation levels.
- (opinion) this style makes access modifiers look like python decorators, Java annotations and C# attributes. IMO, it’s one of the nice things about Ruby: its ability to reproduce most of other languages features, without requiring new syntax or fancy constructs. It’s a simple method call.
Cons:
- Hard to see if a method has any non-standard access modifier. In classes with many methods (code smell!) you must constantly scroll to see what access modifier is applied.
- Some would argue that this could be solved with proper syntax highlighting or visual method decoration. But it requires editor/IDE support, then I’m considering it as a disadvantage.
3. if-else style
We have a similar case in Ruby: the if
keyword creates a new block and has associated else
and elsif
statements, which are also new blocks. The convention suggests the following indentation (note that if
, elsif
and else
are in the same indentation level):
if something? 2.times { play } jump(2.meters) elsif other? sing and dance else cry walk end
Some of the code recently pushed to Rails 3.0 use the same indentation style for classes with access modifiers. I liked it:
class MyClass def the_public_method # ... end private def first_private_method # ... end def second_private_method # ... end protected def the_protected_method # ... end end
Pros:
- Easy to see access modifiers inside classes. With a fast look it is easy to identify sections of private, public and protected methods. They look like blocks.
- Readable code. Similar to other Ruby constructs.
- Used in the rails codebase (mainly newer code).
Cons:
- Still semantically wrong. Access modifiers are inside the scope created by the
class
keyword. They should be indented. if
,elsif
andelse
are keywords and have special meaning. Access modifiers aren’t and should follow the same convention of other method calls.
4. Indentation with one space
C++ also splits private, protected and public methods in sections. The construct is very similar to Ruby:
class MyClass { public: MyClass(); void ThePublicMethod(int n); void Print(ostream &output) const; private: int *Items; bool FirstPrivateMethod(); int SecondPrivateMethod(); };
While reading Google’s style guide for C++ code, their recommendation for public, private and protected sections indentation caught my attention. They suggest that you indent the private
, protected
and public
keywords with only one space.
It seemed a bit awkward in the beginning. But soon, I started liking it because it makes sections easy to identify, access modifiers remain indented inside classes and methods stay all in the same indentation level, as they are all in the same scope.
class MyClass def the_public_method # ... end private def first_private_method # ... end def second_private_method # ... end protected def the_protected_method # ... end end
Pros:
- Easy to see access modifiers and sections inside classes.
- Semantically correct.
- All methods remain in the same indentation level.
- Google style guide.
Cons:
- People are always fighting for 2 spaces vs 4 spaces vs tabs indentation. One space? Very uncommon.
- Special treatment for regular method calls. Statements inside the same scope with different indentation levels
My choice
Currently, I tend to like the 3rd (new Rails style) and 4th (Google) styles more. I somehow feel they give the best deal, considering their advantages and disadvantages. Being able to easily identify sections and access modifiers inside classes is very important to me.
In my current project, the team adopted the Google style. I’m happy with it, but you must be flexible in the beginning to adopt one-space-indentation. I won’t lie, it feels strange until you get used. Another issue I have is that my TextMate indent Ruby code with two spaces and treat them as one “step” when navigating with keyboard cursors. Then, I have to type a few more keystrokes to indent access modifiers the way I want. It’s hard to explain, you will have to try it yourself.
And you, what’s your opinion?
How do you indent access modifiers and their sections inside classes?