Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
259 changes: 259 additions & 0 deletions README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -1421,12 +1421,58 @@ result =

Use `when x then ...` for one-line cases.

[source,ruby]
----
# bad
case year
when 1850..1889
'Blues'
when 1890..1909
'Ragtime'
when 1910..1929
'New Orleans Jazz'
when 1930..1939
'Swing'
when 1940..1950
'Bebop'
else
'Jazz'
end

# good
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
----

NOTE: The alternative syntax `when x: ...` has been removed as of Ruby 1.9.

=== Semicolon in `when` [[no-when-semicolons]]

Do not use `when x; ...`. See the previous rule.

[source,ruby]
----
# bad
case year
when 1850..1889; 'Blues'
when 1890..1909; 'Ragtime'
else; 'Jazz'
end

# good
case year
when 1850..1889 then 'Blues'
when 1890..1909 then 'Ragtime'
else 'Jazz'
end
----

=== Semicolon in `in` [[no-in-pattern-semicolons]]

Do not use `in pattern; ...`. Use `in pattern then ...` for one-line `in` pattern branches.
Expand Down Expand Up @@ -1581,6 +1627,22 @@ false || true && false # => false (it's effectively false || (true && false))

Avoid multi-line `?:` (the ternary operator); use `if`/`unless` instead.

[source,ruby]
----
# bad
result = some_condition ?
something :
something_else

# good
result =
if some_condition
something
else
something_else
end
----

=== `if` as a Modifier [[if-as-a-modifier]]

Prefer modifier `if`/`unless` usage when you have a single-line body.
Expand Down Expand Up @@ -1892,6 +1954,15 @@ end

Avoid the use of `BEGIN` blocks.

[source,ruby]
----
# bad
BEGIN { puts 'Initializing...' }

# good
puts 'Initializing...'
----

=== `END` Blocks [[no-END-blocks]]

Do not use `END` blocks. Use `Kernel#at_exit` instead.
Expand Down Expand Up @@ -3129,6 +3200,18 @@ IMPORTANT: When calling `super` without arguments, `super` and `super()` mean di

Avoid parameter lists longer than three or four parameters.

[source,ruby]
----
# bad
def create_user(first_name, last_name, email, phone, address, age)
# ...
end

# good
def create_user(first_name, last_name, email:, phone: nil, address: nil, age: nil)
# ...
end
----

=== Optional Arguments [[optional-arguments]]

Expand Down Expand Up @@ -3300,6 +3383,23 @@ end

If you really need "global" methods, add them to Kernel and make them private.

[source,ruby]
----
# bad
def global_helper
# ...
end

# good
module Kernel
private

def global_helper
# ...
end
end
----

== Classes & Modules

=== Consistent Classes [[consistent-classes]]
Expand Down Expand Up @@ -4018,6 +4118,15 @@ Write comments in English.

Use one space between the leading `#` character of the comment and the text of the comment.

[source,ruby]
----
# bad
#some comment

# good
# some comment
----

=== English Syntax [[english-syntax]]

Comments longer than a word are capitalized and use punctuation.
Expand Down Expand Up @@ -4338,6 +4447,18 @@ hash = { one: 1, two: 2, three: 3 }

Avoid the use of mutable objects as hash keys.

[source,ruby]
----
# bad
hash = { 'name' => 'John' }

# good
hash = { name: 'John' }

# good - frozen string key when symbols won't do
hash = { 'name'.freeze => 'John' }
----

=== No Mutable Defaults [[no-mutable-defaults]]

Avoid the use of shared mutable objects as hash default values.
Expand Down Expand Up @@ -4571,6 +4692,17 @@ Rely on the fact that as of Ruby 1.9 hashes are ordered.

Do not modify a collection while traversing it.

[source,ruby]
----
# bad
numbers = [1, 2, 3, 4, 5]
numbers.each { |n| numbers.delete(n) if n.even? }

# good
numbers = [1, 2, 3, 4, 5]
odd_numbers = numbers.reject(&:even?)
----

