Recommended style of grammar usage in Ruby programming, grammar style of ruby programming
Use :: to reference constants (including classes and modules) and constructors (such as Array () or Nokogiri :: HTML ()).
Never use :: to call methods.
# bad
SomeClass :: some_method
some_object :: some_method
# good
SomeClass.some_method
some_object.some_method
SomeModule :: SomeClass :: SOME_CONST
SomeModule :: SomeClass ()
Use brackets to enclose def parameters. Ignore parentheses when the method does not receive any parameters.
# 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 the exact reason for using it. Most of the time iterators can be used instead of for. for is implemented by a set of each (so you are indirectly adding a level), but there is a clue-for does not contain a new scope (unlike each) and the variables defined in its block are also outside Accessible.
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 in multi-line if / unless.
# bad
if some_condition then
# body omitted
end
# good
if some_condition
# body omitted
end
If / unless on multiple lines always put the condition on the same line as if / unless.
# bad
if
some_condition
do_something
do_something_else
end
# good
if some_condition
do_something
do_something_else
end
I like ternary operations (? :) over if / then / else / end structures.
It is 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 to use only one expression under each branch of the ternary operation. This means that ternary operators should not be nested. It is better to use if / else in such situations.
# 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
Don't use if x: ...-it was removed in Ruby 1.9. Use ternary operation arithmetic instead.
# bad
result = if some_condition then something else something_else end
# good
result = some_condition? something: something_else
Don't use if x; .... Use ternary operations instead.
With the fact that if and case are expressions, they return a result.
# bad
if condition
result = x
else
result = y
end
# good
result =
if condition
x
else
y
end
Use when x then ... in one-line cases. The alternative syntax when x: xxx has been removed in Ruby 1.9.
Don't use when x; .... See the rules above.
Use! Instead of not.
# Bad-Because operators have precedence, parentheses are required.
x = (not something)
# good
x =! something
Avoid using !!.
# 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 and or keywords are banned. It's just not worth
it. Always use && and || instead.
The keywords and and or are prohibited. Its name is not true. 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?: (Ternary operator); use if / unless instead.
Single-line subjects like to use if / unless modifiers. Another good way is to use && / || to control the process.
# bad
if some_condition
do_something
end
# good
do_something if some_condition
# another good option
some_condition && do_something
Boolean expressions use && / ||, and / or to control the flow. (Experience Rule: If you must use extra parentheses (expression logic), then you are using the wrong operator.)
# boolean expression
if some_condition && some_other_condition
do_something
end
# control flow
document.save? or document.save!
Avoid multiple lines ?: (ternary operations), use if / unless instead.
I like to use the if / unless modifier in single-line statements. Another good option is to use and / or for process control.
# bad
if some_condition
do_something
end
# good
do_something if some_condition
# another good option
some_condition and do_something
Never use unless and else combinations. Rewrite them into positive conditions.
# bad
unless success?
puts 'failure'
else
puts 'success'
end
# good
if success?
puts 'success'
else
puts 'failure'
end
Don't use brackets to include if / unless / while conditions.
# bad
if (x> 10)
# body omitted
end
# good
if x> 10
# body omitted
end
Do not use while / until condition do in multi-line while / 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
When you have a single line body, try using the while / until modifier.
# bad
while some_condition
do_something
end
# good
do_something while some_condition
Negative condition judgments try to use until instead of while.
# bad
do_something while! some_condition
# good
do_something until some_condition
Post-loop conditional judgments use Kernel # loop and break instead of begin / end / until or begin / end / while.
# bad
begin
puts val
val + = 1
end while val <0
# good
loop do
puts val
val + = 1
break unless val <0
end
Ignore parentheses around internal DSL method parameters (eg Rake, Rails, RSpec)
"Keyword" status methods (such as: attr_reader, puts) and property access methods. All other method calls use parentheses around the parameters.
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
Ignore braces outside the implicit option hash.
# bad
user.set ({name: 'John', age: 45, permissions: {read: true}})
# good
user.set (name: 'John', age: 45, permissions: {read: true})
Outer brackets and braces for internal DSL methods.
class Person <ActiveRecord :: Base
# bad
validates (: name, {presence: true, length: {within: 1..10}})
# good
validates: name, presence: true, length: {within: 1..10}
end
Method calls do not require parameters, so parentheses are ignored.
# bad
Kernel.exit! ()
2.even? ()
fork ()
'test'.upcase ()
# good
Kernel.exit!
2.even?
fork
'test'.upcase
I prefer to use {...} instead of do ... end in a single line of code. Avoid using {...} in multi-line code blocks (multi-line chaining usually becomes very ugly). Usually do ... end is used for flow control and method definition (for example in Rakefiles and some DSLs). Avoid using do ... end in chained calls.
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 people will argue that multi-line chaining looks the same as using {...}, but they ask themselves-such code is really readable and why the contents of the code block cannot be extracted into beautiful 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.
Consider using explicit block parameters to avoid writing block literals that only pass parameters to another block. Be careful of performance impact, even if,
The block is converted to 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 parameter and pwd is set: # {dir}"
end
Avoid using return when flow control is not required.
# bad
def some_method (some_arr)
return some_arr.size
end
# good
def some_method (some_arr)
some_arr.size
end
Avoid using self where it is not needed (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 placing methods (parameters) in the shadow of local variables unless they are equal.
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
Do not use the return value of = (assignment) in a conditional expression unless the conditional expression is assigned in parentheses.
This is a fairly popular ruby dialect, sometimes called a 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 the shortcut self assignment operator wherever possible.
# 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 when they are not initialized.
# set name to Vozhidar, only if it's nil or false
name || = 'Bozhidar'
Do not use || = to initialize Boolean variables. (Think about what happens if the current value is false.)
# bad-would set enabled to true even if it was false
enable || = true
# good
enabled = true if enabled.nil?
Use && = to preprocess variables that are not sure if they exist. Use && = only when (variable) exists
Only change the value, remove the use of if to check its existence.
# 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 the use of the equality === operator. As the name suggests, this is an implicit use of case expressions and use outside of a case statement can produce unintelligible 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's specified variable style (eg, $ :, $; etc.) They are quite mysterious and discourage their use beyond single lines of code.
Use the friendly alias provided by the English library.
# bad
$ :. unshift File.dirname (__ FILE__)
# good
require 'English'
$ LOAD_PATH.unshift File.dirname (__ FILE__)
Never use spaces between method names and (parameter) opening brackets.
# bad
f (3 + 2) + 1
# good
f (3 + 2) +1
If the first parameter of the method starts with an open parenthesis, usually use parentheses to enclose them all. For example, f ((3 + 2) + 1).
The -w option is usually used to run the Ruby interpreter. Ruby will prompt you if you forget the rules mentioned above.
Define single-line blocks using the new lambda syntax. Define multi-line blocks to use lambda method.
# 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
Use proc instead of Proc.new.
# bad
p = Proc.new {| n | puts n}
# good
p = proc {| n | puts n}
Anonymous methods and blocks use proc.call () instead of proc [] or proc. ().
# 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)
Unused block parameters and local variables use _. It is also acceptable to use _ (even if it is less descriptive).
This convention is organized by the Ruby interpreter and tools like RuboCop which will suppress their unused parameter 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. Although constants can be reassigned in Ruby (possibly redirected to a stream), the interpreter will warn you if you insist.
Use warn instead of $ stderr.puts. In addition to being more clear and concise, if you need to,
warn also allows you to suppress warnings (set the warning level to 0 with -W0).
Tend to use sprintf and its alias format instead of the rather obscure String #% 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 '
Tend to use Array # join rather than the rather obscure Array # * that takes strings as parameters.
# bad
% w (one two three) * ','
# => 'one, two, three'
# good
% w (one two three) .join (',')
# => 'one, two, three'
When dealing with variables that you want to treat like Array, but you are not sure it is an array,
Use [* var] or Array () instead of explicit Array check.
# 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)}
Try to use ranges or Comparable # between? To replace complex logical comparisons.
# bad
do_something if x> = 1000 && x <= 2000
# good
do_something if (1000..2000) .include? (x)
# good
do_something if x.between? (1000, 2000)
Try to use the predicate method instead of ==. Except for comparative figures.
# 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
Avoid using BEGIN blocks.
Use Kernel # at_exit. Never use the END block.
# bad
END {puts 'Goodbye!'}
# good
at_exit {puts 'Goodbye!'}
Avoid flip-flops.
Avoid using nested conditions to control the process.
When you may assert illegal data, use a defensive statement. A defensive statement is a conditional statement at the top of a function, so that if the data is illegal, it can jump out of the function as soon as possible.
# 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