Olio Ruby Style Guide
*NOTES:*
This document is a work in progress, it may contain errors, inconsistencies and change periodically. Inspiration for the layout and structure is taken from the Rubocop style guide.
Inspiration
In an attempt to document and formularise Olio’s approach to writing Ruby, this document contains the agreed upon Ruby style guides that are acceptable for submission into our repositories.
A Note about Consistency
A style guide is about consistency. Consistency with this style guide is important. Consistency within a project is more important. Consistency within one class or method is the most important.
However, know when to be inconsistent — sometimes style guide recommendations just aren’t applicable. When in doubt, use your best judgment. Look at other examples and decide what looks best. And don’t hesitate to ask!
In particular: do not break backwards compatibility just to comply with this guide!
Some other good reasons to ignore a particular guideline:
- When applying the guideline would make the code less readable, even for someone who is used to reading code that follows this style guide.
- To be consistent with surrounding code that also breaks it (maybe for historic reasons) — although this is also an opportunity to clean up someone else’s mess (in true XP style).
- When the code needs to remain compatible with older versions of Ruby that don’t support the feature recommended by the style guide.
Rules
Indentation
Use two spaces per indentation level (aka soft tabs).
# bad - four spaces
def some_method
do_something
end
# good
def some_method
do_something
end
Operator Method Call
Avoid dot where not required for operator method calls.
# bad
num.+ 42
# good
num + 42
Spaces and Operators
Use spaces around operators, after commas, colons and semicolons. Whitespace might be (mostly) irrelevant to the Ruby interpreter, but its proper use is the key to writing easily readable code.
# bad
sum=1+2
a,b=1,2
class FooError<StandardError;end
# good
sum = 1 + 2
a, b = 1, 2
class FooError < StandardError; end
Spaces and Braces
No spaces after (, [ or before ], ). Use spaces around { and before }.
# bad
some( arg ).other
[ 1, 2, 3 ].each{|e| puts e}
# good
some(arg).other
[1, 2, 3].each { |e| puts e }
{
and }
deserve a bit of clarification, since they are used for block and hash literals, as well as string interpolation.
Below, the second variant has the advantage of adding visual difference between block and hash literals. Whichever one you pick - apply it consistently.
# bad - no space inside brackets
{one: 1, two: 2}
# good - space inside brakets
{ one: 1, two: 2 }
With interpolated expressions, there should be no padded-spacing inside the braces.
# bad
"From: #{ user.first_name }, #{ user.last_name }"
# good
"From: #{user.first_name}, #{user.last_name}"
No Space after Bang
No space after !
.
# bad
! something
# good
!something
No Space inside Range Literals
No space inside range literals.
# bad
1 .. 3
'a' ... 'z'
# good
1..3
'a'...'z'
Space in Method Calls
Do not put a space between a method name and the opening parenthesis.
# bad
puts (x + y)
# good
puts(x + y)
Space in Brackets Access
Do not put a space between a receiver name and the opening brackets.
# bad
collection [index_or_key]
# good
collection[index_or_key]
Memoised Instance Variables
When creating an instance variable used for “memoising” a methods returned value, use a @_
prefix to better communicate that the variable should be used directly.
# bad
def foo
@foo ||= my_method.call
end
# bad - different variable name
def foo
@foo_call ||= my_method.call
end
# good
def foo
@_foo ||= my_method.call
end
Class/Method Chaining
Olio applies the dot in chained method calls, at the end of the line:
# bad
MyModule::MyClass
.description_method_name
.chained_method_name
.map #...
# good
MyModule::MyClass.
description_method_name.
chained_method_name.
map #...
Unused Variables Prefix
Prefix with _ unused block parameters and local variables. It’s also acceptable to use just _ (although it’s a bit less descriptive). This convention is recognized by the Ruby interpreter and tools like RuboCop will suppress their unused variable warnings.
# bad
result = hash.map { |k, v| v + 1 }
# good
result = hash.map { |_k, v| v + 1 }
# good
result = hash.map { |_, v| v + 1 }
# bad
def something(x)
unused_var, used_var = something_else(x)
# some code
end
def something(x)
_unused_var, used_var = something_else(x)
# some code
end
def something(x)
_, used_var = something_else(x)
# some code
end