=== Accessing Elements Directly [[accessing-elements-directly]]

When accessing elements of a collection, avoid direct access via `[n]` by using an alternate form of the reader method if it is supplied.
Expand Down Expand Up @@ -4613,6 +4745,25 @@ This is not a hard requirement; if the use of the alias enhances readability, 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.

[source,ruby]
----
# bad
items.collect { |item| item.name }
items.detect(&:active?)
items.find_all(&:valid?)
items.inject(0) { |sum, i| sum + i }
items.member?(value)
items.length

# good
items.map { |item| item.name }
items.find(&:active?)
items.select(&:valid?)
items.reduce(0) { |sum, i| sum + i }
items.include?(value)
items.size
----

=== `count` vs `size` [[count-vs-size]]

Don't use `count` as a substitute for `size`.
Expand Down Expand Up @@ -5270,6 +5421,15 @@ SQL

Prefer `Time.now` over `Time.new` when retrieving the current system time.

[source,ruby]
----
# bad
Time.new

# good
Time.now
----

=== No `DateTime` [[no-datetime]]

Don't use `DateTime` unless you need to account for historical calendar reform - and if you do, explicitly specify the `start` argument to clearly state your intentions.
Expand Down Expand Up @@ -5564,6 +5724,15 @@ echo = %x(echo `date`)
Avoid the use of `%s`.
It seems that the community has decided `:"some string"` is the preferred way to create a symbol with spaces in it.

[source,ruby]
----
# bad
%s(some symbol)

# good
:"some symbol"
----

=== Percent Literal Braces [[percent-literal-braces]]

Use the braces that are the most appropriate for the various kinds of percent literals.
Expand Down Expand Up @@ -5604,10 +5773,44 @@ Use the braces that are the most appropriate for the various kinds of percent li

Avoid needless metaprogramming.

[source,ruby]
----
# bad
class Person
%i[name age email].each do |attr|
define_method(attr) { instance_variable_get("@#{attr}") }
end
end

# good
class Person
attr_reader :name, :age, :email
end
----

=== No Monkey Patching [[no-monkey-patching]]

Do not mess around in core classes when writing libraries (do not monkey-patch them).

[source,ruby]
----
# bad
class String
def to_hierarchical_date
split('-').map(&:to_i)
end
end

# good - use refinements instead
module DateParsing
refine String do
def to_hierarchical_date
split('-').map(&:to_i)
end
end
end
----

=== Block `class_eval` [[block-class-eval]]

The block form of `class_eval` is preferable to the string-interpolated form.
Expand Down Expand Up @@ -6056,6 +6259,21 @@ Write `ruby -w` safe code.
Avoid hashes as optional parameters.
Does the method do too much? (Object initializers are exceptions for this rule).

[source,ruby]
----
# bad
def send_email(subject, opts = {})
to = opts[:to]
cc = opts[:cc]
# ...
end

# good
def send_email(subject, to:, cc: nil)
# ...
end
----

=== Instance Vars [[instance-vars]]

Use module instance variables instead of global variables.
Expand Down Expand Up @@ -6083,10 +6301,51 @@ Use `OptionParser` for parsing complex command line options and `ruby -s` for tr

Do not mutate parameters unless that is the purpose of the method.

[source,ruby]
----
# bad
def clean(users)
users.reject!(&:disabled?)
users
end

# good
def clean(users)
users.reject(&:disabled?)
end
----

=== Three is the Number Thou Shalt Count [[three-is-the-number-thou-shalt-count]]

Avoid more than three levels of block nesting.

[source,ruby]
----
# bad
def process(items)
items.each do |item|
item.widgets.each do |widget|
widget.parts.each do |part|
part.update!
end
end
end
end

# good
def process(items)
items.each do |item|
process_widgets(item.widgets)
end
end

def process_widgets(widgets)
widgets.each do |widget|
widget.parts.each(&:update!)
end
end
----

=== Functional Code [[functional-code]]

Code in a functional way, avoiding mutation when that makes sense.
Expand Down