- Whitespace
- Commenting
- Methods
- Conditional Expressions
- Syntax
- Naming
- Classes
- Exceptions
- Collections
- Strings
- Be Consistent
- Use soft-tabs set to 2 spaces.
class Pokemon
∙∙def weakness
∙∙∙∙# Handles weakness
end
end
-
Never leave trailing whitespace.
-
Use spaces around operators; after commas, colons, and semicolons; and around
{
and before}
.
sum = 1 + 1
a, b = 1, 2
a > sum ? '2 is now greater than 1' : 'You cannot math'
[1, 2, 3].each { |e| puts e }
- No spaces after
(
,[
or before]
,)
.
some(arg).other
[1, 2, 3].length
- Add a new line after conditionals, blocks, case statements, etc.
if wall.needs_paint?
paint_the_wall
end
wall.paint(:favorite_color)
Though a pain to write, comments are absolutely vital to keeping our code readable. The following rules describe what you should comment and where. But remember: while comments are very important, the best code is self-documenting. Giving sensible names to types and variables is much better than using obscure names that you must then explain through comments.
When writing your comments, write for your audience: the next contributor who will need to understand your code. Be generous — the next one may be you!
Please don't leave commented-out code, Brian will personally hunt you down.
- Use
def
with parentheses when there are arguments. Omit the parentheses when the method doesn't accept any arguments.
def some_method
# body omitted
end
def some_method_with_arguments(arg1, arg2)
# body omitted
end
- Do not use default arguments. Use keyword arguments instead.
# bad
def bake(pie, temp = 400, at = Time.now)
# Bake stuff
end
# good
def bake(pie, temp: 400, at: Time.now)
# Bake stuff
end
- Never use
then
for multi-lineif/unless
.
# bad
if some_condition then
...
end
# good
if some_condition
...
end
-
The
and
andor
keywords are banned. They have a lower order of precednce and will cause unexpected side effects. Always use&&
and||
instead. -
Modifier
if/unless
usage is okay when the body is simple, the condition is simple, and the whole thing fits on one line. Otherwise, avoid modifierif/unless
.return if object.nil?
is ok. -
unless
withelse
is confusing. Please use the positive case first.
# bad
unless success?
puts 'failure'
else
puts 'success'
end
# good
if success?
puts 'success'
else
puts 'failure'
end
- Avoid
unless
with multiple conditions.
# bad
unless foo? && bar?
...
end
# okay
if !(foo? && bar?)
...
end
- Don't use parentheses around the condition of an
if/unless/while
, unless the condition contains an assignment (see Using the return value of=
below).
# bad
if (x > 10)
...
end
# good
if x > 10
...
end
# ok
if (x = self.next_value)
...
end
- Avoid the ternary operator (
?:
) except in cases where all expressions are extremely trivial. However, do use the ternary operator(?:
) overif/then/else/end
constructs for single line conditionals.
# bad
result = if some_condition then something else something_else end
# good
result = some_condition ? something : something_else
- Use one expression per branch in a ternary operator. This
also means that ternary operators must not be nested. Prefer
if/else
constructs in these cases.
# bad
some_condition ? (nested_condition ? nested_something : nested_something_else) : something_else
# good
if some_condition
nested_condition ? nested_something : nested_something_else
else
something_else
end
- Avoid multi-line
?:
(the ternary operator), useif/then/else/end
instead.
- Never use
for
, unless you know exactly why. Most of the time iterators should be used instead.for
is implemented in terms ofeach
(so you're adding a level of indirection), but with a twist -for
doesn't introduce a new scope (unlikeeach
) and variables defined in its block will be visible outside it.
arr = [1, 2, 3]
# bad
for elem in arr do
puts elem
end
# good
arr.each { |elem| puts elem }
- Use
{...}
overdo...end
for single-line blocks. Do not use{...}
for multi-line blocks (multiline chaining is always ugly). Always usedo...end
for "control flow" and "method definitions" (e.g. in Rakefiles and certain DSLs). Avoiddo...end
when chaining.
names = ["Bozhidar", "Steve", "Sarah"]
# bad
names.each do |name|
puts name
end
# good
names.each { |name| puts name }
# bad
names.select do |name|
name.start_with?("S")
end.map { |name| name.upcase }
# good
names.select { |name| name.start_with?("S") }.map { |name| name.upcase }
- Utilize Ruby's implicit return, only use
return
statements when necessary (returning early from a function)
# bad
def some_method(some_arr)
return some_arr.size
end
# good
def some_method(some_arr)
some_arr.size
end
- Use
||=
freely to initialize variables.
# set name to Ash, only if it's nil or false
name ||= 'Ash'
- Don't use
||=
to initialize boolean variables. (Consider what would happen if the current value happened to befalse
.)
# bad - would set enabled to true even if it was false
enabled ||= true
# good
enabled = true if enabled.nil?
- When a method block takes only one argument, and the body consists solely of
reading an attribute or calling one method with no arguments, use the
&:
shorthand.
# bad
bluths.map { |bluth| bluth.occupation }
bluths.select { |bluth| bluth.blue_self? }
# good
bluths.map(&:occupation)
bluths.select(&:blue_self?)
-
Use
snake_case
for methods and variables. -
Use
CamelCase
for classes and modules (Keep acronyms like HTTP, RFC, XML uppercase). -
Use
SCREAMING_SNAKE_CASE
for other constants. -
The names of predicate methods (methods that return a boolean value) should end in a question mark. (i.e.
Array#empty?
). -
The names of potentially "dangerous" methods (i.e. methods that modify
self
or the arguments,exit!
, etc.) should end with an exclamation mark. Bang methods should only exist if a non-bang method exists ([More on this][ruby-naming-bang]).
- Avoid the usage of class (
@@
) variables due to their "nasty" behavior in inheritance.
class Parent
@@class_var = 'parent'
def self.print_class_var
puts @@class_var
end
end
class Child < Parent
@@class_var = 'child'
end
Parent.print_class_var # => will print "child"
As you can see all the classes in a class hierarchy actually share one class variable. Class instance variables should usually be preferred over class variables.
- Use
def self.method
to define singleton methods. This makes the methods more resistant to refactoring changes.
class TestClass
# bad
def TestClass.some_method
...
end
# good
def self.some_other_method
...
end
- Indent the
public
,protected
, andprivate
methods as much the method definitions they apply to. Leave one blank line above them.
class SomeClass
def public_method
# ...
end
protected
def protected_method
# ...
end
private
def private_method
# ...
end
end
- Don't use exceptions for flow of control.
# bad
begin
n / d
rescue ZeroDivisionError
puts "Cannot divide by 0!"
end
# good
if d.zero?
puts "Cannot divide by 0!"
else
n / d
end
- Do not rescuing the
Exception
class, be explicit in what you are rescuing from
# bad
begin
# an exception occurs here
rescue Exception
# exception handling
end
# bad
begin
# an exception occurs here
rescue
# exception handling
end
# good
begin
# an exception occurs here
rescue ActiveRecord::RecordNotFound
# exception handling
end
- Use
Set
instead ofArray
when dealing with unique elements.Set
implements a collection of unordered values with no duplicates. This is a hybrid ofArray
's intuitive inter-operation facilities andHash
's fast lookup.
Set.new([1,1,2,3]) # => #<Set: {1, 2, 3}>
- Use symbols instead of strings as hash keys.
# bad
hash = { 'one' => 1, 'two' => 2, 'three' => 3 }
# good
hash = { one: 1, two: 2, three: 3 }
- Use multi-line hashes when it makes the code more readable, and use trailing commas to ensure that parameter changes don't cause extraneous diff lines when the logic has not otherwise changed.
hash = {
protocol: 'https',
only_path: false,
controller: :users,
action: :set_password,
redirect: @redirect_url,
secret: @secret
}
-
Use single quotes, unless using string interpolation.
-
Prefer string interpolation instead of string concatenation:
# bad
email_with_name = user.name + ' <' + user.email + '>'
# good
email_with_name = "#{user.name} <#{user.email}>"
- Avoid using
String#+
when you need to construct large data chunks. Instead, useString#<<
. Concatenation mutates the string instance in-place and is always faster thanString#+
, which creates a bunch of new string objects.
# good and also fast
html = ''
html << '<h1>Page title</h1>'
paragraphs.each do |paragraph|
html << "<p>#{paragraph}</p>"
end
If you're editing code, take a few minutes to look at the code around you and determine its style. If they use spaces around all their arithmetic operators, you should too. If their comments have little boxes of hash marks around them, make your comments have little boxes of hash marks around them too.
The point of having style guidelines is to have a common vocabulary of coding so people can concentrate on what you're saying rather than on how you're saying it. We present global style rules here so people know the vocabulary, but local style is also important. If code you add to a file looks drastically different from the existing code around it, it throws readers out of their rhythm when they go to read it. Avoid this.
Thanks to these kind folks!