There are some areas in which there is no clear consensus in the Ruby community regarding a particular style (like string literal quoting, spacing inside hash literals, dot position in multi-line method chaining, etc.). In such scenarios all popular styles are acknowledged and it's up to you to pick one and apply it consistently.
This style guide evolves over time as additional conventions are identified and past conventions are rendered obsolete by changes in Ruby itself.
If you need to bust this cache file to pick up the latest changes to the guide (which should happen automatically every 24 hours), you can simply delete the cache file from your project.
We didn't come up with all the rules out of nowhere. In fact, this repo started life as a fork of bbatsov's excellent ruby-style-guide
, with a few changes
that happen to suit our tastes.
-
Use UTF-8
as the source file encoding.
[link]
-
Use two spaces per indentation level (aka soft tabs). No hard tabs.
[link]
def some_method
do_something
end
def some_method
do_something
end
-
Use Unix-style line endings. (*BSD/Solaris/Linux/macOS users are covered by
default, Windows users have to be extra careful.)
[link]
-
Don't use ;
to separate statements and expressions. As a corollary—use
one expression per line.
[link]
puts 'foobar';
puts 'foo'; puts 'bar'
puts 'foobar'
puts 'foo'
puts 'bar'
puts 'foo', 'bar'
-
Prefer a single-line format for class definitions with no body.
[link]
class FooError < StandardError
end
class FooError < StandardError; end
FooError = Class.new(StandardError)
-
Avoid single-line methods. Although they are somewhat popular in the wild,
there are a few peculiarities about their definition syntax that make their
use undesirable. At any rate—there should be no more than one expression
in a single-line method.
[link]
def too_much; something; something_else; end
def no_braces_method; body end
def no_braces_method; body; end
def some_method() body end
def some_method
body
end
One exception to the rule are empty-body methods.
def no_op; end
-
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.
[link]
sum = 1 + 2
a, b = 1, 2
class FooError < StandardError; end
The only exception, regarding operators, is the exponent operator:
e = M * c ** 2
e = M * c**2
-
No spaces after (
, [
or before ]
, )
.
Use spaces around {
and before }
.
[link]
some( arg ).other
[ 1, 2, 3 ].each{|e| puts e}
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.
For hash literals two styles are considered acceptable.
The first variant is slightly more readable (and arguably more
popular in the Ruby community in general). The second variant has
the advantage of adding visual difference between block and hash
literals. Whichever one you pick—apply it consistently.
{ one: 1, two: 2 }
{one: 1, two: 2}
With interpolated expressions, there should be no padded-spacing inside the braces.
"From: #{ user.first_name }, #{ user.last_name }"
"From: #{user.first_name}, #{user.last_name}"
-
No space after !
.
[link]
! something
!something
-
No space inside range literals.
[link]
1 .. 3
'a' ... 'z'
1..3
'a'...'z'
-
Indent when
as deep as case
. This is the style established in both
"The Ruby Programming Language" and "Programming Ruby".
[link]
case
when song.name == 'Misty'
puts 'Not again!'
when song.duration > 120
puts 'Too long!'
when Time.now.hour > 21
puts "It's too late"
else
song.play
end
case
when song.name == 'Misty'
puts 'Not again!'
when song.duration > 120
puts 'Too long!'
when Time.now.hour > 21
puts "It's too late"
else
song.play
end
-
When assigning the result of a conditional expression to a variable,
preserve the usual alignment of its branches.
[link]
kind = case year
when 1850..1889 then 'Blues'
when 1890..1909 then 'Ragtime'
when 1910..1929 then 'New Orleans Jazz'
when 1930..1939 then 'Swing'
when 1940..1950 then 'Bebop'
else 'Jazz'
end
result = if some_cond
calc_something
else
calc_something_else
end
kind = case year
when 1850..1889 then 'Blues'
when 1890..1909 then 'Ragtime'
when 1910..1929 then 'New Orleans Jazz'
when 1930..1939 then 'Swing'
when 1940..1950 then 'Bebop'
else 'Jazz'
end
result = if some_cond
calc_something
else
calc_something_else
end
kind =
case year
when 1850..1889 then 'Blues'
when 1890..1909 then 'Ragtime'
when 1910..1929 then 'New Orleans Jazz'
when 1930..1939 then 'Swing'
when 1940..1950 then 'Bebop'
else 'Jazz'
end
result =
if some_cond
calc_something
else
calc_something_else
end
-
Use empty lines between method definitions and also to break up methods
into logical paragraphs internally.
[link]
def some_method
data = initialize(options)
data.manipulate!
data.result
end
def some_method
result
end
-
Don't use several empty lines in a row.
[link]
some_method
some_method
some_method
some_method
-
Use empty lines around access modifiers.
[link]
class Foo
attr_reader :foo
def foo
end
end
class Foo
attr_reader :foo
def foo
end
end
-
Don't use empty lines around method, class, module, block bodies.
[link]
class Foo
def foo
begin
do_something do
something
end
rescue
something
end
end
end
class Foo
def foo
begin
do_something do
something
end
rescue
something
end
end
end
-
Avoid comma after the last parameter in a method call, especially when the
parameters are not on separate lines.
[link]
some_method(
size,
count,
color,
)
some_method(size, count, color, )
some_method(size, count, color)
-
Use spaces around the =
operator when assigning default values to method
parameters:
[link]
def some_method(arg1=:default, arg2=nil, arg3=[])
end
def some_method(arg1 = :default, arg2 = nil, arg3 = [])
end
While several Ruby books suggest the first style, the second is much more
prominent in practice (and arguably a bit more readable).
-
Avoid line continuation \
where not required. In practice, avoid using
line continuations for anything but string concatenation.
[link]
result = 1 - \
2
result = 1 \
- 2
long_string = 'First part of the long string' \
' and second part of the long string'
-
Adopt a consistent multi-line method chaining style. There are two popular
styles in the Ruby community, both of which are considered
good—leading .
(Option A) and trailing .
(Option B).
[link]
-
(Option A) When continuing a chained method invocation on
another line keep the .
on the second line.
one.two.three.
four
one.two.three
.four
-
(Option B) When continuing a chained method invocation on another line,
include the .
on the first line to indicate that the
expression continues.
one.two.three
.four
one.two.three.
four
A discussion on the merits of both alternative styles can be found
here.
-
Align the parameters of a method call if they span more than one
line. When aligning parameters is not appropriate due to line-length
constraints, single indent for the lines after the first is also
acceptable.
[link]
def send_mail(source)
Mailer.deliver(to: 'bob@example.com', from: 'us@example.com', subject: 'Important message', body: source.text)
end
def send_mail(source)
Mailer.deliver(
to: 'bob@example.com',
from: 'us@example.com',
subject: 'Important message',
body: source.text)
end
def send_mail(source)
Mailer.deliver(to: 'bob@example.com',
from: 'us@example.com',
subject: 'Important message',
body: source.text)
end
def send_mail(source)
Mailer.deliver(
to: 'bob@example.com',
from: 'us@example.com',
subject: 'Important message',
body: source.text
)
end
-
Align the elements of array literals spanning multiple lines.
[link]
menu_item = ['Spam', 'Spam', 'Spam', 'Spam', 'Spam', 'Spam', 'Spam', 'Spam',
'Baked beans', 'Spam', 'Spam', 'Spam', 'Spam', 'Spam']
menu_item = [
'Spam', 'Spam', 'Spam', 'Spam', 'Spam', 'Spam', 'Spam', 'Spam',
'Baked beans', 'Spam', 'Spam', 'Spam', 'Spam', 'Spam'
]
menu_item =
['Spam', 'Spam', 'Spam', 'Spam', 'Spam', 'Spam', 'Spam', 'Spam',
'Baked beans', 'Spam', 'Spam', 'Spam', 'Spam', 'Spam']
-
Add underscores to large numeric literals to improve their readability.
[link]
num = 1000000
num = 1_000_000
-
Prefer smallcase letters for numeric literal prefixes.
0o
for octal, 0x
for hexadecimal and 0b
for binary.
Do not use 0d
prefix for decimal literals.
[link]
num = 01234
num = 0O1234
num = 0X12AB
num = 0B10101
num = 0D1234
num = 0d1234
num = 0o1234
num = 0x12AB
num = 0b10101
num = 1234
-
Use [Rdoc][rdoc] and its conventions for API documentation. Don't put an
empty line between the comment block and the def
.
[link]
-
Limit lines to 80 characters.
[link]
-
Avoid trailing whitespace.
[link]
-
End each file with a newline.
[link]
-
Don't use block comments. They cannot be preceded by whitespace and are not
as easy to spot as regular comments.
[link]
-
Use ::
only to reference constants(this includes classes and
modules) and constructors (like Array()
or Nokogiri::HTML()
).
Do not use ::
for regular method invocation.
[link]
SomeClass::some_method
some_object::some_method
SomeClass.some_method
some_object.some_method
SomeModule::SomeClass::SOME_CONST
SomeModule::SomeClass()
-
Use def
with parentheses when there are parameters. Omit the
parentheses when the method doesn't accept any parameters.
[link]
def some_method()
end
def some_method
end
def some_method_with_parameters param1, param2
end
def some_method_with_parameters(param1, param2)
end
-
Use parentheses around the arguments of method invocations,
especially if the first argument begins with an open parenthesis (
,
as in f((3 + 2) + 1)
.
[link]
x = Math.sin y
x = Math.sin(y)
array.delete e
array.delete(e)
temperance = Person.new 'Temperance', 30
temperance = Person.new('Temperance', 30)
Only omit parentheses for
-
Method calls with no arguments:
Kernel.exit!()
2.even?()
fork()
'test'.upcase()
Kernel.exit!
2.even?
fork
'test'.upcase
-
Methods that are part of an internal DSL (e.g., Rake, Rails, RSpec):
validates(:name, presence: true)
validates :name, presence: true
-
Methods that have "keyword" status in Ruby:
class Person
attr_reader(:name, :age)
attr_reader :name, :age
end
puts(temperance.age)
puts temperance.age
-
Define optional arguments at the end of the list of arguments.
Ruby has some unexpected results when calling methods that have
optional arguments at the front of the list.
[link]
def some_method(a = 1, b = 2, c, d)
puts "#{a}, #{b}, #{c}, #{d}"
end
some_method('w', 'x')
some_method('w', 'x', 'y')
some_method('w', 'x', 'y', 'z')
def some_method(c, d, a = 1, b = 2)
puts "#{a}, #{b}, #{c}, #{d}"
end
some_method('w', 'x')
some_method('w', 'x', 'y')
some_method('w', 'x', 'y', 'z')
-
Avoid the use of parallel assignment for defining variables. Parallel
assignment is allowed when it is the return of a method call, used with
the splat operator, or when used to swap variable assignment. Parallel
assignment is less readable than separate assignment.
[link]
a, b, c, d = 'foo', 'bar', 'baz', 'foobar'
a = 'foo'
b = 'bar'
c = 'baz'
d = 'foobar'
a = 'foo'
b = 'bar'
a, b = b, a
puts a
puts b
def multi_return
[1, 2]
end
first, second = multi_return
first, *list = [1, 2, 3, 4]
hello_array = *'Hello'
a = *(1..3)
-
Avoid the use of unnecessary trailing underscore variables during
parallel assignment. Named underscore variables are to be preferred over
underscore variables because of the context that they provide.
Trailing underscore variables are necessary when there is a splat variable
defined on the left side of the assignment, and the splat variable is
not an underscore.
[link]
foo = 'one,two,three,four,five'
first, second, _ = foo.split(',')
first, _, _ = foo.split(',')
first, *_ = foo.split(',')
foo = 'one,two,three,four,five'
*beginning, _ = foo.split(',')
*beginning, something, _ = foo.split(',')
a, = foo.split(',')
a, b, = foo.split(',')
first, _second = foo.split(',')
first, _second, = foo.split(',')
first, *_ending = foo.split(',')
-
Do not use for
, unless you know exactly why. Most of the time iterators
should be used instead. for
is implemented in terms of each
(so you're
adding a level of indirection), but with a twist—for
doesn't
introduce a new scope (unlike each
) and variables defined in its block
will be visible outside it.
[link]
arr = [1, 2, 3]
for elem in arr do
puts elem
end
elem
arr.each { |elem| puts elem }
elem
-
Do not use then
for multi-line if
/unless
.
[link]
if some_condition then
end
if some_condition
end
-
Always put the condition on the same line as the if
/unless
in a
multi-line conditional.
[link]
if
some_condition
do_something
do_something_else
end
if some_condition
do_something
do_something_else
end
-
Favor the ternary operator(?:
) over if/then/else/end
constructs.
It's more common and obviously more concise.
[link]
result = if some_condition then something else something_else end
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.
[link]
some_condition ? (nested_condition ? nested_something : nested_something_else) : something_else
if some_condition
nested_condition ? nested_something : nested_something_else
else
something_else
end
-
Do not use if x; ...
. Use the ternary
operator instead.
[link]
result = if some_condition; something else something_else end
result = some_condition ? something : something_else
-
Leverage the fact that if
and case
are expressions which return a
result.
[link]
if condition
result = x
else
result = y
end
result =
if condition
x
else
y
end
-
Use when x then ...
for one-line cases. The alternative syntax when x: ...
has been removed as of Ruby 1.9.
[link]
-
Do not use when x; ...
. See the previous rule.
[link]
-
Use !
instead of not
.
[link]
x = (not something)
x = !something
-
Avoid the use of !!
.
[link]
!!
converts a value to boolean, but you don't need this explicit
conversion in the condition of a control expression; using it only
obscures your intention. If you want to do a nil
check, use nil?
instead.
x = 'test'
if !!x
end
x = 'test'
if x
end
-
The and
and or
keywords are banned. The minimal added readability is just
not worth the high probability of introducing subtle bugs. For boolean
expressions, always use &&
and ||
instead. For flow control, use
if
and unless
; &&
and ||
are also acceptable but less clear.
[link]
ok = got_needed_arguments and arguments_are_valid
document.save or fail(RuntimeError, "Failed to save document!")
ok = got_needed_arguments && arguments_are_valid
fail(RuntimeError, "Failed to save document!") unless document.save
document.save || fail(RuntimeError, "Failed to save document!")
-
Avoid multi-line ?:
(the ternary operator); use if
/unless
instead.
[link]
-
Favor modifier if
/unless
usage when you have a single-line body. Another
good alternative is the usage of control flow &&
/||
.
[link]
if some_condition
do_something
end
do_something if some_condition
some_condition && do_something
-
Avoid modifier if
/unless
usage at the end of a non-trivial multi-line
block.
[link]
10.times do
end if some_condition
if some_condition
10.times do
end
end
-
Avoid nested modifier if
/unless
/while
/until
usage. Favor &&
/||
if
appropriate.
[link]
do_something if other_condition if some_condition
do_something if some_condition && other_condition
-
Favor unless
over if
for negative conditions (or control flow ||
).
[link]
do_something if !some_condition
do_something if not some_condition
do_something unless some_condition
some_condition || do_something
-
Do not use unless
with else
. Rewrite these with the positive case first.
[link]
unless success?
puts 'failure'
else
puts 'success'
end
if success?
puts 'success'
else
puts 'failure'
end
-
Don't use parentheses around the condition of a control expression.
[link]
if (x > 10)
end
if x > 10
end
-
Do not use while/until condition do
for multi-line while/until
.
[link]
while x > 5 do
end
until x > 5 do
end
while x > 5
end
until x > 5
end
-
Favor modifier while/until
usage when you have a single-line body.
[link]
while some_condition
do_something
end
do_something while some_condition
-
Favor until
over while
for negative conditions.
[link]
do_something while !some_condition
do_something until some_condition
-
Use Kernel#loop
instead of while/until
when you need an infinite loop.
[link]
while true
do_something
end
until false
do_something
end
loop do
do_something
end
-
Use Kernel#loop
with break
rather than begin/end/until
or
begin/end/while
for post-loop tests.
[link]
begin
puts val
val += 1
end while val < 0
loop do
puts val
val += 1
break unless val < 0
end
-
Omit the outer braces around an implicit options hash.
[link]
user.set({ name: 'John', age: 45, permissions: { read: true } })
user.set(name: 'John', age: 45, permissions: { read: true })
-
Omit both the outer braces and parentheses for methods that are part of an
internal DSL.
[link]
class Person < ActiveRecord::Base
validates(:name, { presence: true, length: { within: 1..10 } })
validates :name, presence: true, length: { within: 1..10 }
end
-
Use the proc invocation shorthand when the invoked method is the only operation of a block.
[link]
names.map { |name| name.upcase }
names.map(&:upcase)
-
Prefer {...}
over do...end
for single-line blocks. Avoid using {...}
for multi-line blocks (multi-line chaining is always ugly), except in
RSpec source files, e.g., when using before
, let
, subject
, etc. Always use
do...end
for "control flow" and "method definitions" (e.g. in Rakefiles and
certain DSLs). Avoid do...end
when chaining.
[link]
names = %w[Bozhidar Steve Sarah]
names.each do |name|
puts name
end
names.each { |name| puts name }
names.select do |name|
name.start_with?('S')
end.map { |name| name.upcase }
names.select { |name| name.start_with?('S') }.map(&:upcase)
Some will argue that multi-line chaining would look OK with the use of {...},
but they should ask themselves—is this code really readable and can the
blocks' contents be extracted into nifty methods?
-
Consider using explicit block argument to avoid writing block literal that
just passes its arguments to another block. Beware of the performance impact,
though, as the block gets converted to a Proc.
[link]
require 'tempfile'
def with_tmp_dir
Dir.mktmpdir do |tmp_dir|
Dir.chdir(tmp_dir) { |dir| yield dir }
end
end
def with_tmp_dir(&block)
Dir.mktmpdir do |tmp_dir|
Dir.chdir(tmp_dir, &block)
end
end
with_tmp_dir do |dir|
puts "dir is accessible as a parameter and pwd is set: #{dir}"
end
-
Avoid return
where not required for flow of control.
[link]
def some_method(some_arr)
return some_arr.size
end
def some_method(some_arr)
some_arr.size
end
-
Avoid self
where not required. (It is only required when calling a self
write accessor, methods named after reserved words, or overloadable operators.)
[link]
def ready?
if self.last_reviewed_at > self.last_updated_at
self.worker.update(self.content, self.options)
self.status = :in_progress
end
self.status == :verified
end
def ready?
if last_reviewed_at > last_updated_at
worker.update(content, options)
self.status = :in_progress
end
status == :verified
end
-
As a corollary, avoid shadowing methods with local variables unless they are
both equivalent.
[link]
class Foo
attr_accessor :options
def initialize(options)
self.options = options
end
def do_something(options = {})
unless options[:when] == :later
output(self.options[:message])
end
end
def do_something(params = {})
unless params[:when] == :later
output(options[:message])
end
end
end
-
Don't use the return value of =
(an assignment) in conditional expressions
unless the assignment is wrapped in parentheses. This is a fairly popular
idiom among Rubyists that's sometimes referred to as safe assignment in
condition.
[link]
if v = array.grep(/foo/)
do_something(v)
end
if (v = array.grep(/foo/))
do_something(v)
end
v = array.grep(/foo/)
if v
do_something(v)
end
-
Use shorthand self assignment operators whenever applicable.
[link]
x = x + y
x = x * y
x = x**y
x = x / y
x = x || y
x = x && y
x += y
x *= y
x **= y
x /= y
x ||= y
x &&= y
-
Use ||=
to initialize variables only if they're not already initialized.
[link]
name = name ? name : 'Bozhidar'
name = 'Bozhidar' unless name
name ||= 'Bozhidar'
-
Don't use ||=
to initialize boolean variables. (Consider what would happen
if the current value happened to be false
.)
[link]
enabled ||= true
enabled = true if enabled.nil?
-
Use &&=
to preprocess variables that may or may not exist. Using &&=
will change the value only if it exists, removing the need to check its
existence with if
.
[link]
if something
something = something.downcase
end
something = something ? something.downcase : nil
something = something.downcase if something
something = something && something.downcase
something &&= something.downcase
-
Avoid explicit use of the case equality operator ===
. As its name implies
it is meant to be used implicitly by case
expressions and outside of them it
yields some pretty confusing code.
[link]
Array === something
(1..100) === 7
/something/ === some_string
something.is_a?(Array)
(1..100).include?(7)
some_string =~ /something/
-
Do not use eql?
when using ==
will do. The stricter comparison semantics
provided by eql?
are rarely needed in practice.
[link]
'ruby'.eql? some_str
'ruby' == some_str
1.0.eql? x
-
Avoid using Perl-style special variables (like $:
, $;
, etc. ). They are
quite cryptic and their use in anything but one-liner scripts is discouraged.
Use the human-friendly aliases provided by the English
library.
[link]
$:.unshift File.dirname(__FILE__)
require 'English'
$LOAD_PATH.unshift File.dirname(__FILE__)
-
Do not put a space between a method name and the opening parenthesis.
[link]
f (3 + 2) + 1
f(3 + 2) + 1
-
Always run the Ruby interpreter with the -w
option so it will warn you if
you forget either of the rules above!
[link]
-
Do not use nested method definitions, use lambda instead.
Nested method definitions actually produce methods in the same scope
(e.g. class) as the outer method. Furthermore, the "nested method" will be
redefined every time the method containing its definition is invoked.
[link]
def foo(x)
def bar(y)
end
bar(x)
end
def bar(y)
end
def foo(x)
bar(x)
end
def foo(x)
bar = ->(y) { ... }
bar.call(x)
end
-
Use the new lambda literal syntax for single line body blocks. Use the
lambda
method for multi-line blocks.
[link]
l = lambda { |a, b| a + b }
l.call(1, 2)
l = ->(a, b) do
tmp = a * 7
tmp * b / 50
end
l = ->(a, b) { a + b }
l.call(1, 2)
l = lambda do |a, b|
tmp = a * 7
tmp * b / 50
end
-
Don't omit the parameter parentheses when defining a stabby lambda with
parameters.
[link]
l = ->x, y { something(x, y) }
l = ->(x, y) { something(x, y) }
-
Omit the parameter parentheses when defining a stabby lambda with
no parameters.
[link]
l = ->() { something }
l = -> { something }
-
Prefer proc
over Proc.new
.
[link]
p = Proc.new { |n| puts n }
p = proc { |n| puts n }
-
Prefer proc.call()
over proc[]
or proc.()
for both lambdas and procs.
[link]
l = ->(v) { puts v }
l[1]
l = ->(v) { puts v }
l.(1)
l = ->(v) { puts v }
l.call(1)
-
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 and
will suppress their unused variable warnings.
[link]
result = hash.map { |k, v| v + 1 }
def something(x)
unused_var, used_var = something_else(x)
end
result = hash.map { |_k, v| v + 1 }
def something(x)
_unused_var, used_var = something_else(x)
end
result = hash.map { |_, v| v + 1 }
def something(x)
_, used_var = something_else(x)
end
-
Use $stdout/$stderr/$stdin
instead of STDOUT/STDERR/STDIN
.
STDOUT/STDERR/STDIN
are constants, and while you can actually reassign
(possibly to redirect some stream) constants in Ruby, you'll get an
interpreter warning if you do so.
[link]
-
Use warn
instead of $stderr.puts
. Apart from being more concise and
clear, warn
allows you to suppress warnings if you need to (by setting the
warn level to 0 via -W0
).
[link]
-
Favor the use of sprintf
and its alias format
over the fairly cryptic
String#%
method.
[link]
'%d %d' % [20, 10]
sprintf('%d %d', 20, 10)
sprintf('%{first} %{second}', first: 20, second: 10)
format('%d %d', 20, 10)
format('%{first} %{second}', first: 20, second: 10)
-
Favor the use of Array#join
over the fairly cryptic Array#*
with
a string argument.
[link]
%w[one two three] * ', '
%w[one two three].join(', ')
-
Use Array()
instead of explicit Array
check or [*var]
, when dealing
with a variable you want to treat as an Array, but you're not certain it's an
array.
[link]
paths = [paths] unless paths.is_a? Array
paths.each { |path| do_something(path) }
[*paths].each { |path| do_something(path) }
Array(paths).each { |path| do_something(path) }
-
Use ranges or Comparable#between?
instead of complex comparison logic when
possible.
[link]
do_something if x >= 1000 && x <= 2000
do_something if (1000..2000).include?(x)
do_something if x.between?(1000, 2000)
-
Favor the use of predicate methods to explicit comparisons with ==
.
Numeric comparisons are OK.
[link]
if x % 2 == 0
end
if x % 2 == 1
end
if x == nil
end
if x.even?
end
if x.odd?
end
if x.nil?
end
if x.zero?
end
if x == 0
end
-
Don't do explicit non-nil
checks unless you're dealing with boolean
values.
[link]
do_something if !something.nil?
do_something if something != nil
do_something if something
def value_set?
!@some_boolean.nil?
end
-
Avoid the use of BEGIN
blocks.
[link]
-
Do not use END
blocks. Use Kernel#at_exit
instead.
[link]
END { puts 'Goodbye!' }
at_exit { puts 'Goodbye!' }
-
Avoid the use of flip-flops.
[link]
-
Avoid use of nested conditionals for flow of control.
[link]
Prefer a guard clause when you can assert invalid data. A guard clause
is a conditional statement at the top of a function that bails out as
soon as it can.
def compute_thing(thing)
if thing[:foo]
update_with_bar(thing[:foo])
if thing[:foo][:bar]
partial_compute(thing)
else
re_compute(thing)
end
end
end
def compute_thing(thing)
return unless thing[:foo]
update_with_bar(thing[:foo])
return re_compute(thing) unless thing[:foo][:bar]
partial_compute(thing)
end
Prefer next
in loops instead of conditional blocks.
[0, 1, 2, 3].each do |item|
if item > 1
puts item
end
end
[0, 1, 2, 3].each do |item|
next unless item > 1
puts item
end
-
Prefer map
over collect
, find
over detect
, select
over find_all
,
reduce
over inject
and size
over length
. This is not a hard
requirement; if the use of the alias enhances readability, it's ok to use it.
The rhyming methods are inherited from Smalltalk and are not common in other
programming languages. The reason the use of select
is encouraged over
find_all
is that it goes together nicely with reject
and its name is
pretty self-explanatory.
[link]
-
Don't use count
as a substitute for size
. For Enumerable
objects other
than Array
it will iterate the entire collection in order to determine its
size.
[link]
some_hash.count
some_hash.size
-
Use flat_map
instead of map
+ flatten
. This does not apply for arrays
with a depth greater than 2, i.e. if users.first.songs == ['a', ['b','c']]
,
then use map + flatten
rather than flat_map
. flat_map
flattens the
array by 1, whereas flatten
flattens it all the way.
[link]
all_songs = users.map(&:songs).flatten.uniq
all_songs = users.flat_map(&:songs).uniq
-
Prefer reverse_each
to reverse.each
because some classes that include Enumerable
will provide an efficient implementation. Even in the worst case
where a class does not provide a specialized implementation, the general
implementation inherited from Enumerable
will be at least as efficient as
using reverse.each
.
[link]
array.reverse.each { ... }
array.reverse_each { ... }
-
Name identifiers in English.
[link]
заплата = 1_000
zaplata = 1_000
salary = 1_000
-
Use snake_case
for symbols, methods and variables.
[link]
:'some symbol'
:SomeSymbol
:someSymbol
someVar = 5
var_10 = 10
def someMethod
end
def SomeMethod
end
:some_symbol
some_var = 5
var10 = 10
def some_method
end
-
Do not separate numbers from letters on symbols, methods and variables.
[link]
:some_sym_1
some_var_1 = 1
def some_method_1
end
:some_sym1
some_var1 = 1
def some_method1
end
-
Use CamelCase
for classes and modules. (Keep acronyms like HTTP, RFC, XML
uppercase.)
[link]
class Someclass
end
class Some_Class
end
class SomeXml
end
class XmlSomething
end
class SomeClass
end
class SomeXML
end
class XMLSomething
end
-
Use snake_case
for naming files, e.g. hello_world.rb
.
[link]
-
Use snake_case
for naming directories, e.g.
lib/hello_world/hello_world.rb
.
[link]
-
Aim to have just a single class/module per source file. Name the file name
as the class/module, but replacing CamelCase with snake_case.
[link]
-
Use SCREAMING_SNAKE_CASE
for other constants.
[link]
SomeConst = 5
SOME_CONST = 5
-
The names of predicate methods (methods that return a boolean value) should
end in a question mark. (i.e. Array#empty?
). Methods that don't return a
boolean, shouldn't end in a question mark.
[link]
-
Avoid prefixing predicate methods with the auxiliary verbs such as is
,
does
, or can
. These words are redundant and inconsistent with the style of
boolean methods in the Ruby core library, such as empty?
and include?
.
[link]
class Person
def is_tall?
true
end
def can_play_basketball?
false
end
def does_like_candy?
true
end
end
class Person
def tall?
true
end
def basketball_player?
false
end
def likes_candy?
true
end
end
-
The names of potentially dangerous methods (i.e. methods that modify
self
or the arguments, exit!
(doesn't run the finalizers like exit
does), etc.) should end with an exclamation mark if there exists a safe
version of that dangerous method.
[link]
class Person
def update!
end
end
class Person
def update
end
end
class Person
def update!
end
def update
end
end
-
Define the non-bang (safe) method in terms of the bang (dangerous) one if
possible.
[link]
class Array
def flatten_once!
res = []
each do |e|
[*e].each { |f| res << f }
end
replace(res)
end
def flatten_once
dup.flatten_once!
end
end
-
When defining binary operators, name the parameter other
(<<
and []
are
exceptions to the rule, since their semantics are different).
[link]
def +(other)
end
-
Use a consistent structure in your class definitions.
[link]
class Person
extend SomeModule
include AnotherModule
CustomError = Class.new(StandardError)
SOME_CONSTANT = 20
attr_reader :name
validates :name
def self.some_method
end
def initialize
end
def some_method
end
protected
def some_protected_method
end
private
def some_private_method
end
end
-
Split multiple mixins into separate statements.
[link]
class Person
include Foo, Bar
end
class Person
include Foo
include Bar
end
-
Don't nest multi-line classes within classes. Try to have such nested
classes each in their own file in a folder named like the containing class.
[link]
class Foo
class Bar
end
class Car
end
end
class Foo
end
class Foo
class Bar
end
end
class Foo
class Car
end
end
-
Prefer modules to classes with only class methods. Classes should be used
only when it makes sense to create instances out of them.
[link]
class SomeClass
def self.some_method
end
def self.some_other_method
end
end
module SomeModule
module_function
def some_method
end
def some_other_method
end
end
-
Favor the use of module_function
over extend self
when you want to turn
a module's instance methods into class methods.
[link]
module Utilities
extend self
def parse_something(string)
end
def other_utility_method(number, string)
end
end
module Utilities
module_function
def parse_something(string)
end
def other_utility_method(number, string)
end
end
-
When designing class hierarchies make sure that they conform to the Liskov
Substitution
Principle.
[link]
-
Try to make your classes as
SOLID as
possible.
[link]
-
Always supply a proper to_s
method for classes that represent domain
objects.
[link]
class Person
attr_reader :first_name, :last_name
def initialize(first_name, last_name)
@first_name = first_name
@last_name = last_name
end
def to_s
"#{@first_name} #{@last_name}"
end
end
-
Use the attr
family of functions to define trivial accessors or mutators.
[link]
class Person
def initialize(first_name, last_name)
@first_name = first_name
@last_name = last_name
end
def first_name
@first_name
end
def last_name
@last_name
end
end
class Person
attr_reader :first_name, :last_name
def initialize(first_name, last_name)
@first_name = first_name
@last_name = last_name
end
end
-
For accessors and mutators, avoid prefixing method names with
get_
and set_
.
It is a Ruby convention to use attribute names for accessors (readers) and
attr_name=
for mutators (writers).
[link]
class Person
def get_name
"#{@first_name} #{@last_name}"
end
def set_name(name)
@first_name, @last_name = name.split(' ')
end
end
class Person
def name
"#{@first_name} #{@last_name}"
end
def name=(name)
@first_name, @last_name = name.split(' ')
end
end
-
Avoid the use of attr
. Use attr_reader
and attr_accessor
instead.
[link]
attr :something, true
attr :one, :two, :three
attr_accessor :something
attr_reader :one, :two, :three
-
Consider using Struct.new
, which defines the trivial accessors,
constructor and comparison operators for you.
[link]
class Person
attr_accessor :first_name, :last_name
def initialize(first_name, last_name)
@first_name = first_name
@last_name = last_name
end
end
Person = Struct.new(:first_name, :last_name) do
end
-
Don't extend an instance initialized by Struct.new
. Extending it introduces
a superfluous class level and may also introduce weird errors if the file is
required multiple times.
[link]
class Person < Struct.new(:first_name, :last_name)
end
Person = Struct.new(:first_name, :last_name)
-
Consider adding factory methods to provide additional sensible ways to
create instances of a particular class.
[link]
class Person
def self.create(options_hash)
end
end
-
Prefer duck-typing over
inheritance.
[link]
class Animal
def speak
end
end
class Duck < Animal
def speak
puts 'Quack! Quack'
end
end
class Dog < Animal
def speak
puts 'Bau! Bau!'
end
end
class Duck
def speak
puts 'Quack! Quack'
end
end
class Dog
def speak
puts 'Bau! Bau!'
end
end
-
Avoid the usage of class (@@
) variables due to their "nasty" behavior in
inheritance.
[link]
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
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.
-
Assign proper visibility levels to methods (private
, protected
) in
accordance with their intended usage. Don't go off leaving everything public
(which is the default). After all we're coding in Ruby now, not in Python.
[link]
-
Indent the public
, protected
, and private
methods as much as the method
definitions they apply to. Leave one blank line above the visibility modifier
and one blank line below in order to emphasize that it applies to all methods
below it.
[link]
class SomeClass
def public_method
end
private
def private_method
end
def another_private_method
end
end
-
Use def self.method
to define class methods. This makes the code
easier to refactor since the class name is not repeated.
[link]
class TestClass
def TestClass.some_method
end
def self.some_other_method
end
class << self
def first_method
end
def second_method_etc
end
end
end
-
Prefer alias
when aliasing methods in lexical class scope as the
resolution of self
in this context is also lexical, and it communicates
clearly to the user that the indirection of your alias will not be altered
at runtime or by any subclass unless made explicit.
[link]
class Westerner
def first_name
@names.first
end
alias given_name first_name
end
Since alias
, like def
, is a keyword, prefer bareword arguments over
symbols or strings. In other words, do alias foo bar
, not
alias :foo :bar
.
Also be aware of how Ruby handles aliases and inheritance: an alias
references the method that was resolved at the time the alias was defined;
it is not dispatched dynamically.
class Fugitive < Westerner
def first_name
'Nobody'
end
end
In this example, Fugitive#given_name
would still call the original
Westerner#first_name
method, not Fugitive#first_name
. To override the
behavior of Fugitive#given_name
as well, you'd have to redefine it in the
derived class.
class Fugitive < Westerner
def first_name
'Nobody'
end
alias given_name first_name
end
-
Always use alias_method
when aliasing methods of modules, classes, or
singleton classes at runtime, as the lexical scope of alias
leads to
unpredictability in these cases.
[link]
module Mononymous
def self.included(other)
other.class_eval { alias_method :full_name, :given_name }
end
end
class Sting < Westerner
include Mononymous
end
-
When class (or module) methods call other such methods, omit the use of a
leading self
or own name followed by a .
when calling other such methods.
This is often seen in "service classes" or other similar concepts where a
class is treated as though it were a function. This convention tends to reduce
repetitive boilerplate in such classes.
[link]
class TestClass
def self.call(param1, param2)
TestClass.new(param1).call(param2)
end
def self.call(param1, param2)
self.new(param1).call(param2)
end
def self.call(param1, param2)
new(param1).call(param2)
end
end
-
Prefer raise
over fail
for exceptions.
[link]
fail SomeException, 'message'
raise SomeException, 'message'
-
Don't specify RuntimeError
explicitly in the two argument version of
raise
.
[link]
raise RuntimeError, 'message'
raise 'message'
-
Prefer supplying an exception class and a message as two separate arguments
to raise
, instead of an exception instance.
[link]
raise SomeException.new('message')
raise SomeException, 'message'
-
Do not return from an ensure
block. If you explicitly return from a method
inside an ensure
block, the return will take precedence over any exception
being raised, and the method will return as if no exception had been raised at
all. In effect, the exception will be silently thrown away.
[link]
def foo
raise
ensure
return 'very bad idea'
end
-
Use implicit begin blocks where possible.
[link]
def foo
begin
rescue
end
end
def foo
rescue
end
-
Mitigate the proliferation of begin
blocks by using contingency methods
(a term coined by Avdi Grimm).
[link]
begin
something_that_might_fail
rescue IOError
end
begin
something_else_that_might_fail
rescue IOError
end
def with_io_error_handling
yield
rescue IOError
end
with_io_error_handling { something_that_might_fail }
with_io_error_handling { something_else_that_might_fail }
-
Don't suppress exceptions.
[link]
begin
rescue SomeError
end
do_something rescue nil
-
Avoid using rescue
in its modifier form.
[link]
read_file rescue handle_error($!)
def foo
read_file
rescue Errno::ENOENT => ex
handle_error(ex)
end
-
Don't use exceptions for flow of control.
[link]
begin
n / d
rescue ZeroDivisionError
puts 'Cannot divide by 0!'
end
if d.zero?
puts 'Cannot divide by 0!'
else
n / d
end
-
Avoid rescuing the Exception
class. This will trap signals and calls to
exit
, requiring you to kill -9
the process.
[link]
begin
exit
rescue Exception
puts "you didn't really want to exit, right?"
end
begin
rescue => e
end
begin
rescue StandardError => e
end
-
Put more specific exceptions higher up the rescue chain, otherwise they'll
never be rescued from.
[link]
begin
rescue StandardError => e
rescue IOError => e
end
begin
rescue IOError => e
rescue StandardError => e
end
-
Release external resources obtained by your program in an ensure
block.
[link]
f = File.open('testfile')
begin
rescue
ensure
f.close if f
end
-
Use versions of resource obtaining methods that do automatic
resource cleanup when possible.
[link]
f = File.open('testfile')
f.close
File.open('testfile') do |f|
end
-
Favor the use of exceptions from the standard library over introducing new
exception classes.
[link]
-
Prefer literal array and hash creation notation (unless you need to pass
parameters to their constructors, that is).
[link]
arr = Array.new
hash = Hash.new
arr = []
hash = {}
-
Prefer %w
to the literal array syntax when you need an array of words
(non-empty strings without spaces and special characters in them). Apply this
rule only to arrays with two or more elements.
[link]
STATES = ['draft', 'open', 'closed']
STATES = %w[draft open closed]
-
Prefer %i
to the literal array syntax when you need an array of symbols
(and you don't need to maintain Ruby 1.9 compatibility). Apply this rule only
to arrays with two or more elements.
[link]
STATES = [:draft, :open, :closed]
STATES = %i[draft open closed]
-
Avoid comma after the last item of an Array
or Hash
literal, especially
when the items are not on separate lines.
[link]
VALUES = [
1001,
2020,
3333,
]
VALUES = [1001, 2020, 3333, ]
VALUES = [1001, 2020, 3333]
-
Avoid the creation of huge gaps in arrays.
[link]
arr = []
arr[100] = 1
-
When accessing the first or last element from an array, prefer first
or
last
over [0]
or [-1]
.
[link]
-
Use Set
instead of Array
when dealing with unique elements. Set
implements a collection of unordered values with no duplicates. This is a
hybrid of Array
's intuitive inter-operation facilities and Hash
's fast
lookup.
[link]
-
Prefer symbols instead of strings as hash keys.
[link]
hash = { 'one' => 1, 'two' => 2, 'three' => 3 }
hash = { one: 1, two: 2, three: 3 }
-
Avoid the use of mutable objects as hash keys.
[link]
-
Use the Ruby 1.9 hash literal syntax when your hash keys are symbols.
[link]
hash = { :one => 1, :two => 2, :three => 3 }
hash = { one: 1, two: 2, three: 3 }
-
Don't mix the Ruby 1.9 hash syntax with hash rockets in the same hash
literal. When you've got keys that are not symbols stick to the hash rockets
syntax.
[link]
{ a: 1, 'b' => 2 }
{ :a => 1, 'b' => 2 }
-
Use Hash#key?
instead of Hash#has_key?
and Hash#value?
instead of
Hash#has_value?
.
[link]
hash.has_key?(:test)
hash.has_value?(value)
hash.key?(:test)
hash.value?(value)
-
Use Hash#each_key
instead of Hash#keys.each
and Hash#each_value
instead of Hash#values.each
.
[link]
hash.keys.each { |k| p k }
hash.values.each { |v| p v }
hash.each { |k, _v| p k }
hash.each { |_k, v| p v }
hash.each_key { |k| p k }
hash.each_value { |v| p v }
-
Use Hash#fetch
when dealing with hash keys that should be present.
[link]
heroes = { batman: 'Bruce Wayne', superman: 'Clark Kent' }
heroes[:batman]
heroes[:supermann]
heroes.fetch(:supermann)
-
Introduce default values for hash keys via Hash#fetch
as opposed to using
custom logic.
[link]
batman = { name: 'Bruce Wayne', is_evil: false }
batman[:is_evil] || true
batman.fetch(:is_evil, true)
-
Prefer the use of the block instead of the default value in Hash#fetch
if the code that has to be evaluated may have side effects or be expensive.
[link]
batman = { name: 'Bruce Wayne' }
batman.fetch(:powers, obtain_batman_powers)
batman.fetch(:powers) { obtain_batman_powers }
-
Use Hash#values_at
when you need to retrieve several values consecutively
from a hash.
[link]
email = data['email']
username = data['nickname']
email, username = data.values_at('email', 'nickname')
-
Rely on the fact that as of Ruby 1.9 hashes are ordered.
[link]
-
Do not modify a collection while traversing it.
[link]
-
When accessing elements of a collection, avoid direct access
via [n]
by using an alternate form of the reader method if it is
supplied. This guards you from calling []
on nil
.
[link]
Regexp.last_match[1]
Regexp.last_match(1)
-
When providing an accessor for a collection, provide an alternate form
to save users from checking for nil
before accessing an element in
the collection.
[link]
def awesome_things
@awesome_things
end
def awesome_things(index = nil)
if index && @awesome_things
@awesome_things[index]
else
@awesome_things
end
end
You can financially support bbatsov's original style guide (and RuboCop) with contributions via Gratipay.