This style guide is based on this community style guide.
Most of the rules listed will have a brief explanation to understand the reasoning behind each. If none is provided, maybe it's too obvious, or assume that its main purpose is to improve readability.
All new projects must adhere to this style guide. Existing and ongoing projects should stick with their current conventions or they can adapt this if no convention is being followed yet.
-
Limit lines to 120 characters only. [link]
-
Indent using soft indents (2 whitespace) instead of real tab.[link]
-
Avoid trailing whitespace.[link]
- Configure your text editor to automatically trim trailing whitespaces.
-
End each file with newline.[link]
- Configure your text editor to automatically put empty line for each file.
- Whitespace around binary operators.[link]
# bad
x>1
str='Hello World'
1+300
# good
x > 1
str = 'Hello World'
1 + 300
- No whitespace after unary operators.[link]
# bad
! is_correct
# good
!is_correct
- Whitespace after comma.[link]
# bad
person.update :name,'Robert'
# good
person.update :name, 'Robert'
- Long right-hand expression should start on the next line.[link]
# bad
# less readable.
result = my_super_long_variable_name.
long_public_method_name_something argument
# ok
# more readable but effortful indentation.
result = my_super_long_variable_name.
long_public_method_name_something argument
# good
# more readable but unnecessary new line.
result =
my_super_long_variable_name.
long_public_method_name_something argument
# better
# more readable.
result =
my_super_long_variable_name.long_public_method_name_something argument
if
-else
,case
-when
, loop, and other multi-line block statements should start on the next line.[link]
# bad
# less readable, assignment is not instantly visible.
output = if some_condition
# do something
else
# do another thing
end
# good
# more readable, assignment is instantly visible but not width efficient.
output = if some_condition
# do something
else
# do another thing
end
# better
# more readable and width efficient.
output =
if some_condition
# do something
else
# do another thing
end
- Content of large hash value should start on the next line, 1 pair per line.[link]
# bad
# less readable.
my_big_hash = {:a => 'Ace of Spades', :b => 'Two of Spades', :c => 'Three of Spades',
:d => 'Four of Spades', :e => 'Five of Spades', :g => 'Joker'
}
# ok
# key-value pairs are much clearer.
my_big_hash = {:a => 'Ace of Spades',
:b => 'Two of Spades',
:c => 'Three of Spades',
:d => 'Four of Spades',
:e => 'Five of Spades',
:g => 'Joker'
}
# ok
# much readable but indentation is a little bit off and not width efficient.
my_big_hash = {:a => 'Ace of Spades',
:b => 'Two of Spades',
:c => 'Three of Spades',
:d => 'Four of Spades',
:e => 'Five of Spades',
:g => 'Joker'
}
# good
# much readable and uniform indentation, but not width efficient.
my_big_hash =
{
:a => 'Ace of Spades',
:b => 'Two of Spades',
:c => 'Three of Spades',
:d => 'Four of Spades',
:e => 'Five of Spades',
:g => 'Joker'
}
# better
# much readable and width efficient.
my_big_hash = {
:a => 'Ace of Spades',
:b => 'Two of Spades',
:c => 'Three of Spades',
:d => 'Four of Spades',
:e => 'Five of Spades',
:g => 'Joker'
}
- Content of large array value should start on the next line, with each of the succeeding line aligned.[link]
# bad
# less readable.
huge_array = [ace, king, queen, jack, ten, nine, eight, seven, six,
five, four, three, two
]
# ok
# readable but effortful indentation.
huge_array = [ace, king, queen, jack, ten, nine, eight, seven, six,
five, four, three, two]
# ok
# more readable but not width efficient.
huge_array =
[
ace, king, queen, jack, ten, nine, eight, seven, six, five, four,
three, two
]
# good
# more readable but too much line usage.
huge_array = [
ace,
king,
queen,
jack,
ten,
nine,
eight,
seven,
six,
five,
four,
three,
two
]
# better
# more readable and width efficient.
huge_array = [
ace, king, queen, jack, ten, nine, eight, seven, six, five, four,
three, two
]
- Use hash rocket (fat arrow)
=>
instead of colon:
.[link]
# bad
# confusing especially for symbol values.
{foo: 'value', bar: 'value 1'}
{foo: :value, bar: :value1}
# good
# much readable.
{:foo => 'value', :bar => 'value 1'}
{:foo => :value, :bar => :value1}
- No whitespace around hash body. Curly braces
{}
with spaces inside will only be used for blocks, in order to make a visual difference between blocks and hashes.[link]
# bad
{ :foo => 'value', :bar => 'value 1' }
# good
{:foo => 'value', :bar => 'value 1'}
- 1 key-value pair per line for large hash.[link]
# bad
{:a => 'aAa', :b => 'B', :c => 'CCC', :d => 'Dee', :e => 'elephant',
:f => 'FFfff', :g => 'GEE'}
# good
# but the indentation is a little bit confusing.
{:a => 'aAa',
:b => 'B',
:c => 'CCC',
:d => 'Dee',
:e => 'elephant',
:f => 'FFfff',
:g => 'GEE'}
# better
{
:a => 'aAa',
:b => 'B',
:c => 'CCC',
:d => 'Dee',
:e => 'elephant',
:f => 'FFfff',
:g => 'GEE'
}
- No whitespace around array body.[link]
# bad
[ 1, 2, 3 ]
# good
[1, 2, 3]
- Align values for large arrays.[link]
# bad
[red, blue, green, white, black, yellow, pink,
orange, gray]
# good
# more readable but not line efficient.
[
red,
blue,
green,
white,
black,
yellow,
pink,
orange,
gray
]
# better
# much readable and line efficient.
[
red, blue, green, white, black, yellow, pink,
orange, gray
]
- Use
_
to promote readability of numbers.[link]
# bad
# how many zeroes?!
number = 1000000
# good
number = 1_000_000
- Use single quotes (
'
) by default.[link]
# bad
# needs to check the whole string content if there is an interpolation.
"The quick brown fox jumps over the lazy dog"
# good
# can quickly recognize that there is no interpolation.
'The quick brown fox jumps over the lazy dog'
-
Use double quotes
""
if interpolation is needed.[link] -
Use double quotes
""
if you have single quote in your string.[link] -
Use
<<
instead of+
when concatenating strings.[link]
# bad
# slower
str = 'Hello'
str += ' World'
# good
# faster
str = 'Hello'
str << ' World'
Check this reference.
- Use
join
when concatenating with a uniform delimiter.[link]
folder = 'lib'
subfolder = 'foo'
file = 'baz.rb'
# bad
# less readable and hard to change the delimiter.
filename = "#{folder}/#{subfolder}/#{file}"
# good
# more readable and easy to change the delimiter.
filename = [folder, subfolder, file].join '/'
- Use
\
to break long strings instead of+
.[link]
# bad
# slower
'Bacon chicken turkey' +
' hotdog eggs tuna spam coffee' +
' mustard ketchup mayo'
# good
# faster
'Bacon chicken turkey' \
' hotdog eggs tuna spam coffee' \
' mustard ketchup mayo'
Check this reference.
- Whitespace around body of proc, lambda, and block.[link]
# bad
# format is too tight.
Proc.new {puts 'hello'}
list.each {|item| item.delete}
# good
# good spacing and much readable.
Proc.new { puts 'hello' }
list.each { |item| item.delete }
- Whitespace before block.[link]
# bad
list.each{ |item| item.save }
# good
list.each { |item| item.save }
- Use
do
andend
for multi-line blocks.[link]
# bad
list.each { |item|
item.name = 'new name'
item.save
}
# good
list.each do |item|
item.name = 'new name'
item.save
end
- Do not use 2 or more consecutive line-break inside blocks.[link]
# bad
# unnecessary logical separation.
list.each do |item|
statement_1
statement_2
end
# good
# enough logical separation.
list.each do |item|
statement_1
statement_2
end
- Do not chain multi-line blocks.[link]
# bad
list.map do |item|
# do something here
# evaluate something
end.each do |item|
# do something here
# random stuff
end
# good
result =
list.map do |item|
# do something here
# evaluate something
end
result.each do |item|
# do something here
# random stuff
end
- Method definition should not use parentheses.[link]
# bad
def foo(arg1, arg2, arg3)
# do something
end
# good
def foo arg1, arg2, arg3
# do something
end
- 1 Line break to separate method definitions.[link]
# bad
# unnecessary or too much logical separation.
def foo
statement_1
statement_2
statement_3
end
def bar
statement_a
statement_b
statement_c
end
# good
# enough logical separation.
def foo
statement_1
statement_2
statement_3
end
def bar
statement_a
statement_b
statement_c
end
- Do not use 2 or more consecutive line-break inside methods.[link]
# bad
# too much logical separation.
def method
statement_1
statement_2
end
# good
# enough logical separation.
def method
statement_1
statement_2
end
- Avoid using more than 3 arguments.[link]
# bad
# hard to memorize argument order.
def update_something color, size, material, brand
# update
end
# good
# no need to memorize argument order, just the argument name.
def update_something properties = {:color => nil, :size => nil, :material => nil, :brand => nil}
# update
end
# good
# arguments are encapsulated on an object.
def update_something properties = PropertyList.new
# update
end
# good
# easier to memorize argument order.
def plot x, y, z
# plot point
end
- No space around
()
.[link]
# bad
foo( arg1 ).bar( arg2 ).baz
# good
foo(arg1).bar(arg2).baz
- Avoid passing method call as argument.[link]
# bad
object.explode universe.answer(human.get(:life))
# good
life = human.get :life
answer = universe.answer life
object.explode answer
- Single-line method call should not use parentheses.[link]
# bad
foo(arg1, arg2, arg3)
# good
foo arg1, arg2, arg3
- Large hash as argument.[link]
# bad
object.update(:prop1 => 'Value 01',
:prop2 => 'Value 02',
:prop3 => 'Value 03',
:prop4 => 'Value 04')
# good
object.update(
:prop1 => 'Value 01',
:prop2 => 'Value 02',
:prop3 => 'Value 03',
:prop4 => 'Value 04'
)
- Large array as argument.[link]
# bad
object.add ['jack of diamonds', 'two of spades', 'ten of clubs',
'seven of diamonds', 'king of hearts', 'ace of hearts', 'nine of spades',
'four of diamonds', 'joker', 'three of clubs', 'joker']
# good
object.add ['jack of diamonds', 'two of spades', 'ten of clubs',
'seven of diamonds', 'king of hearts', 'ace of hearts',
'nine of spades', 'four of diamonds', 'joker', 'three of clubs',
'joker']
# better
object.add [
'jack of diamonds', 'two of spades', 'ten of clubs', 'seven of diamonds',
'king of hearts', 'ace of hearts', 'nine of spades', 'four of diamonds',
'joker', 'three of clubs', 'joker'
]
- As much as possible, write 1 argument per line for long argument list.[link]
# bad
do_this(
'value', 'another value', [
item_1, item_2, item_3, item_4
...
item_n
],
{
:a => 1,
:b => 2,
...
:z => 26
},
1000, 2000, object
)
# good
do_this(
'value',
'another value',
[
item_1, item_2, item_3, item_4
...
item_n
],
{
:a => 1,
:b => 2,
...
:z => 26
},
1000,
2000,
object
)
- As much as possible, use 1 method call per line for long method chains.[link]
# bad
object.foo.
bar(:key => 'Bar!').baz(:a, :b).
fizz(:x => 1000, :y => 2000, :z => 3000)
# good
object.
foo.
bar(:key => 'Bar!').
baz(:a, :b).
fizz(:x => 1000, :y => 2000, :z => 3000)
- Use trailing
.
for long method chains.[link]
# bad
object
.foo
.bar
.baz
# good
object.
foo.
bar.
baz
- No parentheses around conditions.[link]
if expression > 100
-
Do not use
and
andor
on conditions.[link] -
Don't use
unless
withelse
. Convert toif
-else
statement.[link] -
Use early
return
if possible.[link]
# bad
def foo
if must_be_true
# do something
end
end
# good
def foo
return unless must_be_true
# do something
end
- Use ternary operator
?:
for simple statements instead ofif
-else
.[link]
some_condition ? do_something : do_something_else(:arg => 100)
- For long ternary operator
?:
statement, write 1 option per line.[link]
some_condition ?
do_something('hello').map(&:to_f) :
do_something_else(:arg1 => 100, :arg2 => 200)
- 1 expression per line for long condition.[link]
# bad
if something || another ||
maybe_true || sometimes_false
# good
if something ||
another ||
maybe_true ||
sometimes_false
- For long condition, leave 1 line break before the body.[link]
# bad
if something ||
another ||
maybe_true ||
sometimes_false
# body starts here
end
# good
if something ||
another ||
maybe_true ||
sometimes_false
# body starts here
end
- Favor
if/else
modifier for simple single-line body.[link]
# bad
if something_is_true
puts something
end
# good
puts something if something_is_true
- Do not use
if/else
modifier for multi-line blocks.[link]
# bad
list.each do |item|
#
# multi-line body
#
end if test_condition
# good
if test_condition
list.each do |item|
#
# multi-line body
#
end
end
- Favor
unless
overif
for negative conditions.[link]
# bad
dance if !tired
# good
dance unless tired
- Don't use
unless
for negative expressions.[link]
# bad
do_something unless list.empty?
do_another unless text.blank?
# good
do_something if list.any?
do_another if text.present?
- Align
when
withcase
.[link]
case something
when 1
puts 1
when 2
puts 2
end
- Multiple expressions alignment.
# option 1
try_this_one ||
or_this_one ||
or_maybe_this_one ||
okay_this_one
# option 2
try_this_one ||
or_this_one ||
or_maybe_this_one ||
okay_this_one
# option 3
try_this_one ||
or_this_one ||
or_maybe_this_one ||
okay_this_one
TODO: Discuss this.
- Only use multi-line comments for removing a block of code temporarily.[link]
- Do not use end-of-line comments.[link]
# bad
do_something # comment about the process
# good
# comment about the process
do_something
- Use
TODO:
to note task that needs to be done on a specific statement or block of code in the future.[link]
# TODO: refactor this
def complex_method
# do something unexplainable here
end
- Use
SEE: <insert link>
if you need to add a reference to a specific statement or block of code.[link]
# SEE: http://en.wikipedia.org/wiki/Earth_radius#Mean_radius
EARTH_MIN_RADIUS_KM = 6371;
EARTH_MIN_RADIUS_MI = 3958;
- Line break around class and module contents.[link]
module MyModule
def my_method
# do something
end
end
- Use 2 line breaks to create logical separations inside class and module.[link]
class User
include Authenticator
include PasswordManager
attr_accessor :name, :password, :email
end
- Use 3 line breaks to create a logical separation between group of methods inside module/class.[link]
# ok
# related methods are grouped but there is no visible logical separation.
class User
def fook
# foo related method
end
def fooz
# foo related method
end
def bark
# bar related method
end
def barz
# bar related method
end
end
-
5 line breaks between class/module definitions.[link]
-
Always use
self
when callingpublic
andprotected
properties of a class.[link]
# bad
class Person
def save
something = 'xxx'
collection = []
collection.each do |it|
result = it.evaluate_this something
nonsense = result * 100
end
# is name a local variable or an instance method/variable?
raise 'error' if name.blank?
end
end
# good
class Person
def save
something = 'xxx'
collection = []
collection.each do |it|
result = it.evaluate_this something
nonsense = result * 100
end
# it is clear that name is an instance method/variable.
raise 'error' if self.name.blank?
end
end
- Class statements order.[link]
require 'uri'
class Person
# include and extend directives
extend Ability
include Model
# constants
MY_CONSTANT = 100
# attribute directives
attr_accessor :name, :age
attr_reader :nationality
#
#
# Other macros here
#
#
# class methods
def self.class_method
# do something
end
# public methods
def public_method
# do something
end
# protected methods
protected
def protected_utility_method
# do something
end
# private methods
private
def private_utility_method
# do something
end
end
- Use
protected
for utility methods that use instance variables/methods.[link]
class User
protected
def format_name
self.name = self.last_name + ', ' + self.first_name
end
def default_instance_var
@my_variable = 'Default Value'
end
end
- Use
private
for utility methods that don't use instance variables/methods.[link]
class User
private
def day_only date
date.strftime '%A'
end
end