-
Use UTF-8 only
-
Basically, do not write code that need encoding script comments
Reason
-
UTF-8 is a standard encoding globally.
-
2-bytes characters should not be in source code, they should be in locale files.
- Indentation is 2 white spaces
- Do not use tab
- Do not leave trailing white spaces
- Add 1 white space before and after operators, colon (:), and after comma (,), semi-colon (;)
- Do not add white spaces before comma (,) and semi-colon(;)
sum = 1
a, b = 1, 2
1 > 2 ? true : false; puts 'Hi'
-
Do not write more than 80 characters in a line
-
If the line is more than 80 characters, break to a new line following below rules
- If it is a string of methods, break line before dot
.
and let the dot.
be the start of new line
"one string".something_long_long_method(arg1) .other_cool_long_method(arg2) .another_awsome_long_method(arg3)
- If it is method definition, use
()
to avoid syntax error
def long_method_name(parameter_1, parameter_2, parameter_3, parameter_4, parameter_5, parameter_6, options)
- If it is a string of methods, break line before dot
A line can be more than 80 characters in case it is a long leteral string.
# ok
foo = "This is a very very long string that can't be broken down and may contain #{variable}"
- Do not add white spaces before and after [] () {}
a = [1, 2, 3] #The white space left of `[` is the white space following `=`, not the white space before `[`
[1, 2, 3].each{|num| puts num * 2}
def method(a, b, c)
- Use here document for long string with line breaks. However, we can use literal string when define a short message or method chain.
# good
foo = <<-EOS
From this valley they say you are going,
We will miss your bright eyes and sweet smile,
For they say you are taking the sunshine
That has brightened our pathways a while.
EOS
# ok
foo = "Hi, Johnny.
How are you?"
# bad
foo = "From this valley they say you are going,\nWe will miss your bright eyes and sweet smile,\nFor they say you are taking the sunshine\nThat has brightened our pathways a while."
- Add 1 white space after arguments.
# correct
arr.each{|elem| puts elem}
# incorrect
arr.each{|elem|puts elem}
- Write hash in 1.9 style
# incorrect
h = {:key => :value}
# correct
h = {key: :value}
- Add 1 white space between
do
and argument
# correct
arr.each do |elem|
puts elem
end
# incorrect
arr.each do|elem|
puts elem
end
- Add 1 white space after comment out character
#
# this is a bad comment
# this is a good comment
- Do not write anything in line comment out
=begin
=begin # incorrect
do
something
end
=end
=begin
# correct
do
something
end
=end
- Let indentation of
when
andcase
be the same
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
- Howerver, if left side of
case
has anything, indentation ofwhen
lines will be inside compare withcase
.
foo = 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
- Add 1 white space after
def
def method1
# some proccesses
end
def some_method2
# some proccesses
end
- Do not use
()
in method definition- If parameters of method are too many, break them into new lines to ensure a line has less than 80 characters. In that case we should use
()
to avoid syntax error.
- If parameters of method are too many, break them into new lines to ensure a line has less than 80 characters. In that case we should use
def method1
# some proccesses
end
def method2 arg1, arg2
# some proccesses
end
-
Do not use
()
when calling method. However we can use in below cases- There are operators in parameters, or operators right after method, or paremeter is hash
- Has 2 or more parameters
- There are too many parameters, the line will break to a new line so there are less than 80 characters.
-
Do not use
for
arr = [1, 2, 3]
# incorrect
for elem in arr do
puts elem
end
# correct
arr.each{|elem| puts elem}
- Do not use
then
# incorrect
if some_condition then
# some proccesses
end
# correct
if some_condition
# some proccesses
end
- When using ternary operator / conditional operator (
? :
), all should be written on the same line. Do not useif then else
# correct
weather = sun.shiny? ? 'well' : 'cloud'
# incorrect
weather = sun.shin? ?
'well'
:
'cloud'
# incorrect
weather = if sun.shiny? then 'well' else 'cloud' end # you must also not use 'then' keyword.
- Do not use nested ternary operators
# incorrect
some_condition ? (nested_condition ? nested_something : nested_something_else) : something_else
# correct
if some_condition
nested_condition ? nested_something : nested_something_else
else
something_else
end
-
Use
&&
and||
instead ofand
andor
if possible -
if ~ end
orunless ~ end
can be shorten by puttingif
orunless
at the end of line -
Use short style when it is possible to write less than 80 characters in a line
# incorrect
if some_condition
foo = "This is a short string"
end
# correct
foo = "This is a short string" if some_condition
# incorrect
foo = "This is a very very long string that can not be broken down and may contain #{variable}" unless some_condition
# correct
unless some_condition
foo = "This is a very very long string that can not be broken down and may contain #{variable}"
end
- Do not use
unless
withelse
# incorrect
unless success?
puts 'failure'
else
puts 'success'
end
# correct
if success?
puts 'success'
else
puts 'failure'
end
- Do not use
!
inif
conditional clause (if necessary useunless
). However we can still use!
with&&
or||
. In these cases we can use De Morgan's rules to write simpler.
# bad
if !user.nil?
user.greeting
end
# good
unless user.nil?
user.greeting
end
# better
if user
user.greeting
end
# better
user.greeting if user
# OK
if !user.nil? && !user.suspended?
user.greeting
end
# OK but too complex
unless user.nil? || user.suspended?
user.greeting
end
# should write like this
if user && user.active?
user.greeting
end
- Do not use
()
in conditional clause ofif/unless/while
# incorrect
if (x > 10)
# body omitted
end
# correct
if x > 10
# body omitted
end
- If there is a code block, use
{}
and write in 1 line. In case there are many commands, usedo ~ end
This rule also applies to method chain.
names = ["Bozhidar", "Steve", "Sarah"]
# correct
names.each{|name| puts name}
# incorrect
names.each do |name|
puts name
end
# correct
[1, 2, 3].map{|num| num * 2}.reduce{|double, sum| sum += double}
# also good
[1, 2, 3].map do |num|
num * 2
end.reduce do |double, sum|
sum += double
end
- Remove
return
if possible
# incorrect
def some_method(some_arr)
return some_arr.size
end
# correct
def some_method(some_arr)
some_arr.size
end
- If there is assignment inside conditional clause of
if
, use()
# correct
if (v = array.grep(/foo/)) ...
# incorrect
if v = array.grep(/foo/) ...
# also correct - follow priority order
if (v = next_value) == "hello" ...
Reason
-
Avoid misunderstanding with
==
-
Encourage using
||=
for variable declaration However, with boolean variables, false value will be overwritten
# Assign name to be Bozhidar, only when name is nil or false
name ||= 'Bozhidar'
# incorrect - will set enabled to be true even when it is false
enabled ||= true
# correct
enabled = true if enabled.nil?
- There is no white spaces between method name and arguments
# incorrect
f (3 + 2) + 1
# correct
f(3 + 2) + 1
- Do not use argument in block, use
_
# incorrect
result = hash.map {|k, v| v + 1}
# correct
result = hash.map {|_, v| v + 1}
- Use shorten name of argument to name temporary argument in block
# correct
products.each {|product| product.maintain!}
# OK
products.each {|prod| prod.maintain!}
- Create empty array or empty hash by using
Array.new
,Hash.new
.
# incorrect
@users = []
# correct
@users = Array.new
# also correct
@months_of_birth_date = User.all.inject([]){|months, user| months << user.birth_date.month}
Reason
Clearly show intention of creating a new object
-
Method name or variable name use
snake_case
-
Class name or Module name use
CamelCase
-
Constant use
SCREAMING_SNAKE_CASE
-
Methods which return boolean should add
?
at the end, such asArray#empty?
-
Destroy method or dangerous method should add
!
at the end, such asArray#flatten!
When define destroy method, un-destroy method likeArray#flatten
should be defined as well.
- Avoid using class variables
@@
unless it is really necessary
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 # => output "child"
- Check if class instance variable can be accessed
class Parent
@class_instance_var = 'parent'
def self.print_class_instance_var
puts @class_instance_var
end
end
class Child < Parent
@class_instance_var = 'child'
end
Parent.print_class_var # => output "parent"
- When define singleton method (class method), do not use
def self.method
ordef ClassName.method
class TestClass
# incorrect
def TestClass.some_method
# body omitted
end
# incorrect
def self.some_other_method
# body omitted
end
end
- When define a method or a class macro, use
class << self
class TestClass
class << self
attr_accessor :per_page
alias_method :nwo, :find_by_name_with_owner
def find_by_name_with_owner
# body omitted
end
def first_method
# body omitted
end
def second_method_etc
# body omitted
end
end
end
-
With a block of public methods, no need to declare
public
before like private/protected block below. -
Write
protected
methods beforeprivate
methods. When define protected methods, private methods, indent the methods to be the same as public methods and add an empty line above these protected methods, private methods, do not add an empty line below.
class SomeClass
def public_method
# ...
end
protected
def protected_method
# ...
end
private
def private_method
# ...
end
end
- Use
self
to call these methods
class SomeClass
attr_accessor :message
def set_name name
self.message = "Hi #{name}"
end
def greeting
puts self.message
end
end
- Do not use exception to control the flow. Exceptions which can be avoided should be avoided.
Reason
In normal process, avoid generating StackTrace of exceptions as much as possible.
# incorrect
begin
n / d
rescue ZeroDivisionError
puts "Cannot divide by 0!"
end
# correct
if d.zero?
puts "Cannot divide by 0!"
else
n / d
end
- Do not
rescue
classException
. Mustrescue
a specific class
# incorrect
begin
# Exception caught
rescue
# Process exception
end
# incorrect
begin
# Exception caught
rescue Exception
# Process exception
end
# correct
begin
# Exception caught
rescue XxxException # Specify type of exceptions
# Process exception
end
- Use
%w( )
to create array of strings
# incorrect
STATES = ['draft', 'open', 'closed']
# correct
STATES = %w(draft open closed)
- When write key of hash, use symbol instead of characters if possible
# incorrect
hash = { 'one' => 1, 'two' => 2, 'three' => 3 }
# correct
hash = { one: 1, two: 2, three: 3 }
- When combine variables into a string, follow below rules
# incorrect
email_with_name = user.name + ' <' + user.email + '>'
# correct
email_with_name = "#{user.name} <#{user.email}>"
- Use
"
and\
for strings
# incorrect
name = 'Bozhidar'
# correct
name = "Bozhidar"
- When need to add more into string, do not use
String#+
method, useString#<<
method
# correct
html = ''
html << '<h1>Page title</h1>'
paragraphs.each do |paragraph|
html << "<p>#{paragraph}</p>"
end
- When use here document, delimiter is indented the same as assign command
module AttrComparable
module ClassMethods
def attr_comparable *attrs
class_eval <<-DELIM
attrs.each do |attr|
define_method(attr.to_s<<'?'){|param| self.send(attr) == param }
end
DELIM
end
end
#...omitted
- Do not use
$1 〜 9
to name string
# incorrect
/(regexp)/ =~ string
...
process $1
# correct
/(?<meaningful_var>regexp)/ =~ string
...
process meaningful_var
- To define start and end of a string, including new lines, use
\A
and\Z
string = "some injection\nusername"
string[/^username$/] # matches
string[/\Ausername\Z/] # don't match
- Use
x
when writing a complex regular expression. However, all empty characters will be ignored.
regexp = %r{
start # some text
\s # white space char
(group) # first group
(?:alt1|alt2) # some alternation
end
}x
- Use
%()
when need to display"
message = %() (please differenate between ``` ' ``` and ``` " ```)
- Use
%r()
when need to write/
in regular expression
# incorrect
%r(\s+)
# incorrect
%r(^/(.*)$)
# should write as /^\/(.*)$/
# correct
%r(^/blog/2011/(.*)$)
- When need to compare between a variable and a value like a number or a constant, write variable on the right side
greeting = "Hello!"
# bad
if greeting == "Hola!"
...
end
# good
if "Hola!" == greeting
...
end
Reason
If mistakenly write ==
to be =
, the comparison will return SyntaxError
To format the year part of a date as yyyy
, use %Y
.
- Do not use
__END___