To add a collaborator to this project you will need to use the Relish gem to add the collaborator via a terminal command. Soon you'll be able to also add collaborators here!
More about adding a collaboratorsyntax
Use
::
only to reference constants(this includes classes and
modules) and constructors (likeArray()
orNokogiri::HTML()
).
Never use::
for regular method invocation.# bad SomeClass::some_method some_object::some_method # good SomeClass.some_method some_object.some_method SomeModule::SomeClass::SOME_CONST SomeModule::SomeClass()
Use
def
with parentheses when there are arguments. Omit the
parentheses when the method doesn't accept any arguments.# bad def some_method() # body omitted end # good def some_method # body omitted end # bad def some_method_with_arguments arg1, arg2 # body omitted end # good def some_method_with_arguments(arg1, arg2) # body omitted end
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 # note that elem is accessible outside of the for loop elem #=> 3 # good arr.each { |elem| puts elem } # elem is not accessible outside each's block elem #=> NameError: undefined local variable or method `elem'
Never use
then
for multi-lineif/unless
.# bad if some_condition then # body omitted end # good if some_condition # body omitted end
Always put the condition on the same line as the
if
/unless
in a multi-line conditional.# bad if some_condition do_something do_something_else end # good if some_condition do_something do_something_else end
Favor the ternary operator(
?:
) overif/then/else/end
constructs.
It's more common and obviously more concise.# 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
Never use
if x: ...
- as of Ruby 1.9 it has been removed. Use
the ternary operator instead.# bad result = if some_condition: something else something_else end # good result = some_condition ? something : something_else
Never use
if x; ...
. Use the ternary operator instead.Leverage the fact that
if
andcase
are expressions which return a result.# bad if condition result = x else result = y end # good 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.Never use
when x; ...
. See the previous rule.Use
!
instead ofnot
.# bad - braces are required because of op precedence x = (not something) # good x = !something
Avoid the use of
!!
.# bad x = 'test' # obscure nil check if !!x # body omitted end x = false # double negation is useless on booleans !!x # => false # good x = 'test' unless x.nil? # body omitted end
The
and
andor
keywords are banned. It's just not worth
it. Always use&&
and||
instead.# bad # boolean expression if some_condition and some_other_condition do_something end # control flow document.saved? or document.save! # good # boolean expression if some_condition && some_other_condition do_something end # control flow document.saved? || document.save!
Avoid multi-line
?:
(the ternary operator); useif/unless
instead.Favor modifier
if/unless
usage when you have a single-line
body. Another good alternative is the usage of control flow&&/||
.# bad if some_condition do_something end # good do_something if some_condition # another good option some_condition && do_something
Avoid modifier
if/unless
usage at the end of a
non-trivial multi-line block.# bad 10.times do # multi-line body omitted end if some_condition # good if some_condition 10.times do # multi-line body omitted end end
Favor
unless
overif
for negative conditions (or control
flow||
).# bad do_something if !some_condition # bad do_something if not some_condition # good do_something unless some_condition # another good option some_condition || do_something
Never use
unless
withelse
. Rewrite these with the positive case first.# bad unless success? puts 'failure' else puts 'success' end # good if success? puts 'success' else puts 'failure' end
Don't use parentheses around the condition of an
if/unless/while/until
.# bad if (x > 10) # body omitted end # good if x > 10 # body omitted end
Never use
while/until condition do
for multi-linewhile/until
.# bad while x > 5 do # body omitted end until x > 5 do # body omitted end # good while x > 5 # body omitted end until x > 5 # body omitted end
Favor modifier
while/until
usage when you have a single-line
body.# bad while some_condition do_something end # good do_something while some_condition
Favor
until
overwhile
for negative conditions.# bad do_something while !some_condition # good do_something until some_condition
Use
Kernel#loop
instead ofwhile/until
when you need an infinite loop.# bad while true do_something end until false do_something end # good loop do do_something end
Use
Kernel#loop
withbreak
rather thanbegin/end/until
orbegin/end/while
for post-loop tests.# bad begin puts val val += 1 end while val < 0 # good loop do puts val val += 1 break unless val < 0 end
Omit parentheses around parameters for methods that are part of an
internal DSL (e.g. Rake, Rails, RSpec), methods that have
"keyword" status in Ruby (e.g.attr_reader
,puts
) and attribute
access methods. Use parentheses around the arguments of all other
method invocations.class Person attr_reader :name, :age # omitted end temperance = Person.new('Temperance', 30) temperance.name puts temperance.age x = Math.sin(y) array.delete(e) bowling.score.should == 0
Omit the outer braces around an implicit options hash.
# bad user.set({ name: 'John', age: 45, permissions: { read: true } }) # good 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.class Person < ActiveRecord::Base # bad validates(:name, { presence: true, length: { within: 1..10 } }) # good validates :name, presence: true, length: { within: 1..10 } end
Omit parentheses for method calls with no arguments.
# bad Kernel.exit!() 2.even?() fork() 'test'.upcase() # good Kernel.exit! 2.even? fork 'test'.upcase
Prefer
{...}
overdo...end
for single-line blocks. Avoid using
{...}
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 }
Some will argue that multiline 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.require 'tempfile' # bad def with_tmp_dir Dir.mktmpdir do |tmp_dir| Dir.chdir(tmp_dir) { |dir| yield dir } # block just passes arguments end end # good 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.# bad def some_method(some_arr) return some_arr.size end # good def some_method(some_arr) some_arr.size end
Avoid
self
where not required. (It is only required when calling a self write accessor.)# bad 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 # good 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.
class Foo attr_accessor :options # ok def initialize(options) self.options = options # both options and self.options are equivalent here end # bad def do_something(options = {}) unless options[:when] == :later output(self.options[:message]) end end # good 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.# bad (+ a warning) if v = array.grep(/foo/) do_something(v) ... end # good (MRI would still complain, but RuboCop won't) if (v = array.grep(/foo/)) do_something(v) ... end # good v = array.grep(/foo/) if v do_something(v) ... end
Use shorthand self assignment operators whenever applicable.
# bad x = x + y x = x * y x = x**y x = x / y x = x || y x = x && y # good x += y x *= y x **= y x /= y x ||= y x &&= y
Use
||=
to initialize variables only if they're not already initialized.# bad name = name ? name : 'Bozhidar' # bad name = 'Bozhidar' unless name # good - set name to Bozhidar, only if it's nil or false name ||= 'Bozhidar'
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?
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 withif
.# bad if something something = something.downcase end # bad something = something ? nil : something.downcase # ok something = something.downcase if something # good something = something && something.downcase # better something &&= something.downcase
Avoid explicit use of the case equality operator
===
. As its name
implies it is meant to be used implicitly bycase
expressions and
outside of them it yields some pretty confusing code.# bad Array === something (1..100) === 7 /something/ === some_string # good something.is_a?(Array) (1..100).include?(7) some_string =~ /something/
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 theEnglish
library.# bad $:.unshift File.dirname(__FILE__) # good require 'English' $LOAD_PATH.unshift File.dirname(__FILE__)
Never put a space between a method name and the opening parenthesis.
# bad f (3 + 2) + 1 # good f(3 + 2) + 1
If the first argument to a method begins with an open parenthesis,
always use parentheses in the method invocation. For example, write
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!Use the new lambda literal syntax for single line body blocks. Use the
lambda
method for multi-line blocks.# bad l = lambda { |a, b| a + b } l.call(1, 2) # correct, but looks extremely awkward l = ->(a, b) do tmp = a * 7 tmp * b / 50 end # good l = ->(a, b) { a + b } l.call(1, 2) l = lambda do |a, b| tmp = a * 7 tmp * b / 50 end
Prefer
proc
overProc.new
.# bad p = Proc.new { |n| puts n } # good p = proc { |n| puts n }
Prefer
proc.call()
overproc[]
orproc.()
for both lambdas and procs.# bad - looks similar to Enumeration access l = ->(v) { puts v } l[1] # also bad - uncommon syntax l = ->(v) { puts v } l.(1) # good 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.# bad result = hash.map { |k, v| v + 1 } def something(x) unused_var, used_var = something_else(x) # ... end # good result = hash.map { |_k, v| v + 1 } def something(x) _unused_var, used_var = something_else(x) # ... end # good 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.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
).Favor the use of
sprintf
and its aliasformat
over the fairly
crypticString#%
method.# bad '%d %d' % [20, 10] # => '20 10' # good sprintf('%d %d', 20, 10) # => '20 10' # good sprintf('%{first} %{second}', first: 20, second: 10) # => '20 10' format('%d %d', 20, 10) # => '20 10' # good format('%{first} %{second}', first: 20, second: 10) # => '20 10'
Favor the use of
Array#join
over the fairly crypticArray#*
with
a string argument.# bad %w(one two three) * ', ' # => 'one, two, three' # good %w(one two three).join(', ') # => 'one, two, three'
Use
[*var]
orArray()
instead of explicitArray
check, when dealing with a
variable you want to treat as an Array, but you're not certain it's
an array.# bad paths = [paths] unless paths.is_a? Array paths.each { |path| do_something(path) } # good [*paths].each { |path| do_something(path) } # good (and a bit more readable) Array(paths).each { |path| do_something(path) }
Use ranges or
Comparable#between?
instead of complex comparison logic when possible.# bad do_something if x >= 1000 && x <= 2000 # good do_something if (1000..2000).include?(x) # good do_something if x.between?(1000, 2000)
Favor the use of predicate methods to explicit comparisons with
==
. Numeric comparisons are OK.# bad if x % 2 == 0 end if x % 2 == 1 end if x == nil end # good 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.# bad do_something if !something.nil? do_something if something != nil # good do_something if something # good - dealing with a boolean def value_set? [email protected]_boolean.nil? end
Avoid the use of
BEGIN
blocks.Never use
END
blocks. UseKernel#at_exit
instead.# bad END { puts 'Goodbye!' } # good at_exit { puts 'Goodbye!' }
Avoid the use of flip-flops.
Avoid use of nested conditionals for flow of control.
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.# bad def compute_thing(thing) if thing[:foo] update_with_bar(thing) if thing[:foo][:bar] partial_compute(thing) else re_compute(thing) end end end # good 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.# bad [0, 1, 2, 3].each do |item| if item > 1 puts item end end # good [0, 1, 2, 3].each do |item| next unless item > 1 puts item end
Last published almost 7 years ago by David Kariuki.