Class has too many lines. [255/100] Open
class Exporter
attr_accessor :data
attr_accessor :context
attr_accessor :progression_tracker
- Read upRead up
- Exclude checks
Checks if the length of a class exceeds some maximum value. Comment lines can optionally be ignored. The maximum allowed length is configurable.
You can set constructs you want to fold with CountAsOne
.
Available are: 'array', 'hash', 'heredoc', and 'method_call'. Each construct
will be counted as one line regardless of its actual size.
NOTE: This cop also applies for Struct
definitions.
Example: CountAsOne: ['array', 'heredoc', 'method_call']
class Foo
ARRAY = [ # +1
1,
2
]
HASH = { # +3
key: 'value'
}
MSG = <<~HEREDOC # +1
Heredoc
content.
HEREDOC
foo( # +1
1,
2
)
end # 6 points
Method has too many lines. [34/10] Open
def add_sheet_content(content, wb_styles, sheet)
content[:rows].each_with_index do |row, index|
row_style = []
if row[:styles].is_a?(Array) && row[:styles].any?
row[:styles].each do |style|
- Read upRead up
- Exclude checks
Checks if the length of a method exceeds some maximum value. Comment lines can optionally be allowed. The maximum allowed length is configurable.
You can set constructs you want to fold with CountAsOne
.
Available are: 'array', 'hash', 'heredoc', and 'method_call'. Each construct
will be counted as one line regardless of its actual size.
NOTE: The ExcludedMethods
and IgnoredMethods
configuration is
deprecated and only kept for backwards compatibility.
Please use AllowedMethods
and AllowedPatterns
instead.
By default, there are no methods to allowed.
Example: CountAsOne: ['array', 'heredoc', 'method_call']
def m
array = [ # +1
1,
2
]
hash = { # +3
key: 'value'
}
<<~HEREDOC # +1
Heredoc
content.
HEREDOC
foo( # +1
1,
2
)
end # 6 points
Cyclomatic complexity for add_sheet_content is too high. [25/7] Open
def add_sheet_content(content, wb_styles, sheet)
content[:rows].each_with_index do |row, index|
row_style = []
if row[:styles].is_a?(Array) && row[:styles].any?
row[:styles].each do |style|
- Read upRead up
- Exclude checks
Checks that the cyclomatic complexity of methods is not higher than the configured maximum. The cyclomatic complexity is the number of linearly independent paths through a method. The algorithm counts decision points and adds one.
An if statement (or unless or ?:) increases the complexity by one. An else branch does not, since it doesn't add a decision point. The && operator (or keyword and) can be converted to a nested if statement, and ||/or is shorthand for a sequence of ifs, so they also add one. Loops can be said to have an exit condition, so they add one. Blocks that are calls to builtin iteration methods (e.g. `ary.map{...}) also add one, others are ignored.
def each_child_node(*types) # count begins: 1
unless block_given? # unless: +1
return to_enum(__method__, *types)
children.each do |child| # each{}: +1
next unless child.is_a?(Node) # unless: +1
yield child if types.empty? || # if: +1, ||: +1
types.include?(child.type)
end
self
end # total: 6
Method add_sheet_content
has a Cognitive Complexity of 26 (exceeds 5 allowed). Consider refactoring. Open
def add_sheet_content(content, wb_styles, sheet)
content[:rows].each_with_index do |row, index|
row_style = []
if row[:styles].is_a?(Array) && row[:styles].any?
row[:styles].each do |style|
- Read upRead up
Cognitive Complexity
Cognitive Complexity is a measure of how difficult a unit of code is to intuitively understand. Unlike Cyclomatic Complexity, which determines how difficult your code will be to test, Cognitive Complexity tells you how difficult your code will be to read and comprehend.
A method's cognitive complexity is based on a few simple rules:
- Code is not considered more complex when it uses shorthand that the language provides for collapsing multiple statements into one
- Code is considered more complex for each "break in the linear flow of the code"
- Code is considered more complex when "flow breaking structures are nested"
Further reading
Perceived complexity for add_sheet_content is too high. [25/8] Open
def add_sheet_content(content, wb_styles, sheet)
content[:rows].each_with_index do |row, index|
row_style = []
if row[:styles].is_a?(Array) && row[:styles].any?
row[:styles].each do |style|
- Read upRead up
- Exclude checks
Tries to produce a complexity score that's a measure of the
complexity the reader experiences when looking at a method. For that
reason it considers when
nodes as something that doesn't add as much
complexity as an if
or a &&
. Except if it's one of those special
case
/when
constructs where there's no expression after case
. Then
the cop treats it as an if
/elsif
/elsif
... and lets all the when
nodes count. In contrast to the CyclomaticComplexity cop, this cop
considers else
nodes as adding complexity.
Example:
def my_method # 1
if cond # 1
case var # 2 (0.8 + 4 * 0.2, rounded)
when 1 then func_one
when 2 then func_two
when 3 then func_three
when 4..10 then func_other
end
else # 1
do_something until a && b # 2
end # ===
end # 7 complexity points
Method has too many lines. [24/10] Open
def resolve_header_row(headers, index)
row = { values: [], styles: [], merge_cells: [], height: nil }
return row unless headers
col_index = 1
- Read upRead up
- Exclude checks
Checks if the length of a method exceeds some maximum value. Comment lines can optionally be allowed. The maximum allowed length is configurable.
You can set constructs you want to fold with CountAsOne
.
Available are: 'array', 'hash', 'heredoc', and 'method_call'. Each construct
will be counted as one line regardless of its actual size.
NOTE: The ExcludedMethods
and IgnoredMethods
configuration is
deprecated and only kept for backwards compatibility.
Please use AllowedMethods
and AllowedPatterns
instead.
By default, there are no methods to allowed.
Example: CountAsOne: ['array', 'heredoc', 'method_call']
def m
array = [ # +1
1,
2
]
hash = { # +3
key: 'value'
}
<<~HEREDOC # +1
Heredoc
content.
HEREDOC
foo( # +1
1,
2
)
end # 6 points
Method has too many lines. [23/10] Open
def format_value(resolver, record)
styles = []
type = nil
if resolver.is_a?(Proc)
value = resolver.call(record)
- Read upRead up
- Exclude checks
Checks if the length of a method exceeds some maximum value. Comment lines can optionally be allowed. The maximum allowed length is configurable.
You can set constructs you want to fold with CountAsOne
.
Available are: 'array', 'hash', 'heredoc', and 'method_call'. Each construct
will be counted as one line regardless of its actual size.
NOTE: The ExcludedMethods
and IgnoredMethods
configuration is
deprecated and only kept for backwards compatibility.
Please use AllowedMethods
and AllowedPatterns
instead.
By default, there are no methods to allowed.
Example: CountAsOne: ['array', 'heredoc', 'method_call']
def m
array = [ # +1
1,
2
]
hash = { # +3
key: 'value'
}
<<~HEREDOC # +1
Heredoc
content.
HEREDOC
foo( # +1
1,
2
)
end # 6 points
Method has too many lines. [22/10] Open
def list_data_validation_for_column(list_config)
if list_config.is_a?(Array)
return {
type: :list,
formula1: "\"#{list_config.join(', ')}\""
- Read upRead up
- Exclude checks
Checks if the length of a method exceeds some maximum value. Comment lines can optionally be allowed. The maximum allowed length is configurable.
You can set constructs you want to fold with CountAsOne
.
Available are: 'array', 'hash', 'heredoc', and 'method_call'. Each construct
will be counted as one line regardless of its actual size.
NOTE: The ExcludedMethods
and IgnoredMethods
configuration is
deprecated and only kept for backwards compatibility.
Please use AllowedMethods
and AllowedPatterns
instead.
By default, there are no methods to allowed.
Example: CountAsOne: ['array', 'heredoc', 'method_call']
def m
array = [ # +1
1,
2
]
hash = { # +3
key: 'value'
}
<<~HEREDOC # +1
Heredoc
content.
HEREDOC
foo( # +1
1,
2
)
end # 6 points
Method has too many lines. [18/10] Open
def resolve_record_row(schema, record, index)
row = { values: [], styles: [], merge_cells: [], height: nil, types: [] }
col_index = 1
schema.each do |column|
next unless column_is_visible?(column, record)
- Read upRead up
- Exclude checks
Checks if the length of a method exceeds some maximum value. Comment lines can optionally be allowed. The maximum allowed length is configurable.
You can set constructs you want to fold with CountAsOne
.
Available are: 'array', 'hash', 'heredoc', and 'method_call'. Each construct
will be counted as one line regardless of its actual size.
NOTE: The ExcludedMethods
and IgnoredMethods
configuration is
deprecated and only kept for backwards compatibility.
Please use AllowedMethods
and AllowedPatterns
instead.
By default, there are no methods to allowed.
Example: CountAsOne: ['array', 'heredoc', 'method_call']
def m
array = [ # +1
1,
2
]
hash = { # +3
key: 'value'
}
<<~HEREDOC # +1
Heredoc
content.
HEREDOC
foo( # +1
1,
2
)
end # 6 points
Method has too many lines. [17/10] Open
def content
content = { rows: [] }
index = 0
(schema[:extra_headers] || []).each_with_index do |header|
index += 1
- Read upRead up
- Exclude checks
Checks if the length of a method exceeds some maximum value. Comment lines can optionally be allowed. The maximum allowed length is configurable.
You can set constructs you want to fold with CountAsOne
.
Available are: 'array', 'hash', 'heredoc', and 'method_call'. Each construct
will be counted as one line regardless of its actual size.
NOTE: The ExcludedMethods
and IgnoredMethods
configuration is
deprecated and only kept for backwards compatibility.
Please use AllowedMethods
and AllowedPatterns
instead.
By default, there are no methods to allowed.
Example: CountAsOne: ['array', 'heredoc', 'method_call']
def m
array = [ # +1
1,
2
]
hash = { # +3
key: 'value'
}
<<~HEREDOC # +1
Heredoc
content.
HEREDOC
foo( # +1
1,
2
)
end # 6 points
File exporter.rb
has 260 lines of code (exceeds 250 allowed). Consider refactoring. Open
require 'caxlsx'
module NtqExcelsior
class Exporter
attr_accessor :data
Class Exporter
has 21 methods (exceeds 20 allowed). Consider refactoring. Open
class Exporter
attr_accessor :data
attr_accessor :context
attr_accessor :progression_tracker
Cyclomatic complexity for list_data_validation_for_column is too high. [11/7] Open
def list_data_validation_for_column(list_config)
if list_config.is_a?(Array)
return {
type: :list,
formula1: "\"#{list_config.join(', ')}\""
- Read upRead up
- Exclude checks
Checks that the cyclomatic complexity of methods is not higher than the configured maximum. The cyclomatic complexity is the number of linearly independent paths through a method. The algorithm counts decision points and adds one.
An if statement (or unless or ?:) increases the complexity by one. An else branch does not, since it doesn't add a decision point. The && operator (or keyword and) can be converted to a nested if statement, and ||/or is shorthand for a sequence of ifs, so they also add one. Loops can be said to have an exit condition, so they add one. Blocks that are calls to builtin iteration methods (e.g. `ary.map{...}) also add one, others are ignored.
def each_child_node(*types) # count begins: 1
unless block_given? # unless: +1
return to_enum(__method__, *types)
children.each do |child| # each{}: +1
next unless child.is_a?(Node) # unless: +1
yield child if types.empty? || # if: +1, ||: +1
types.include?(child.type)
end
self
end # total: 6
Perceived complexity for list_data_validation_for_column is too high. [11/8] Open
def list_data_validation_for_column(list_config)
if list_config.is_a?(Array)
return {
type: :list,
formula1: "\"#{list_config.join(', ')}\""
- Read upRead up
- Exclude checks
Tries to produce a complexity score that's a measure of the
complexity the reader experiences when looking at a method. For that
reason it considers when
nodes as something that doesn't add as much
complexity as an if
or a &&
. Except if it's one of those special
case
/when
constructs where there's no expression after case
. Then
the cop treats it as an if
/elsif
/elsif
... and lets all the when
nodes count. In contrast to the CyclomaticComplexity cop, this cop
considers else
nodes as adding complexity.
Example:
def my_method # 1
if cond # 1
case var # 2 (0.8 + 4 * 0.2, rounded)
when 1 then func_one
when 2 then func_two
when 3 then func_three
when 4..10 then func_other
end
else # 1
do_something until a && b # 2
end # ===
end # 7 complexity points
Cyclomatic complexity for resolve_header_row is too high. [9/7] Open
def resolve_header_row(headers, index)
row = { values: [], styles: [], merge_cells: [], height: nil }
return row unless headers
col_index = 1
- Read upRead up
- Exclude checks
Checks that the cyclomatic complexity of methods is not higher than the configured maximum. The cyclomatic complexity is the number of linearly independent paths through a method. The algorithm counts decision points and adds one.
An if statement (or unless or ?:) increases the complexity by one. An else branch does not, since it doesn't add a decision point. The && operator (or keyword and) can be converted to a nested if statement, and ||/or is shorthand for a sequence of ifs, so they also add one. Loops can be said to have an exit condition, so they add one. Blocks that are calls to builtin iteration methods (e.g. `ary.map{...}) also add one, others are ignored.
def each_child_node(*types) # count begins: 1
unless block_given? # unless: +1
return to_enum(__method__, *types)
children.each do |child| # each{}: +1
next unless child.is_a?(Node) # unless: +1
yield child if types.empty? || # if: +1, ||: +1
types.include?(child.type)
end
self
end # total: 6
Perceived complexity for resolve_header_row is too high. [9/8] Open
def resolve_header_row(headers, index)
row = { values: [], styles: [], merge_cells: [], height: nil }
return row unless headers
col_index = 1
- Read upRead up
- Exclude checks
Tries to produce a complexity score that's a measure of the
complexity the reader experiences when looking at a method. For that
reason it considers when
nodes as something that doesn't add as much
complexity as an if
or a &&
. Except if it's one of those special
case
/when
constructs where there's no expression after case
. Then
the cop treats it as an if
/elsif
/elsif
... and lets all the when
nodes count. In contrast to the CyclomaticComplexity cop, this cop
considers else
nodes as adding complexity.
Example:
def my_method # 1
if cond # 1
case var # 2 (0.8 + 4 * 0.2, rounded)
when 1 then func_one
when 2 then func_two
when 3 then func_three
when 4..10 then func_other
end
else # 1
do_something until a && b # 2
end # ===
end # 7 complexity points
Cyclomatic complexity for get_styles is too high. [8/7] Open
def get_styles(row_styles, cell_styles = [])
row_styles ||= []
return {} if row_styles.length == 0 && cell_styles.length == 0
styles_hash = {}
- Read upRead up
- Exclude checks
Checks that the cyclomatic complexity of methods is not higher than the configured maximum. The cyclomatic complexity is the number of linearly independent paths through a method. The algorithm counts decision points and adds one.
An if statement (or unless or ?:) increases the complexity by one. An else branch does not, since it doesn't add a decision point. The && operator (or keyword and) can be converted to a nested if statement, and ||/or is shorthand for a sequence of ifs, so they also add one. Loops can be said to have an exit condition, so they add one. Blocks that are calls to builtin iteration methods (e.g. `ary.map{...}) also add one, others are ignored.
def each_child_node(*types) # count begins: 1
unless block_given? # unless: +1
return to_enum(__method__, *types)
children.each do |child| # each{}: +1
next unless child.is_a?(Node) # unless: +1
yield child if types.empty? || # if: +1, ||: +1
types.include?(child.type)
end
self
end # total: 6
Method resolve_header_row
has a Cognitive Complexity of 12 (exceeds 5 allowed). Consider refactoring. Open
def resolve_header_row(headers, index)
row = { values: [], styles: [], merge_cells: [], height: nil }
return row unless headers
col_index = 1
- Read upRead up
Cognitive Complexity
Cognitive Complexity is a measure of how difficult a unit of code is to intuitively understand. Unlike Cyclomatic Complexity, which determines how difficult your code will be to test, Cognitive Complexity tells you how difficult your code will be to read and comprehend.
A method's cognitive complexity is based on a few simple rules:
- Code is not considered more complex when it uses shorthand that the language provides for collapsing multiple statements into one
- Code is considered more complex for each "break in the linear flow of the code"
- Code is considered more complex when "flow breaking structures are nested"
Further reading
Method add_sheet_content
has 34 lines of code (exceeds 25 allowed). Consider refactoring. Open
def add_sheet_content(content, wb_styles, sheet)
content[:rows].each_with_index do |row, index|
row_style = []
if row[:styles].is_a?(Array) && row[:styles].any?
row[:styles].each do |style|
Method format_value
has a Cognitive Complexity of 7 (exceeds 5 allowed). Consider refactoring. Open
def format_value(resolver, record)
styles = []
type = nil
if resolver.is_a?(Proc)
value = resolver.call(record)
- Read upRead up
Cognitive Complexity
Cognitive Complexity is a measure of how difficult a unit of code is to intuitively understand. Unlike Cyclomatic Complexity, which determines how difficult your code will be to test, Cognitive Complexity tells you how difficult your code will be to read and comprehend.
A method's cognitive complexity is based on a few simple rules:
- Code is not considered more complex when it uses shorthand that the language provides for collapsing multiple statements into one
- Code is considered more complex for each "break in the linear flow of the code"
- Code is considered more complex when "flow breaking structures are nested"
Further reading
Method resolve_record_row
has a Cognitive Complexity of 7 (exceeds 5 allowed). Consider refactoring. Open
def resolve_record_row(schema, record, index)
row = { values: [], styles: [], merge_cells: [], height: nil, types: [] }
col_index = 1
schema.each do |column|
next unless column_is_visible?(column, record)
- Read upRead up
Cognitive Complexity
Cognitive Complexity is a measure of how difficult a unit of code is to intuitively understand. Unlike Cyclomatic Complexity, which determines how difficult your code will be to test, Cognitive Complexity tells you how difficult your code will be to read and comprehend.
A method's cognitive complexity is based on a few simple rules:
- Code is not considered more complex when it uses shorthand that the language provides for collapsing multiple statements into one
- Code is considered more complex for each "break in the linear flow of the code"
- Code is considered more complex when "flow breaking structures are nested"
Further reading
Method number_of_headers_row
has a Cognitive Complexity of 7 (exceeds 5 allowed). Consider refactoring. Open
def number_of_headers_row(columns, count = 1)
columns_with_children = columns.select{ |c| c[:children] && c[:children].any? }
return count unless columns_with_children && columns_with_children.size > 0
columns_with_children.each do |column|
- Read upRead up
Cognitive Complexity
Cognitive Complexity is a measure of how difficult a unit of code is to intuitively understand. Unlike Cyclomatic Complexity, which determines how difficult your code will be to test, Cognitive Complexity tells you how difficult your code will be to read and comprehend.
A method's cognitive complexity is based on a few simple rules:
- Code is not considered more complex when it uses shorthand that the language provides for collapsing multiple statements into one
- Code is considered more complex for each "break in the linear flow of the code"
- Code is considered more complex when "flow breaking structures are nested"
Further reading
Method dig_value
has a Cognitive Complexity of 6 (exceeds 5 allowed). Consider refactoring. Open
def dig_value(value, accessors = [])
v = value
return v unless accessors && accessors.length > 0
return v.dig(*accessors) if v.is_a?(Hash)
- Read upRead up
Cognitive Complexity
Cognitive Complexity is a measure of how difficult a unit of code is to intuitively understand. Unlike Cyclomatic Complexity, which determines how difficult your code will be to test, Cognitive Complexity tells you how difficult your code will be to read and comprehend.
A method's cognitive complexity is based on a few simple rules:
- Code is not considered more complex when it uses shorthand that the language provides for collapsing multiple statements into one
- Code is considered more complex for each "break in the linear flow of the code"
- Code is considered more complex when "flow breaking structures are nested"
Further reading
Method content
has a Cognitive Complexity of 6 (exceeds 5 allowed). Consider refactoring. Open
def content
content = { rows: [] }
index = 0
(schema[:extra_headers] || []).each_with_index do |header|
index += 1
- Read upRead up
Cognitive Complexity
Cognitive Complexity is a measure of how difficult a unit of code is to intuitively understand. Unlike Cyclomatic Complexity, which determines how difficult your code will be to test, Cognitive Complexity tells you how difficult your code will be to read and comprehend.
A method's cognitive complexity is based on a few simple rules:
- Code is not considered more complex when it uses shorthand that the language provides for collapsing multiple statements into one
- Code is considered more complex for each "break in the linear flow of the code"
- Code is considered more complex when "flow breaking structures are nested"
Further reading
Assignment Branch Condition size for format_value is too high. [<11, 14, 6> 18.79/17] Open
def format_value(resolver, record)
styles = []
type = nil
if resolver.is_a?(Proc)
value = resolver.call(record)
- Read upRead up
- Exclude checks
Checks that the ABC size of methods is not higher than the configured maximum. The ABC size is based on assignments, branches (method calls), and conditions. See http://c2.com/cgi/wiki?AbcMetric and https://en.wikipedia.org/wiki/ABC_Software_Metric.
Interpreting ABC size:
-
<= 17
satisfactory -
18..30
unsatisfactory -
>
30 dangerous
You can have repeated "attributes" calls count as a single "branch".
For this purpose, attributes are any method with no argument; no attempt
is meant to distinguish actual attr_reader
from other methods.
Example: CountRepeatedAttributes: false (default is true)
# `model` and `current_user`, referenced 3 times each,
# are each counted as only 1 branch each if
# `CountRepeatedAttributes` is set to 'false'
def search
@posts = model.active.visible_by(current_user)
.search(params[:q])
@posts = model.some_process(@posts, current_user)
@posts = model.another_process(@posts, current_user)
render 'pages/search/page'
end
This cop also takes into account AllowedMethods
(defaults to []
)
And AllowedPatterns
(defaults to []
)
Assignment Branch Condition size for add_sheet_content is too high. [<10, 54, 26> 60.76/17] Open
def add_sheet_content(content, wb_styles, sheet)
content[:rows].each_with_index do |row, index|
row_style = []
if row[:styles].is_a?(Array) && row[:styles].any?
row[:styles].each do |style|
- Read upRead up
- Exclude checks
Checks that the ABC size of methods is not higher than the configured maximum. The ABC size is based on assignments, branches (method calls), and conditions. See http://c2.com/cgi/wiki?AbcMetric and https://en.wikipedia.org/wiki/ABC_Software_Metric.
Interpreting ABC size:
-
<= 17
satisfactory -
18..30
unsatisfactory -
>
30 dangerous
You can have repeated "attributes" calls count as a single "branch".
For this purpose, attributes are any method with no argument; no attempt
is meant to distinguish actual attr_reader
from other methods.
Example: CountRepeatedAttributes: false (default is true)
# `model` and `current_user`, referenced 3 times each,
# are each counted as only 1 branch each if
# `CountRepeatedAttributes` is set to 'false'
def search
@posts = model.active.visible_by(current_user)
.search(params[:q])
@posts = model.some_process(@posts, current_user)
@posts = model.another_process(@posts, current_user)
render 'pages/search/page'
end
This cop also takes into account AllowedMethods
(defaults to []
)
And AllowedPatterns
(defaults to []
)
Assignment Branch Condition size for resolve_header_row is too high. [<8, 27, 9> 29.56/17] Open
def resolve_header_row(headers, index)
row = { values: [], styles: [], merge_cells: [], height: nil }
return row unless headers
col_index = 1
- Read upRead up
- Exclude checks
Checks that the ABC size of methods is not higher than the configured maximum. The ABC size is based on assignments, branches (method calls), and conditions. See http://c2.com/cgi/wiki?AbcMetric and https://en.wikipedia.org/wiki/ABC_Software_Metric.
Interpreting ABC size:
-
<= 17
satisfactory -
18..30
unsatisfactory -
>
30 dangerous
You can have repeated "attributes" calls count as a single "branch".
For this purpose, attributes are any method with no argument; no attempt
is meant to distinguish actual attr_reader
from other methods.
Example: CountRepeatedAttributes: false (default is true)
# `model` and `current_user`, referenced 3 times each,
# are each counted as only 1 branch each if
# `CountRepeatedAttributes` is set to 'false'
def search
@posts = model.active.visible_by(current_user)
.search(params[:q])
@posts = model.some_process(@posts, current_user)
@posts = model.another_process(@posts, current_user)
render 'pages/search/page'
end
This cop also takes into account AllowedMethods
(defaults to []
)
And AllowedPatterns
(defaults to []
)
Assignment Branch Condition size for resolve_record_row is too high. [<8, 25, 5> 26.72/17] Open
def resolve_record_row(schema, record, index)
row = { values: [], styles: [], merge_cells: [], height: nil, types: [] }
col_index = 1
schema.each do |column|
next unless column_is_visible?(column, record)
- Read upRead up
- Exclude checks
Checks that the ABC size of methods is not higher than the configured maximum. The ABC size is based on assignments, branches (method calls), and conditions. See http://c2.com/cgi/wiki?AbcMetric and https://en.wikipedia.org/wiki/ABC_Software_Metric.
Interpreting ABC size:
-
<= 17
satisfactory -
18..30
unsatisfactory -
>
30 dangerous
You can have repeated "attributes" calls count as a single "branch".
For this purpose, attributes are any method with no argument; no attempt
is meant to distinguish actual attr_reader
from other methods.
Example: CountRepeatedAttributes: false (default is true)
# `model` and `current_user`, referenced 3 times each,
# are each counted as only 1 branch each if
# `CountRepeatedAttributes` is set to 'false'
def search
@posts = model.active.visible_by(current_user)
.search(params[:q])
@posts = model.some_process(@posts, current_user)
@posts = model.another_process(@posts, current_user)
render 'pages/search/page'
end
This cop also takes into account AllowedMethods
(defaults to []
)
And AllowedPatterns
(defaults to []
)
Assignment Branch Condition size for list_data_validation_for_column is too high. [<6, 18, 10> 21.45/17] Open
def list_data_validation_for_column(list_config)
if list_config.is_a?(Array)
return {
type: :list,
formula1: "\"#{list_config.join(', ')}\""
- Read upRead up
- Exclude checks
Checks that the ABC size of methods is not higher than the configured maximum. The ABC size is based on assignments, branches (method calls), and conditions. See http://c2.com/cgi/wiki?AbcMetric and https://en.wikipedia.org/wiki/ABC_Software_Metric.
Interpreting ABC size:
-
<= 17
satisfactory -
18..30
unsatisfactory -
>
30 dangerous
You can have repeated "attributes" calls count as a single "branch".
For this purpose, attributes are any method with no argument; no attempt
is meant to distinguish actual attr_reader
from other methods.
Example: CountRepeatedAttributes: false (default is true)
# `model` and `current_user`, referenced 3 times each,
# are each counted as only 1 branch each if
# `CountRepeatedAttributes` is set to 'false'
def search
@posts = model.active.visible_by(current_user)
.search(params[:q])
@posts = model.some_process(@posts, current_user)
@posts = model.another_process(@posts, current_user)
render 'pages/search/page'
end
This cop also takes into account AllowedMethods
(defaults to []
)
And AllowedPatterns
(defaults to []
)
Assignment Branch Condition size for content is too high. [<9, 29, 7> 31.16/17] Open
def content
content = { rows: [] }
index = 0
(schema[:extra_headers] || []).each_with_index do |header|
index += 1
- Read upRead up
- Exclude checks
Checks that the ABC size of methods is not higher than the configured maximum. The ABC size is based on assignments, branches (method calls), and conditions. See http://c2.com/cgi/wiki?AbcMetric and https://en.wikipedia.org/wiki/ABC_Software_Metric.
Interpreting ABC size:
-
<= 17
satisfactory -
18..30
unsatisfactory -
>
30 dangerous
You can have repeated "attributes" calls count as a single "branch".
For this purpose, attributes are any method with no argument; no attempt
is meant to distinguish actual attr_reader
from other methods.
Example: CountRepeatedAttributes: false (default is true)
# `model` and `current_user`, referenced 3 times each,
# are each counted as only 1 branch each if
# `CountRepeatedAttributes` is set to 'false'
def search
@posts = model.active.visible_by(current_user)
.search(params[:q])
@posts = model.some_process(@posts, current_user)
@posts = model.another_process(@posts, current_user)
render 'pages/search/page'
end
This cop also takes into account AllowedMethods
(defaults to []
)
And AllowedPatterns
(defaults to []
)
Identical blocks of code found in 2 locations. Consider refactoring. Open
if width > 1
colspan = width - 1
row[:values].push(*Array.new(colspan, nil))
row[:merge_cells].push cells_range([col_index, index], [col_index + colspan, index])
col_index += colspan
- Read upRead up
Duplicated Code
Duplicated code can lead to software that is hard to understand and difficult to change. The Don't Repeat Yourself (DRY) principle states:
Every piece of knowledge must have a single, unambiguous, authoritative representation within a system.
When you violate DRY, bugs and maintenance problems are sure to follow. Duplicated code has a tendency to both continue to replicate and also to diverge (leaving bugs as two similar implementations differ in subtle ways).
Tuning
This issue has a mass of 35.
We set useful threshold defaults for the languages we support but you may want to adjust these settings based on your project guidelines.
The threshold configuration represents the minimum mass a code block must have to be analyzed for duplication. The lower the threshold, the more fine-grained the comparison.
If the engine is too easily reporting duplication, try raising the threshold. If you suspect that the engine isn't catching enough duplication, try lowering the threshold. The best setting tends to differ from language to language.
See codeclimate-duplication
's documentation for more information about tuning the mass threshold in your .codeclimate.yml
.
Refactorings
- Extract Method
- Extract Class
- Form Template Method
- Introduce Null Object
- Pull Up Method
- Pull Up Field
- Substitute Algorithm
Further Reading
- Don't Repeat Yourself on the C2 Wiki
- Duplicated Code on SourceMaking
- Refactoring: Improving the Design of Existing Code by Martin Fowler. Duplicated Code, p76
Identical blocks of code found in 2 locations. Consider refactoring. Open
if width > 1
colspan = width - 1
row[:values].push(*Array.new(colspan, nil))
row[:merge_cells].push cells_range([col_index, index], [col_index + colspan, index])
col_index += colspan
- Read upRead up
Duplicated Code
Duplicated code can lead to software that is hard to understand and difficult to change. The Don't Repeat Yourself (DRY) principle states:
Every piece of knowledge must have a single, unambiguous, authoritative representation within a system.
When you violate DRY, bugs and maintenance problems are sure to follow. Duplicated code has a tendency to both continue to replicate and also to diverge (leaving bugs as two similar implementations differ in subtle ways).
Tuning
This issue has a mass of 35.
We set useful threshold defaults for the languages we support but you may want to adjust these settings based on your project guidelines.
The threshold configuration represents the minimum mass a code block must have to be analyzed for duplication. The lower the threshold, the more fine-grained the comparison.
If the engine is too easily reporting duplication, try raising the threshold. If you suspect that the engine isn't catching enough duplication, try lowering the threshold. The best setting tends to differ from language to language.
See codeclimate-duplication
's documentation for more information about tuning the mass threshold in your .codeclimate.yml
.
Refactorings
- Extract Method
- Extract Class
- Form Template Method
- Introduce Null Object
- Pull Up Method
- Pull Up Field
- Substitute Algorithm
Further Reading
- Don't Repeat Yourself on the C2 Wiki
- Duplicated Code on SourceMaking
- Refactoring: Improving the Design of Existing Code by Martin Fowler. Duplicated Code, p76
Redundant return
detected. Open
return dig_value(v, accessors.slice(1..-1))
- Read upRead up
- Exclude checks
Checks for redundant return
expressions.
Example:
# These bad cases should be extended to handle methods whose body is
# if/else or a case expression with a default branch.
# bad
def test
return something
end
# bad
def test
one
two
three
return something
end
# bad
def test
return something if something_else
end
# good
def test
something if something_else
end
# good
def test
if x
elsif y
else
end
end
Example: AllowMultipleReturnValues: false (default)
# bad
def test
return x, y
end
Example: AllowMultipleReturnValues: true
# good
def test
return x, y
end
Prefer double-quoted strings unless you need single quotes to avoid extra backslashes for escaping. Open
row[:values] << header[:title] || ''
- Read upRead up
- Exclude checks
Checks if uses of quotes match the configured preference.
Example: EnforcedStyle: single_quotes (default)
# bad
"No special symbols"
"No string interpolation"
"Just text"
# good
'No special symbols'
'No string interpolation'
'Just text'
"Wait! What's #{this}!"
Example: EnforcedStyle: double_quotes
# bad
'Just some text'
'No special chars or interpolation'
# good
"Just some text"
"No special chars or interpolation"
"Every string in #{project} uses double_quotes"
Group together all attr_accessor
attributes. Open
attr_accessor :data
- Read upRead up
- Exclude checks
Checks for grouping of accessors in class
and module
bodies.
By default it enforces accessors to be placed in grouped declarations,
but it can be configured to enforce separating them in multiple declarations.
NOTE: If there is a method call before the accessor method it is always allowed as it might be intended like Sorbet.
Example: EnforcedStyle: grouped (default)
# bad
class Foo
attr_reader :bar
attr_reader :bax
attr_reader :baz
end
# good
class Foo
attr_reader :bar, :bax, :baz
end
# good
class Foo
# may be intended comment for bar.
attr_reader :bar
sig { returns(String) }
attr_reader :bax
may_be_intended_annotation :baz
attr_reader :baz
end
Example: EnforcedStyle: separated
# bad
class Foo
attr_reader :bar, :baz
end
# good
class Foo
attr_reader :bar
attr_reader :baz
end
Favor modifier if
usage when having a single-line body. Another good alternative is the usage of control flow &&
/||
. Open
if value.is_a?(String)
- Read upRead up
- Exclude checks
Checks for if
and unless
statements that would fit on one line if
written as modifier if
/unless
. The cop also checks for modifier
if
/unless
lines that exceed the maximum line length.
The maximum line length is configured in the Layout/LineLength
cop. The tab size is configured in the IndentationWidth
of the
Layout/IndentationStyle
cop.
One-line pattern matching is always allowed. To ensure that there are few cases
where the match variable is not used, and to prevent oversights. The variable x
becomes undefined and raises NameError
when the following example is changed to
the modifier form:
if [42] in [x]
x # `x` is undefined when using modifier form.
end
NOTE: It is allowed when defined?
argument has an undefined value,
because using the modifier form causes the following incompatibility:
unless defined?(undefined_foo)
undefined_foo = 'default_value'
end
undefined_foo # => 'default_value'
undefined_bar = 'default_value' unless defined?(undefined_bar)
undefined_bar # => nil
Example:
# bad
if condition
do_stuff(bar)
end
unless qux.empty?
Foo.do_something
end
do_something_with_a_long_name(arg) if long_condition_that_prevents_code_fit_on_single_line
# good
do_stuff(bar) if condition
Foo.do_something unless qux.empty?
if long_condition_that_prevents_code_fit_on_single_line
do_something_with_a_long_name(arg)
end
if short_condition # a long comment that makes it too long if it were just a single line
do_something
end
Prefer double-quoted strings unless you need single quotes to avoid extra backslashes for escaping. Open
format_code: 'dd-mm-yyyy'
- Read upRead up
- Exclude checks
Checks if uses of quotes match the configured preference.
Example: EnforcedStyle: single_quotes (default)
# bad
"No special symbols"
"No string interpolation"
"Just text"
# good
'No special symbols'
'No string interpolation'
'Just text'
"Wait! What's #{this}!"
Example: EnforcedStyle: double_quotes
# bad
'Just some text'
'No special chars or interpolation'
# good
"Just some text"
"No special chars or interpolation"
"Every string in #{project} uses double_quotes"
Avoid comma after the last item of a hash. Open
showInputMessage: list_config[:show_input_message] || false,
- Read upRead up
- Exclude checks
Checks for trailing comma in hash literals. The configuration options are:
-
consistent_comma
: Requires a comma after the last item of all non-empty, multiline hash literals. -
comma
: Requires a comma after the last item in a hash, but only when each item is on its own line. -
no_comma
: Does not require a comma after the last item in a hash
Example: EnforcedStyleForMultiline: consistent_comma
# bad
a = { foo: 1, bar: 2, }
# good
a = { foo: 1, bar: 2 }
# good
a = {
foo: 1, bar: 2,
qux: 3,
}
# good
a = {
foo: 1, bar: 2, qux: 3,
}
# good
a = {
foo: 1,
bar: 2,
}
Example: EnforcedStyleForMultiline: comma
# bad
a = { foo: 1, bar: 2, }
# good
a = { foo: 1, bar: 2 }
# bad
a = {
foo: 1, bar: 2,
qux: 3,
}
# good
a = {
foo: 1, bar: 2,
qux: 3
}
# bad
a = {
foo: 1, bar: 2, qux: 3,
}
# good
a = {
foo: 1, bar: 2, qux: 3
}
# good
a = {
foo: 1,
bar: 2,
}
Example: EnforcedStyleForMultiline: no_comma (default)
# bad
a = { foo: 1, bar: 2, }
# good
a = {
foo: 1,
bar: 2
}
Expected 1 empty line between method definitions; found 0. Open
def styles(value = nil)
- Read upRead up
- Exclude checks
Checks whether class/module/method definitions are separated by one or more empty lines.
NumberOfEmptyLines
can be an integer (default is 1) or
an array (e.g. [1, 2]) to specify a minimum and maximum
number of empty lines permitted.
AllowAdjacentOneLineDefs
configures whether adjacent
one-line definitions are considered an offense.
Example: EmptyLineBetweenMethodDefs: true (default)
# checks for empty lines between method definitions.
# bad
def a
end
def b
end
Example:
# good
def a
end
def b
end
Example: EmptyLineBetweenClassDefs: true (default)
# checks for empty lines between class definitions.
# bad
class A
end
class B
end
def b
end
Example:
# good
class A
end
class B
end
def b
end
Example: EmptyLineBetweenModuleDefs: true (default)
# checks for empty lines between module definitions.
# bad
module A
end
module B
end
def b
end
Example:
# good
module A
end
module B
end
def b
end
Example: AllowAdjacentOneLineDefs: true (default)
# good
class ErrorA < BaseError; end
class ErrorB < BaseError; end
class ErrorC < BaseError; end
# good
class ErrorA < BaseError; end
class ErrorB < BaseError; end
class ErrorC < BaseError; end
Example: AllowAdjacentOneLineDefs: false
# bad
class ErrorA < BaseError; end
class ErrorB < BaseError; end
class ErrorC < BaseError; end
# good
class ErrorA < BaseError; end
class ErrorB < BaseError; end
class ErrorC < BaseError; end
Tab detected in indentation. Open
def initialize(data)
- Read upRead up
- Exclude checks
Checks that the indentation method is consistent. Either tabs only or spaces only are used for indentation.
Example: EnforcedStyle: spaces (default)
# bad
# This example uses a tab to indent bar.
def foo
bar
end
# good
# This example uses spaces to indent bar.
def foo
bar
end
Example: EnforcedStyle: tabs
# bad
# This example uses spaces to indent bar.
def foo
bar
end
# good
# This example uses a tab to indent bar.
def foo
bar
end
Space missing to the left of {. Open
columns_with_children = columns.select{ |c| c[:children] && c[:children].any? }
- Read upRead up
- Exclude checks
Checks that block braces have or don't have a space before the opening brace depending on configuration.
Example: EnforcedStyle: space (default)
# bad
foo.map{ |a|
a.bar.to_s
}
# good
foo.map { |a|
a.bar.to_s
}
Example: EnforcedStyle: no_space
# bad
foo.map { |a|
a.bar.to_s
}
# good
foo.map{ |a|
a.bar.to_s
}
Example: EnforcedStyleForEmptyBraces: space (default)
# bad
7.times{}
# good
7.times {}
Example: EnforcedStyleForEmptyBraces: no_space
# bad
7.times {}
# good
7.times{}
Use next
to skip iteration. Open
if row[:merge_cells]
- Read upRead up
- Exclude checks
Use next
to skip iteration instead of a condition at the end.
Example: EnforcedStyle: skipmodifierifs (default)
# bad
[1, 2].each do |a|
if a == 1
puts a
end
end
# good
[1, 2].each do |a|
next unless a == 1
puts a
end
# good
[1, 2].each do |a|
puts a if a == 1
end
Example: EnforcedStyle: always
# With `always` all conditions at the end of an iteration needs to be
# replaced by next - with `skip_modifier_ifs` the modifier if like
# this one are ignored: `[1, 2].each { |a| puts a if a == 1 }`
# bad
[1, 2].each do |a|
puts a if a == 1
end
# bad
[1, 2].each do |a|
if a == 1
puts a
end
end
# good
[1, 2].each do |a|
next unless a == 1
puts a
end
Use (at % 5).zero?
instead of at % 5 == 0
. Open
progression_tracker.call(at) if at % 5 == 0
- Read upRead up
- Exclude checks
Checks for usage of comparison operators (==
,
>
, <
) to test numbers as zero, positive, or negative.
These can be replaced by their respective predicate methods.
This cop can also be configured to do the reverse.
This cop can be customized allowed methods with AllowedMethods
.
By default, there are no methods to allowed.
This cop disregards #nonzero?
as its value is truthy or falsey,
but not true
and false
, and thus not always interchangeable with
!= 0
.
This cop allows comparisons to global variables, since they are often
populated with objects which can be compared with integers, but are
not themselves Integer
polymorphic.
Safety:
This cop is unsafe because it cannot be guaranteed that the receiver defines the predicates or can be compared to a number, which may lead to a false positive for non-standard classes.
Example: EnforcedStyle: predicate (default)
# bad
foo == 0
0 > foo
bar.baz > 0
# good
foo.zero?
foo.negative?
bar.baz.positive?
Example: EnforcedStyle: comparison
# bad
foo.zero?
foo.negative?
bar.baz.positive?
# good
foo == 0
0 > foo
bar.baz > 0
Example: AllowedMethods: [] (default) with EnforcedStyle: predicate
# bad
foo == 0
0 > foo
bar.baz > 0
Example: AllowedMethods: [==] with EnforcedStyle: predicate
# good
foo == 0
# bad
0 > foo
bar.baz > 0
Example: AllowedPatterns: [] (default) with EnforcedStyle: comparison
# bad
foo.zero?
foo.negative?
bar.baz.positive?
Example: AllowedPatterns: ['zero'] with EnforcedStyle: predicate
# good
# bad
foo.zero?
# bad
foo.negative?
bar.baz.positive?
Use empty?
instead of length == 0
. Open
return {} if row_styles.length == 0 && cell_styles.length == 0
- Read upRead up
- Exclude checks
Checks for numeric comparisons that can be replaced
by a predicate method, such as receiver.length == 0
,
receiver.length > 0
, and receiver.length != 0
,
receiver.length < 1
and receiver.size == 0
that can be
replaced by receiver.empty?
and !receiver.empty?
.
NOTE: File
, Tempfile
, and StringIO
do not have empty?
so allow size == 0
and size.zero?
.
Safety:
This cop is unsafe because it cannot be guaranteed that the receiver
has an empty?
method that is defined in terms of length
. If there
is a non-standard class that redefines length
or empty?
, the cop
may register a false positive.
Example:
# bad
[1, 2, 3].length == 0
0 == "foobar".length
array.length < 1
{a: 1, b: 2}.length != 0
string.length > 0
hash.size > 0
# good
[1, 2, 3].empty?
"foobar".empty?
array.empty?
!{a: 1, b: 2}.empty?
!string.empty?
!hash.empty?
end
at 305, 4 is not aligned with def
at 297, 2. Open
end
- Read upRead up
- Exclude checks
Checks whether the end keywords of method definitions are aligned properly.
Two modes are supported through the EnforcedStyleAlignWith configuration
parameter. If it's set to start_of_line
(which is the default), the
end
shall be aligned with the start of the line where the def
keyword is. If it's set to def
, the end
shall be aligned with the
def
keyword.
Example: EnforcedStyleAlignWith: startofline (default)
# bad
private def foo
end
# good
private def foo
end
Example: EnforcedStyleAlignWith: def
# bad
private def foo
end
# good
private def foo
end
Use (at % 5).zero?
instead of at % 5 == 0
. Open
progression_tracker.call(at) if at % 5 == 0 || index == content[:rows].length - 1
- Read upRead up
- Exclude checks
Checks for usage of comparison operators (==
,
>
, <
) to test numbers as zero, positive, or negative.
These can be replaced by their respective predicate methods.
This cop can also be configured to do the reverse.
This cop can be customized allowed methods with AllowedMethods
.
By default, there are no methods to allowed.
This cop disregards #nonzero?
as its value is truthy or falsey,
but not true
and false
, and thus not always interchangeable with
!= 0
.
This cop allows comparisons to global variables, since they are often
populated with objects which can be compared with integers, but are
not themselves Integer
polymorphic.
Safety:
This cop is unsafe because it cannot be guaranteed that the receiver defines the predicates or can be compared to a number, which may lead to a false positive for non-standard classes.
Example: EnforcedStyle: predicate (default)
# bad
foo == 0
0 > foo
bar.baz > 0
# good
foo.zero?
foo.negative?
bar.baz.positive?
Example: EnforcedStyle: comparison
# bad
foo.zero?
foo.negative?
bar.baz.positive?
# good
foo == 0
0 > foo
bar.baz > 0
Example: AllowedMethods: [] (default) with EnforcedStyle: predicate
# bad
foo == 0
0 > foo
bar.baz > 0
Example: AllowedMethods: [==] with EnforcedStyle: predicate
# good
foo == 0
# bad
0 > foo
bar.baz > 0
Example: AllowedPatterns: [] (default) with EnforcedStyle: comparison
# bad
foo.zero?
foo.negative?
bar.baz.positive?
Example: AllowedPatterns: ['zero'] with EnforcedStyle: predicate
# good
# bad
foo.zero?
# bad
foo.negative?
bar.baz.positive?
Use safe navigation (&.
) instead of checking if an object exists before calling the method. Open
return column[:width].call(context) if column[:width] && column[:width].is_a?(Proc)
- Read upRead up
- Exclude checks
Transforms usages of a method call safeguarded by a non nil
check for the variable whose method is being called to
safe navigation (&.
). If there is a method chain, all of the methods
in the chain need to be checked for safety, and all of the methods will
need to be changed to use safe navigation.
The default for ConvertCodeThatCanStartToReturnNil
is false
.
When configured to true
, this will
check for code in the format !foo.nil? && foo.bar
. As it is written,
the return of this code is limited to false
and whatever the return
of the method is. If this is converted to safe navigation,
foo&.bar
can start returning nil
as well as what the method
returns.
The default for MaxChainLength
is 2
We have limited the cop to not register an offense for method chains
that exceed this option is set.
Safety:
Autocorrection is unsafe because if a value is false
, the resulting
code will have different behavior or raise an error.
x = false
x && x.foo # return false
x&.foo # raises NoMethodError
Example:
# bad
foo.bar if foo
foo.bar.baz if foo
foo.bar(param1, param2) if foo
foo.bar { |e| e.something } if foo
foo.bar(param) { |e| e.something } if foo
foo.bar if !foo.nil?
foo.bar unless !foo
foo.bar unless foo.nil?
foo && foo.bar
foo && foo.bar.baz
foo && foo.bar(param1, param2)
foo && foo.bar { |e| e.something }
foo && foo.bar(param) { |e| e.something }
foo ? foo.bar : nil
foo.nil? ? nil : foo.bar
!foo.nil? ? foo.bar : nil
!foo ? nil : foo.bar
# good
foo&.bar
foo&.bar&.baz
foo&.bar(param1, param2)
foo&.bar { |e| e.something }
foo&.bar(param) { |e| e.something }
foo && foo.bar.baz.qux # method chain with more than 2 methods
foo && foo.nil? # method that `nil` responds to
# Method calls that do not use `.`
foo && foo < bar
foo < bar if foo
# When checking `foo&.empty?` in a conditional, `foo` being `nil` will actually
# do the opposite of what the author intends.
foo && foo.empty?
# This could start returning `nil` as well as the return of the method
foo.nil? || foo.bar
!foo || foo.bar
# Methods that are used on assignment, arithmetic operation or
# comparison should not be converted to use safe navigation
foo.baz = bar if foo
foo.baz + bar if foo
foo.bar > 2 if foo
Trailing whitespace detected. Open
number_of_children = number_of_headers_row(column[:children], count += 1)
- Read upRead up
- Exclude checks
Looks for trailing whitespace in the source code.
Example:
# The line in this example contains spaces after the 0.
# bad
x = 0
# The line in this example ends directly after the 0.
# good
x = 0
Example: AllowInHeredoc: false (default)
# The line in this example contains spaces after the 0.
# bad
code = <<~RUBY
x = 0
RUBY
# ok
code = <<~RUBY
x = 0 #{}
RUBY
# good
trailing_whitespace = ' '
code = <<~RUBY
x = 0#{trailing_whitespace}
RUBY
Example: AllowInHeredoc: true
# The line in this example contains spaces after the 0.
# good
code = <<~RUBY
x = 0
RUBY
Redundant safe navigation detected, use .
instead. Open
if progression_tracker&.is_a?(Proc)
- Read upRead up
- Exclude checks
Checks for redundant safe navigation calls.
Use cases where a constant, named in camel case for classes and modules is nil
are rare,
and an offense is not detected when the receiver is a constant. The detection also applies
to literal receivers, except for nil
.
For all receivers, the instance_of?
, kind_of?
, is_a?
, eql?
, respond_to?
,
and equal?
methods are checked by default.
These are customizable with AllowedMethods
option.
The AllowedMethods
option specifies nil-safe methods,
in other words, it is a method that is allowed to skip safe navigation.
Note that the AllowedMethod
option is not an option that specifies methods
for which to suppress (allow) this cop's check.
In the example below, the safe navigation operator (&.
) is unnecessary
because NilClass
has methods like respond_to?
and is_a?
.
Safety:
This cop is unsafe, because autocorrection can change the return type of
the expression. An offending expression that previously could return nil
will be autocorrected to never return nil
.
Example:
# bad
CamelCaseConst&.do_something
# bad
do_something if attrs&.respond_to?(:[])
# good
do_something if attrs.respond_to?(:[])
# bad
while node&.is_a?(BeginNode)
node = node.parent
end
# good
CamelCaseConst.do_something
# good
while node.is_a?(BeginNode)
node = node.parent
end
# good - without `&.` this will always return `true`
foo&.respond_to?(:to_a)
# bad - for `nil`s conversion methods return default values for the type
foo&.to_h || {}
foo&.to_h { |k, v| [k, v] } || {}
foo&.to_a || []
foo&.to_i || 0
foo&.to_f || 0.0
foo&.to_s || ''
# good
foo.to_h
foo.to_h { |k, v| [k, v] }
foo.to_a
foo.to_i
foo.to_f
foo.to_s
Example: AllowedMethods: [nilsafemethod]
# bad
do_something if attrs&.nil_safe_method(:[])
# good
do_something if attrs.nil_safe_method(:[])
do_something if attrs&.not_nil_safe_method(:[])
Useless assignment to variable - columns
. Open
columns = schema[:columns]
- Read upRead up
- Exclude checks
Checks for every useless assignment to local variable in every
scope.
The basic idea for this cop was from the warning of ruby -cw
:
assigned but unused variable - foo
Currently this cop has advanced logic that detects unreferenced reassignments and properly handles varied cases such as branch, loop, rescue, ensure, etc.
NOTE: Given the assignment foo = 1, bar = 2
, removing unused variables
can lead to a syntax error, so this case is not autocorrected.
Safety:
This cop's autocorrection is unsafe because removing assignment from
operator assignment can cause NameError if this assignment has been used to declare
local variable. For example, replacing a ||= 1
to a || 1
may cause
"undefined local variable or method `a' for main:Object (NameError)".
Example:
# bad
def some_method
some_var = 1
do_something
end
Example:
# good
def some_method
some_var = 1
do_something(some_var)
end
Prefer double-quoted strings unless you need single quotes to avoid extra backslashes for escaping. Open
config[:errorTitle] = list_config[:error_title] || ''
- Read upRead up
- Exclude checks
Checks if uses of quotes match the configured preference.
Example: EnforcedStyle: single_quotes (default)
# bad
"No special symbols"
"No string interpolation"
"Just text"
# good
'No special symbols'
'No string interpolation'
'Just text'
"Wait! What's #{this}!"
Example: EnforcedStyle: double_quotes
# bad
'Just some text'
'No special chars or interpolation'
# good
"Just some text"
"No special chars or interpolation"
"Every string in #{project} uses double_quotes"
Prefer double-quoted strings unless you need single quotes to avoid extra backslashes for escaping. Open
config[:promptTitle] = list_config[:prompt_title] || ''
- Read upRead up
- Exclude checks
Checks if uses of quotes match the configured preference.
Example: EnforcedStyle: single_quotes (default)
# bad
"No special symbols"
"No string interpolation"
"Just text"
# good
'No special symbols'
'No string interpolation'
'Just text'
"Wait! What's #{this}!"
Example: EnforcedStyle: double_quotes
# bad
'Just some text'
'No special chars or interpolation'
# good
"Just some text"
"No special chars or interpolation"
"Every string in #{project} uses double_quotes"
Indent the right brace the same as the first position after the preceding left parenthesis. Open
})
- Read upRead up
- Exclude checks
Checks the indentation of the first key in a hash literal where the opening brace and the first key are on separate lines. The other keys' indentations are handled by the HashAlignment cop.
By default, Hash literals that are arguments in a method call with parentheses, and where the opening curly brace of the hash is on the same line as the opening parenthesis of the method call, shall have their first key indented one step (two spaces) more than the position inside the opening parenthesis.
Other hash literals shall have their first key indented one step more than the start of the line where the opening curly brace is.
This default style is called 'specialinsideparentheses'. Alternative styles are 'consistent' and 'align_braces'. Here are examples:
Example: EnforcedStyle: specialinsideparentheses (default)
# The `special_inside_parentheses` style enforces that the first key
# in a hash literal where the opening brace and the first key are on
# separate lines is indented one step (two spaces) more than the
# position inside the opening parentheses.
# bad
hash = {
key: :value
}
and_in_a_method_call({
no: :difference
})
takes_multi_pairs_hash(x: {
a: 1,
b: 2
},
y: {
c: 1,
d: 2
})
# good
special_inside_parentheses
hash = {
key: :value
}
but_in_a_method_call({
its_like: :this
})
takes_multi_pairs_hash(x: {
a: 1,
b: 2
},
y: {
c: 1,
d: 2
})
Example: EnforcedStyle: consistent
# The `consistent` style enforces that the first key in a hash
# literal where the opening brace and the first key are on
# separate lines is indented the same as a hash literal which is not
# defined inside a method call.
# bad
hash = {
key: :value
}
but_in_a_method_call({
its_like: :this
})
# good
hash = {
key: :value
}
and_in_a_method_call({
no: :difference
})
Example: EnforcedStyle: align_braces
# The `align_brackets` style enforces that the opening and closing
# braces are indented to the same position.
# bad
and_now_for_something = {
completely: :different
}
takes_multi_pairs_hash(x: {
a: 1,
b: 2
},
y: {
c: 1,
d: 2
})
# good
and_now_for_something = {
completely: :different
}
takes_multi_pairs_hash(x: {
a: 1,
b: 2
},
y: {
c: 1,
d: 2
})
Tab detected in indentation. Open
end
- Read upRead up
- Exclude checks
Checks that the indentation method is consistent. Either tabs only or spaces only are used for indentation.
Example: EnforcedStyle: spaces (default)
# bad
# This example uses a tab to indent bar.
def foo
bar
end
# good
# This example uses spaces to indent bar.
def foo
bar
end
Example: EnforcedStyle: tabs
# bad
# This example uses spaces to indent bar.
def foo
bar
end
# good
# This example uses a tab to indent bar.
def foo
bar
end
Use accessors.length.positive?
instead of accessors.length > 0
. Open
return v unless accessors && accessors.length > 0
- Read upRead up
- Exclude checks
Checks for usage of comparison operators (==
,
>
, <
) to test numbers as zero, positive, or negative.
These can be replaced by their respective predicate methods.
This cop can also be configured to do the reverse.
This cop can be customized allowed methods with AllowedMethods
.
By default, there are no methods to allowed.
This cop disregards #nonzero?
as its value is truthy or falsey,
but not true
and false
, and thus not always interchangeable with
!= 0
.
This cop allows comparisons to global variables, since they are often
populated with objects which can be compared with integers, but are
not themselves Integer
polymorphic.
Safety:
This cop is unsafe because it cannot be guaranteed that the receiver defines the predicates or can be compared to a number, which may lead to a false positive for non-standard classes.
Example: EnforcedStyle: predicate (default)
# bad
foo == 0
0 > foo
bar.baz > 0
# good
foo.zero?
foo.negative?
bar.baz.positive?
Example: EnforcedStyle: comparison
# bad
foo.zero?
foo.negative?
bar.baz.positive?
# good
foo == 0
0 > foo
bar.baz > 0
Example: AllowedMethods: [] (default) with EnforcedStyle: predicate
# bad
foo == 0
0 > foo
bar.baz > 0
Example: AllowedMethods: [==] with EnforcedStyle: predicate
# good
foo == 0
# bad
0 > foo
bar.baz > 0
Example: AllowedPatterns: [] (default) with EnforcedStyle: comparison
# bad
foo.zero?
foo.negative?
bar.baz.positive?
Example: AllowedPatterns: ['zero'] with EnforcedStyle: predicate
# good
# bad
foo.zero?
# bad
foo.negative?
bar.baz.positive?
Prefer double-quoted strings unless you need single quotes to avoid extra backslashes for escaping. Open
COLUMN_NAMES = Array('A'..'Z').freeze
- Read upRead up
- Exclude checks
Checks if uses of quotes match the configured preference.
Example: EnforcedStyle: single_quotes (default)
# bad
"No special symbols"
"No string interpolation"
"Just text"
# good
'No special symbols'
'No string interpolation'
'Just text'
"Wait! What's #{this}!"
Example: EnforcedStyle: double_quotes
# bad
'Just some text'
'No special chars or interpolation'
# good
"Just some text"
"No special chars or interpolation"
"Every string in #{project} uses double_quotes"
Prefer double-quoted strings inside interpolations. Open
formula1: "\"#{list_config.join(', ')}\""
- Read upRead up
- Exclude checks
Checks that quotes inside string, symbol, and regexp interpolations match the configured preference.
Example: EnforcedStyle: single_quotes (default)
# bad
string = "Tests #{success ? "PASS" : "FAIL"}"
symbol = :"Tests #{success ? "PASS" : "FAIL"}"
heredoc = <<~TEXT
Tests #{success ? "PASS" : "FAIL"}
TEXT
regexp = /Tests #{success ? "PASS" : "FAIL"}/
# good
string = "Tests #{success ? 'PASS' : 'FAIL'}"
symbol = :"Tests #{success ? 'PASS' : 'FAIL'}"
heredoc = <<~TEXT
Tests #{success ? 'PASS' : 'FAIL'}
TEXT
regexp = /Tests #{success ? 'PASS' : 'FAIL'}/
Example: EnforcedStyle: double_quotes
# bad
string = "Tests #{success ? 'PASS' : 'FAIL'}"
symbol = :"Tests #{success ? 'PASS' : 'FAIL'}"
heredoc = <<~TEXT
Tests #{success ? 'PASS' : 'FAIL'}
TEXT
regexp = /Tests #{success ? 'PASS' : 'FAIL'}/
# good
string = "Tests #{success ? "PASS" : "FAIL"}"
symbol = :"Tests #{success ? "PASS" : "FAIL"}"
heredoc = <<~TEXT
Tests #{success ? "PASS" : "FAIL"}
TEXT
regexp = /Tests #{success ? "PASS" : "FAIL"}/
Prefer double-quoted strings inside interpolations. Open
formula1: "\"#{list_config[:options].join(', ')}\"",
- Read upRead up
- Exclude checks
Checks that quotes inside string, symbol, and regexp interpolations match the configured preference.
Example: EnforcedStyle: single_quotes (default)
# bad
string = "Tests #{success ? "PASS" : "FAIL"}"
symbol = :"Tests #{success ? "PASS" : "FAIL"}"
heredoc = <<~TEXT
Tests #{success ? "PASS" : "FAIL"}
TEXT
regexp = /Tests #{success ? "PASS" : "FAIL"}/
# good
string = "Tests #{success ? 'PASS' : 'FAIL'}"
symbol = :"Tests #{success ? 'PASS' : 'FAIL'}"
heredoc = <<~TEXT
Tests #{success ? 'PASS' : 'FAIL'}
TEXT
regexp = /Tests #{success ? 'PASS' : 'FAIL'}/
Example: EnforcedStyle: double_quotes
# bad
string = "Tests #{success ? 'PASS' : 'FAIL'}"
symbol = :"Tests #{success ? 'PASS' : 'FAIL'}"
heredoc = <<~TEXT
Tests #{success ? 'PASS' : 'FAIL'}
TEXT
regexp = /Tests #{success ? 'PASS' : 'FAIL'}/
# good
string = "Tests #{success ? "PASS" : "FAIL"}"
symbol = :"Tests #{success ? "PASS" : "FAIL"}"
heredoc = <<~TEXT
Tests #{success ? "PASS" : "FAIL"}
TEXT
regexp = /Tests #{success ? "PASS" : "FAIL"}/
Extra empty line detected at class body end. Open
end
- Read upRead up
- Exclude checks
Checks if empty lines around the bodies of classes match the configuration.
Example: EnforcedStyle: noemptylines (default)
# good
class Foo
def bar
# ...
end
end
Example: EnforcedStyle: empty_lines
# good
class Foo
def bar
# ...
end
end
Example: EnforcedStyle: emptylinesexcept_namespace
# good
class Foo
class Bar
# ...
end
end
Example: EnforcedStyle: emptylinesspecial
# good
class Foo
def bar; end
end
Example: EnforcedStyle: beginning_only
# good
class Foo
def bar
# ...
end
end
Example: EnforcedStyle: ending_only
# good
class Foo
def bar
# ...
end
end
Redundant safe navigation detected, use .
instead. Open
if progression_tracker&.is_a?(Proc)
- Read upRead up
- Exclude checks
Checks for redundant safe navigation calls.
Use cases where a constant, named in camel case for classes and modules is nil
are rare,
and an offense is not detected when the receiver is a constant. The detection also applies
to literal receivers, except for nil
.
For all receivers, the instance_of?
, kind_of?
, is_a?
, eql?
, respond_to?
,
and equal?
methods are checked by default.
These are customizable with AllowedMethods
option.
The AllowedMethods
option specifies nil-safe methods,
in other words, it is a method that is allowed to skip safe navigation.
Note that the AllowedMethod
option is not an option that specifies methods
for which to suppress (allow) this cop's check.
In the example below, the safe navigation operator (&.
) is unnecessary
because NilClass
has methods like respond_to?
and is_a?
.
Safety:
This cop is unsafe, because autocorrection can change the return type of
the expression. An offending expression that previously could return nil
will be autocorrected to never return nil
.
Example:
# bad
CamelCaseConst&.do_something
# bad
do_something if attrs&.respond_to?(:[])
# good
do_something if attrs.respond_to?(:[])
# bad
while node&.is_a?(BeginNode)
node = node.parent
end
# good
CamelCaseConst.do_something
# good
while node.is_a?(BeginNode)
node = node.parent
end
# good - without `&.` this will always return `true`
foo&.respond_to?(:to_a)
# bad - for `nil`s conversion methods return default values for the type
foo&.to_h || {}
foo&.to_h { |k, v| [k, v] } || {}
foo&.to_a || []
foo&.to_i || 0
foo&.to_f || 0.0
foo&.to_s || ''
# good
foo.to_h
foo.to_h { |k, v| [k, v] }
foo.to_a
foo.to_i
foo.to_f
foo.to_s
Example: AllowedMethods: [nilsafemethod]
# bad
do_something if attrs&.nil_safe_method(:[])
# good
do_something if attrs.nil_safe_method(:[])
do_something if attrs&.not_nil_safe_method(:[])
Unused block argument - index
. If it's necessary, use _
or _index
as an argument name to indicate that it won't be used. Open
content[:styles]&.each_with_index do |(range, sty), index|
- Read upRead up
- Exclude checks
Checks for unused block arguments.
Example:
# bad
do_something do |used, unused|
puts used
end
do_something do |bar|
puts :foo
end
define_method(:foo) do |bar|
puts :baz
end
# good
do_something do |used, _unused|
puts used
end
do_something do
puts :foo
end
define_method(:foo) do |_bar|
puts :baz
end
Example: IgnoreEmptyBlocks: true (default)
# good
do_something { |unused| }
Example: IgnoreEmptyBlocks: false
# bad
do_something { |unused| }
Example: AllowUnusedKeywordArguments: false (default)
# bad
do_something do |unused: 42|
foo
end
Example: AllowUnusedKeywordArguments: true
# good
do_something do |unused: 42|
foo
end
Use row_styles.length.zero?
instead of row_styles.length == 0
. Open
return {} if row_styles.length == 0 && cell_styles.length == 0
- Read upRead up
- Exclude checks
Checks for usage of comparison operators (==
,
>
, <
) to test numbers as zero, positive, or negative.
These can be replaced by their respective predicate methods.
This cop can also be configured to do the reverse.
This cop can be customized allowed methods with AllowedMethods
.
By default, there are no methods to allowed.
This cop disregards #nonzero?
as its value is truthy or falsey,
but not true
and false
, and thus not always interchangeable with
!= 0
.
This cop allows comparisons to global variables, since they are often
populated with objects which can be compared with integers, but are
not themselves Integer
polymorphic.
Safety:
This cop is unsafe because it cannot be guaranteed that the receiver defines the predicates or can be compared to a number, which may lead to a false positive for non-standard classes.
Example: EnforcedStyle: predicate (default)
# bad
foo == 0
0 > foo
bar.baz > 0
# good
foo.zero?
foo.negative?
bar.baz.positive?
Example: EnforcedStyle: comparison
# bad
foo.zero?
foo.negative?
bar.baz.positive?
# good
foo == 0
0 > foo
bar.baz > 0
Example: AllowedMethods: [] (default) with EnforcedStyle: predicate
# bad
foo == 0
0 > foo
bar.baz > 0
Example: AllowedMethods: [==] with EnforcedStyle: predicate
# good
foo == 0
# bad
0 > foo
bar.baz > 0
Example: AllowedPatterns: [] (default) with EnforcedStyle: comparison
# bad
foo.zero?
foo.negative?
bar.baz.positive?
Example: AllowedPatterns: ['zero'] with EnforcedStyle: predicate
# good
# bad
foo.zero?
# bad
foo.negative?
bar.baz.positive?
Use cell_styles.length.zero?
instead of cell_styles.length == 0
. Open
return {} if row_styles.length == 0 && cell_styles.length == 0
- Read upRead up
- Exclude checks
Checks for usage of comparison operators (==
,
>
, <
) to test numbers as zero, positive, or negative.
These can be replaced by their respective predicate methods.
This cop can also be configured to do the reverse.
This cop can be customized allowed methods with AllowedMethods
.
By default, there are no methods to allowed.
This cop disregards #nonzero?
as its value is truthy or falsey,
but not true
and false
, and thus not always interchangeable with
!= 0
.
This cop allows comparisons to global variables, since they are often
populated with objects which can be compared with integers, but are
not themselves Integer
polymorphic.
Safety:
This cop is unsafe because it cannot be guaranteed that the receiver defines the predicates or can be compared to a number, which may lead to a false positive for non-standard classes.
Example: EnforcedStyle: predicate (default)
# bad
foo == 0
0 > foo
bar.baz > 0
# good
foo.zero?
foo.negative?
bar.baz.positive?
Example: EnforcedStyle: comparison
# bad
foo.zero?
foo.negative?
bar.baz.positive?
# good
foo == 0
0 > foo
bar.baz > 0
Example: AllowedMethods: [] (default) with EnforcedStyle: predicate
# bad
foo == 0
0 > foo
bar.baz > 0
Example: AllowedMethods: [==] with EnforcedStyle: predicate
# good
foo == 0
# bad
0 > foo
bar.baz > 0
Example: AllowedPatterns: [] (default) with EnforcedStyle: comparison
# bad
foo.zero?
foo.negative?
bar.baz.positive?
Example: AllowedPatterns: ['zero'] with EnforcedStyle: predicate
# good
# bad
foo.zero?
# bad
foo.negative?
bar.baz.positive?
Prefer double-quoted strings unless you need single quotes to avoid extra backslashes for escaping. Open
COLUMN_NAMES = Array('A'..'Z').freeze
- Read upRead up
- Exclude checks
Checks if uses of quotes match the configured preference.
Example: EnforcedStyle: single_quotes (default)
# bad
"No special symbols"
"No string interpolation"
"Just text"
# good
'No special symbols'
'No string interpolation'
'Just text'
"Wait! What's #{this}!"
Example: EnforcedStyle: double_quotes
# bad
'Just some text'
'No special chars or interpolation'
# good
"Just some text"
"No special chars or interpolation"
"Every string in #{project} uses double_quotes"
Use !empty?
instead of length > 0
. Open
return v unless accessors && accessors.length > 0
- Read upRead up
- Exclude checks
Checks for numeric comparisons that can be replaced
by a predicate method, such as receiver.length == 0
,
receiver.length > 0
, and receiver.length != 0
,
receiver.length < 1
and receiver.size == 0
that can be
replaced by receiver.empty?
and !receiver.empty?
.
NOTE: File
, Tempfile
, and StringIO
do not have empty?
so allow size == 0
and size.zero?
.
Safety:
This cop is unsafe because it cannot be guaranteed that the receiver
has an empty?
method that is defined in terms of length
. If there
is a non-standard class that redefines length
or empty?
, the cop
may register a false positive.
Example:
# bad
[1, 2, 3].length == 0
0 == "foobar".length
array.length < 1
{a: 1, b: 2}.length != 0
string.length > 0
hash.size > 0
# good
[1, 2, 3].empty?
"foobar".empty?
array.empty?
!{a: 1, b: 2}.empty?
!string.empty?
!hash.empty?
end
at 41, 4 is not aligned with def
at 38, 2. Open
end
- Read upRead up
- Exclude checks
Checks whether the end keywords of method definitions are aligned properly.
Two modes are supported through the EnforcedStyleAlignWith configuration
parameter. If it's set to start_of_line
(which is the default), the
end
shall be aligned with the start of the line where the def
keyword is. If it's set to def
, the end
shall be aligned with the
def
keyword.
Example: EnforcedStyleAlignWith: startofline (default)
# bad
private def foo
end
# good
private def foo
end
Example: EnforcedStyleAlignWith: def
# bad
private def foo
end
# good
private def foo
end
Inconsistent indentation detected. Open
def initialize(data)
@data = data
@data_count = data.size.to_d
end
- Read upRead up
- Exclude checks
Checks for inconsistent indentation.
The difference between indented_internal_methods
and normal
is
that the indented_internal_methods
style prescribes that in
classes and modules the protected
and private
modifier keywords
shall be indented the same as public methods and that protected and
private members shall be indented one step more than the modifiers.
Other than that, both styles mean that entities on the same logical
depth shall have the same indentation.
Example: EnforcedStyle: normal (default)
# bad
class A
def test
puts 'hello'
puts 'world'
end
end
# bad
class A
def test
puts 'hello'
puts 'world'
end
protected
def foo
end
private
def bar
end
end
# good
class A
def test
puts 'hello'
puts 'world'
end
end
# good
class A
def test
puts 'hello'
puts 'world'
end
protected
def foo
end
private
def bar
end
end
Example: EnforcedStyle: indentedinternalmethods
# bad
class A
def test
puts 'hello'
puts 'world'
end
end
# bad
class A
def test
puts 'hello'
puts 'world'
end
protected
def foo
end
private
def bar
end
end
# good
class A
def test
puts 'hello'
puts 'world'
end
end
# good
class A
def test
puts 'hello'
puts 'world'
end
protected
def foo
end
private
def bar
end
end
Use 2 (not 4) spaces for indentation. Open
@data = data
- Read upRead up
- Exclude checks
Checks for indentation that doesn't use the specified number of spaces.
See also the IndentationConsistency cop which is the companion to this one.
Example:
# bad
class A
def test
puts 'hello'
end
end
# good
class A
def test
puts 'hello'
end
end
Example: AllowedPatterns: ['^\s*module']
# bad
module A
class B
def test
puts 'hello'
end
end
end
# good
module A
class B
def test
puts 'hello'
end
end
end
Favor unless
over if
for negative conditions. Open
return true if !column.key?(:visible)
- Read upRead up
- Exclude checks
Checks for uses of if with a negated condition. Only ifs without else are considered. There are three different styles:
- both
- prefix
- postfix
Example: EnforcedStyle: both (default)
# enforces `unless` for `prefix` and `postfix` conditionals
# bad
if !foo
bar
end
# good
unless foo
bar
end
# bad
bar if !foo
# good
bar unless foo
Example: EnforcedStyle: prefix
# enforces `unless` for just `prefix` conditionals
# bad
if !foo
bar
end
# good
unless foo
bar
end
# good
bar if !foo
Example: EnforcedStyle: postfix
# enforces `unless` for just `postfix` conditionals
# bad
bar if !foo
# good
bar unless foo
# good
if !foo
bar
end
Use safe navigation (&.
) instead of checking if an object exists before calling the method. Open
if row[:merge_cells]
row[:merge_cells]&.each do |range|
sheet.merge_cells range
end
end
- Read upRead up
- Exclude checks
Transforms usages of a method call safeguarded by a non nil
check for the variable whose method is being called to
safe navigation (&.
). If there is a method chain, all of the methods
in the chain need to be checked for safety, and all of the methods will
need to be changed to use safe navigation.
The default for ConvertCodeThatCanStartToReturnNil
is false
.
When configured to true
, this will
check for code in the format !foo.nil? && foo.bar
. As it is written,
the return of this code is limited to false
and whatever the return
of the method is. If this is converted to safe navigation,
foo&.bar
can start returning nil
as well as what the method
returns.
The default for MaxChainLength
is 2
We have limited the cop to not register an offense for method chains
that exceed this option is set.
Safety:
Autocorrection is unsafe because if a value is false
, the resulting
code will have different behavior or raise an error.
x = false
x && x.foo # return false
x&.foo # raises NoMethodError
Example:
# bad
foo.bar if foo
foo.bar.baz if foo
foo.bar(param1, param2) if foo
foo.bar { |e| e.something } if foo
foo.bar(param) { |e| e.something } if foo
foo.bar if !foo.nil?
foo.bar unless !foo
foo.bar unless foo.nil?
foo && foo.bar
foo && foo.bar.baz
foo && foo.bar(param1, param2)
foo && foo.bar { |e| e.something }
foo && foo.bar(param) { |e| e.something }
foo ? foo.bar : nil
foo.nil? ? nil : foo.bar
!foo.nil? ? foo.bar : nil
!foo ? nil : foo.bar
# good
foo&.bar
foo&.bar&.baz
foo&.bar(param1, param2)
foo&.bar { |e| e.something }
foo&.bar(param) { |e| e.something }
foo && foo.bar.baz.qux # method chain with more than 2 methods
foo && foo.nil? # method that `nil` responds to
# Method calls that do not use `.`
foo && foo < bar
foo < bar if foo
# When checking `foo&.empty?` in a conditional, `foo` being `nil` will actually
# do the opposite of what the author intends.
foo && foo.empty?
# This could start returning `nil` as well as the return of the method
foo.nil? || foo.bar
!foo || foo.bar
# Methods that are used on assignment, arithmetic operation or
# comparison should not be converted to use safe navigation
foo.baz = bar if foo
foo.baz + bar if foo
foo.bar > 2 if foo
Add empty line after guard clause. Open
return v if accessors.length == 1
- Read upRead up
- Exclude checks
Enforces empty line after guard clause.
This cop allows # :nocov:
directive after guard clause because
SimpleCov excludes code from the coverage report by wrapping it in # :nocov:
:
def foo
# :nocov:
return if condition
# :nocov:
bar
end
Refer to SimpleCov's documentation for more details: https://github.com/simplecov-ruby/simplecov#ignoringskipping-code
Example:
# bad
def foo
return if need_return?
bar
end
# good
def foo
return if need_return?
bar
end
# good
def foo
return if something?
return if something_different?
bar
end
# also good
def foo
if something?
do_something
return if need_return?
end
end
Trailing whitespace detected. Open
value = resolver.call(record)
- Read upRead up
- Exclude checks
Looks for trailing whitespace in the source code.
Example:
# The line in this example contains spaces after the 0.
# bad
x = 0
# The line in this example ends directly after the 0.
# good
x = 0
Example: AllowInHeredoc: false (default)
# The line in this example contains spaces after the 0.
# bad
code = <<~RUBY
x = 0
RUBY
# ok
code = <<~RUBY
x = 0 #{}
RUBY
# good
trailing_whitespace = ' '
code = <<~RUBY
x = 0#{trailing_whitespace}
RUBY
Example: AllowInHeredoc: true
# The line in this example contains spaces after the 0.
# good
code = <<~RUBY
x = 0
RUBY
Method parameter must be at least 3 characters long. Open
def generate_workbook(wb, wb_styles)
- Read upRead up
- Exclude checks
Checks method parameter names for how descriptive they are. It is highly configurable.
The MinNameLength
config option takes an integer. It represents
the minimum amount of characters the name must be. Its default is 3.
The AllowNamesEndingInNumbers
config option takes a boolean. When
set to false, this cop will register offenses for names ending with
numbers. Its default is false. The AllowedNames
config option
takes an array of permitted names that will never register an
offense. The ForbiddenNames
config option takes an array of
restricted names that will always register an offense.
Example:
# bad
def bar(varOne, varTwo)
varOne + varTwo
end
# With `AllowNamesEndingInNumbers` set to false
def foo(num1, num2)
num1 * num2
end
# With `MinNameLength` set to number greater than 1
def baz(a, b, c)
do_stuff(a, b, c)
end
# good
def bar(thud, fred)
thud + fred
end
def foo(speed, distance)
speed * distance
end
def baz(age_a, height_b, gender_c)
do_stuff(age_a, height_b, gender_c)
end
Prefer double-quoted strings unless you need single quotes to avoid extra backslashes for escaping. Open
require 'caxlsx'
- Read upRead up
- Exclude checks
Checks if uses of quotes match the configured preference.
Example: EnforcedStyle: single_quotes (default)
# bad
"No special symbols"
"No string interpolation"
"Just text"
# good
'No special symbols'
'No string interpolation'
'Just text'
"Wait! What's #{this}!"
Example: EnforcedStyle: double_quotes
# bad
'Just some text'
'No special chars or interpolation'
# good
"Just some text"
"No special chars or interpolation"
"Every string in #{project} uses double_quotes"
Prefer double-quoted strings unless you need single quotes to avoid extra backslashes for escaping. Open
config[:prompt] = list_config[:prompt] || ''
- Read upRead up
- Exclude checks
Checks if uses of quotes match the configured preference.
Example: EnforcedStyle: single_quotes (default)
# bad
"No special symbols"
"No string interpolation"
"Just text"
# good
'No special symbols'
'No string interpolation'
'Just text'
"Wait! What's #{this}!"
Example: EnforcedStyle: double_quotes
# bad
'Just some text'
'No special chars or interpolation'
# good
"Just some text"
"No special chars or interpolation"
"Every string in #{project} uses double_quotes"
Use 2 spaces for indentation in a hash, relative to the first position after the preceding left parenthesis. Open
range: cells_range([col_index, index + 1], [col_index, 1_000_000]),
- Read upRead up
- Exclude checks
Checks the indentation of the first key in a hash literal where the opening brace and the first key are on separate lines. The other keys' indentations are handled by the HashAlignment cop.
By default, Hash literals that are arguments in a method call with parentheses, and where the opening curly brace of the hash is on the same line as the opening parenthesis of the method call, shall have their first key indented one step (two spaces) more than the position inside the opening parenthesis.
Other hash literals shall have their first key indented one step more than the start of the line where the opening curly brace is.
This default style is called 'specialinsideparentheses'. Alternative styles are 'consistent' and 'align_braces'. Here are examples:
Example: EnforcedStyle: specialinsideparentheses (default)
# The `special_inside_parentheses` style enforces that the first key
# in a hash literal where the opening brace and the first key are on
# separate lines is indented one step (two spaces) more than the
# position inside the opening parentheses.
# bad
hash = {
key: :value
}
and_in_a_method_call({
no: :difference
})
takes_multi_pairs_hash(x: {
a: 1,
b: 2
},
y: {
c: 1,
d: 2
})
# good
special_inside_parentheses
hash = {
key: :value
}
but_in_a_method_call({
its_like: :this
})
takes_multi_pairs_hash(x: {
a: 1,
b: 2
},
y: {
c: 1,
d: 2
})
Example: EnforcedStyle: consistent
# The `consistent` style enforces that the first key in a hash
# literal where the opening brace and the first key are on
# separate lines is indented the same as a hash literal which is not
# defined inside a method call.
# bad
hash = {
key: :value
}
but_in_a_method_call({
its_like: :this
})
# good
hash = {
key: :value
}
and_in_a_method_call({
no: :difference
})
Example: EnforcedStyle: align_braces
# The `align_brackets` style enforces that the opening and closing
# braces are indented to the same position.
# bad
and_now_for_something = {
completely: :different
}
takes_multi_pairs_hash(x: {
a: 1,
b: 2
},
y: {
c: 1,
d: 2
})
# good
and_now_for_something = {
completely: :different
}
takes_multi_pairs_hash(x: {
a: 1,
b: 2
},
y: {
c: 1,
d: 2
})
Use 2 (not 0) spaces for indentation. Open
def initialize(data)
- Read upRead up
- Exclude checks
Checks for indentation that doesn't use the specified number of spaces.
See also the IndentationConsistency cop which is the companion to this one.
Example:
# bad
class A
def test
puts 'hello'
end
end
# good
class A
def test
puts 'hello'
end
end
Example: AllowedPatterns: ['^\s*module']
# bad
module A
class B
def test
puts 'hello'
end
end
end
# good
module A
class B
def test
puts 'hello'
end
end
end
Use safe navigation (&.
) instead of checking if an object exists before calling the method. Open
columns_with_children = columns.select{ |c| c[:children] && c[:children].any? }
- Read upRead up
- Exclude checks
Transforms usages of a method call safeguarded by a non nil
check for the variable whose method is being called to
safe navigation (&.
). If there is a method chain, all of the methods
in the chain need to be checked for safety, and all of the methods will
need to be changed to use safe navigation.
The default for ConvertCodeThatCanStartToReturnNil
is false
.
When configured to true
, this will
check for code in the format !foo.nil? && foo.bar
. As it is written,
the return of this code is limited to false
and whatever the return
of the method is. If this is converted to safe navigation,
foo&.bar
can start returning nil
as well as what the method
returns.
The default for MaxChainLength
is 2
We have limited the cop to not register an offense for method chains
that exceed this option is set.
Safety:
Autocorrection is unsafe because if a value is false
, the resulting
code will have different behavior or raise an error.
x = false
x && x.foo # return false
x&.foo # raises NoMethodError
Example:
# bad
foo.bar if foo
foo.bar.baz if foo
foo.bar(param1, param2) if foo
foo.bar { |e| e.something } if foo
foo.bar(param) { |e| e.something } if foo
foo.bar if !foo.nil?
foo.bar unless !foo
foo.bar unless foo.nil?
foo && foo.bar
foo && foo.bar.baz
foo && foo.bar(param1, param2)
foo && foo.bar { |e| e.something }
foo && foo.bar(param) { |e| e.something }
foo ? foo.bar : nil
foo.nil? ? nil : foo.bar
!foo.nil? ? foo.bar : nil
!foo ? nil : foo.bar
# good
foo&.bar
foo&.bar&.baz
foo&.bar(param1, param2)
foo&.bar { |e| e.something }
foo&.bar(param) { |e| e.something }
foo && foo.bar.baz.qux # method chain with more than 2 methods
foo && foo.nil? # method that `nil` responds to
# Method calls that do not use `.`
foo && foo < bar
foo < bar if foo
# When checking `foo&.empty?` in a conditional, `foo` being `nil` will actually
# do the opposite of what the author intends.
foo && foo.empty?
# This could start returning `nil` as well as the return of the method
foo.nil? || foo.bar
!foo || foo.bar
# Methods that are used on assignment, arithmetic operation or
# comparison should not be converted to use safe navigation
foo.baz = bar if foo
foo.baz + bar if foo
foo.bar > 2 if foo
Use safe navigation (&.
) instead of checking if an object exists before calling the method. Open
if row[:data_validations]
row[:data_validations].each do |validation|
sheet.add_data_validation(validation[:range], validation[:config])
end
end
- Read upRead up
- Exclude checks
Transforms usages of a method call safeguarded by a non nil
check for the variable whose method is being called to
safe navigation (&.
). If there is a method chain, all of the methods
in the chain need to be checked for safety, and all of the methods will
need to be changed to use safe navigation.
The default for ConvertCodeThatCanStartToReturnNil
is false
.
When configured to true
, this will
check for code in the format !foo.nil? && foo.bar
. As it is written,
the return of this code is limited to false
and whatever the return
of the method is. If this is converted to safe navigation,
foo&.bar
can start returning nil
as well as what the method
returns.
The default for MaxChainLength
is 2
We have limited the cop to not register an offense for method chains
that exceed this option is set.
Safety:
Autocorrection is unsafe because if a value is false
, the resulting
code will have different behavior or raise an error.
x = false
x && x.foo # return false
x&.foo # raises NoMethodError
Example:
# bad
foo.bar if foo
foo.bar.baz if foo
foo.bar(param1, param2) if foo
foo.bar { |e| e.something } if foo
foo.bar(param) { |e| e.something } if foo
foo.bar if !foo.nil?
foo.bar unless !foo
foo.bar unless foo.nil?
foo && foo.bar
foo && foo.bar.baz
foo && foo.bar(param1, param2)
foo && foo.bar { |e| e.something }
foo && foo.bar(param) { |e| e.something }
foo ? foo.bar : nil
foo.nil? ? nil : foo.bar
!foo.nil? ? foo.bar : nil
!foo ? nil : foo.bar
# good
foo&.bar
foo&.bar&.baz
foo&.bar(param1, param2)
foo&.bar { |e| e.something }
foo&.bar(param) { |e| e.something }
foo && foo.bar.baz.qux # method chain with more than 2 methods
foo && foo.nil? # method that `nil` responds to
# Method calls that do not use `.`
foo && foo < bar
foo < bar if foo
# When checking `foo&.empty?` in a conditional, `foo` being `nil` will actually
# do the opposite of what the author intends.
foo && foo.empty?
# This could start returning `nil` as well as the return of the method
foo.nil? || foo.bar
!foo || foo.bar
# Methods that are used on assignment, arithmetic operation or
# comparison should not be converted to use safe navigation
foo.baz = bar if foo
foo.baz + bar if foo
foo.bar > 2 if foo
Use 2 (not 4) spaces for indentation. Open
package = Axlsx::Package.new
- Read upRead up
- Exclude checks
Checks for indentation that doesn't use the specified number of spaces.
See also the IndentationConsistency cop which is the companion to this one.
Example:
# bad
class A
def test
puts 'hello'
end
end
# good
class A
def test
puts 'hello'
end
end
Example: AllowedPatterns: ['^\s*module']
# bad
module A
class B
def test
puts 'hello'
end
end
end
# good
module A
class B
def test
puts 'hello'
end
end
end
Final newline missing. Open
end
- Read upRead up
- Exclude checks
Looks for trailing blank lines and a final newline in the source code.
Example: EnforcedStyle: final_newline (default)
# `final_newline` looks for one newline at the end of files.
# bad
class Foo; end
# EOF
# bad
class Foo; end # EOF
# good
class Foo; end
# EOF
Example: EnforcedStyle: finalblankline
# `final_blank_line` looks for one blank line followed by a new line
# at the end of files.
# bad
class Foo; end
# EOF
# bad
class Foo; end # EOF
# good
class Foo; end
# EOF
Use each
instead of each_with_index
. Open
(schema[:extra_headers] || []).each_with_index do |header|
- Read upRead up
- Exclude checks
Checks for redundant with_index
.
Example:
# bad
ary.each_with_index do |v|
v
end
# good
ary.each do |v|
v
end
# bad
ary.each.with_index do |v|
v
end
# good
ary.each do |v|
v
end
Group together all attr_accessor
attributes. Open
attr_accessor :progression_tracker
- Read upRead up
- Exclude checks
Checks for grouping of accessors in class
and module
bodies.
By default it enforces accessors to be placed in grouped declarations,
but it can be configured to enforce separating them in multiple declarations.
NOTE: If there is a method call before the accessor method it is always allowed as it might be intended like Sorbet.
Example: EnforcedStyle: grouped (default)
# bad
class Foo
attr_reader :bar
attr_reader :bax
attr_reader :baz
end
# good
class Foo
attr_reader :bar, :bax, :baz
end
# good
class Foo
# may be intended comment for bar.
attr_reader :bar
sig { returns(String) }
attr_reader :bax
may_be_intended_annotation :baz
attr_reader :baz
end
Example: EnforcedStyle: separated
# bad
class Foo
attr_reader :bar, :baz
end
# good
class Foo
attr_reader :bar
attr_reader :baz
end
Prefer double-quoted strings unless you need single quotes to avoid extra backslashes for escaping. Open
format_code: 'dd-mm-yyyy hh:mm:ss'
- Read upRead up
- Exclude checks
Checks if uses of quotes match the configured preference.
Example: EnforcedStyle: single_quotes (default)
# bad
"No special symbols"
"No string interpolation"
"Just text"
# good
'No special symbols'
'No string interpolation'
'Just text'
"Wait! What's #{this}!"
Example: EnforcedStyle: double_quotes
# bad
'Just some text'
'No special chars or interpolation'
# good
"Just some text"
"No special chars or interpolation"
"Every string in #{project} uses double_quotes"
Prefer double-quoted strings inside interpolations. Open
"#{lock.include?(:col) ? '$' : ''}#{column_name(col)}#{lock.include?(:row) ? '$' : ''}#{row}"
- Read upRead up
- Exclude checks
Checks that quotes inside string, symbol, and regexp interpolations match the configured preference.
Example: EnforcedStyle: single_quotes (default)
# bad
string = "Tests #{success ? "PASS" : "FAIL"}"
symbol = :"Tests #{success ? "PASS" : "FAIL"}"
heredoc = <<~TEXT
Tests #{success ? "PASS" : "FAIL"}
TEXT
regexp = /Tests #{success ? "PASS" : "FAIL"}/
# good
string = "Tests #{success ? 'PASS' : 'FAIL'}"
symbol = :"Tests #{success ? 'PASS' : 'FAIL'}"
heredoc = <<~TEXT
Tests #{success ? 'PASS' : 'FAIL'}
TEXT
regexp = /Tests #{success ? 'PASS' : 'FAIL'}/
Example: EnforcedStyle: double_quotes
# bad
string = "Tests #{success ? 'PASS' : 'FAIL'}"
symbol = :"Tests #{success ? 'PASS' : 'FAIL'}"
heredoc = <<~TEXT
Tests #{success ? 'PASS' : 'FAIL'}
TEXT
regexp = /Tests #{success ? 'PASS' : 'FAIL'}/
# good
string = "Tests #{success ? "PASS" : "FAIL"}"
symbol = :"Tests #{success ? "PASS" : "FAIL"}"
heredoc = <<~TEXT
Tests #{success ? "PASS" : "FAIL"}
TEXT
regexp = /Tests #{success ? "PASS" : "FAIL"}/
Use !empty?
instead of size > 0
. Open
return count unless columns_with_children && columns_with_children.size > 0
- Read upRead up
- Exclude checks
Checks for numeric comparisons that can be replaced
by a predicate method, such as receiver.length == 0
,
receiver.length > 0
, and receiver.length != 0
,
receiver.length < 1
and receiver.size == 0
that can be
replaced by receiver.empty?
and !receiver.empty?
.
NOTE: File
, Tempfile
, and StringIO
do not have empty?
so allow size == 0
and size.zero?
.
Safety:
This cop is unsafe because it cannot be guaranteed that the receiver
has an empty?
method that is defined in terms of length
. If there
is a non-standard class that redefines length
or empty?
, the cop
may register a false positive.
Example:
# bad
[1, 2, 3].length == 0
0 == "foobar".length
array.length < 1
{a: 1, b: 2}.length != 0
string.length > 0
hash.size > 0
# good
[1, 2, 3].empty?
"foobar".empty?
array.empty?
!{a: 1, b: 2}.empty?
!string.empty?
!hash.empty?
Use empty?
instead of length == 0
. Open
return {} if row_styles.length == 0 && cell_styles.length == 0
- Read upRead up
- Exclude checks
Checks for numeric comparisons that can be replaced
by a predicate method, such as receiver.length == 0
,
receiver.length > 0
, and receiver.length != 0
,
receiver.length < 1
and receiver.size == 0
that can be
replaced by receiver.empty?
and !receiver.empty?
.
NOTE: File
, Tempfile
, and StringIO
do not have empty?
so allow size == 0
and size.zero?
.
Safety:
This cop is unsafe because it cannot be guaranteed that the receiver
has an empty?
method that is defined in terms of length
. If there
is a non-standard class that redefines length
or empty?
, the cop
may register a false positive.
Example:
# bad
[1, 2, 3].length == 0
0 == "foobar".length
array.length < 1
{a: 1, b: 2}.length != 0
string.length > 0
hash.size > 0
# good
[1, 2, 3].empty?
"foobar".empty?
array.empty?
!{a: 1, b: 2}.empty?
!string.empty?
!hash.empty?
end
at 307, 1 is not aligned with class
at 4, 2. Open
end
- Read upRead up
- Exclude checks
Checks whether the end keywords are aligned properly.
Three modes are supported through the EnforcedStyleAlignWith
configuration parameter:
If it's set to keyword
(which is the default), the end
shall be aligned with the start of the keyword (if, class, etc.).
If it's set to variable
the end
shall be aligned with the
left-hand-side of the variable assignment, if there is one.
If it's set to start_of_line
, the end
shall be aligned with the
start of the line where the matching keyword appears.
This Layout/EndAlignment
cop aligns with keywords (e.g. if
, while
, case
)
by default. On the other hand, Layout/BeginEndAlignment
cop aligns with
EnforcedStyleAlignWith: start_of_line
by default due to ||= begin
tends
to align with the start of the line. Layout/DefEndAlignment
cop also aligns with
EnforcedStyleAlignWith: start_of_line
by default.
These style can be configured by each cop.
Example: EnforcedStyleAlignWith: keyword (default)
# bad
variable = if true
end
# good
variable = if true
end
variable =
if true
end
Example: EnforcedStyleAlignWith: variable
# bad
variable = if true
end
# good
variable = if true
end
variable =
if true
end
Example: EnforcedStyleAlignWith: startofline
# bad
variable = if true
end
puts(if true
end)
# good
variable = if true
end
puts(if true
end)
variable =
if true
end
Inconsistent indentation detected. Open
def export
package = Axlsx::Package.new
wb = package.workbook
wb_styles = wb.styles
- Read upRead up
- Exclude checks
Checks for inconsistent indentation.
The difference between indented_internal_methods
and normal
is
that the indented_internal_methods
style prescribes that in
classes and modules the protected
and private
modifier keywords
shall be indented the same as public methods and that protected and
private members shall be indented one step more than the modifiers.
Other than that, both styles mean that entities on the same logical
depth shall have the same indentation.
Example: EnforcedStyle: normal (default)
# bad
class A
def test
puts 'hello'
puts 'world'
end
end
# bad
class A
def test
puts 'hello'
puts 'world'
end
protected
def foo
end
private
def bar
end
end
# good
class A
def test
puts 'hello'
puts 'world'
end
end
# good
class A
def test
puts 'hello'
puts 'world'
end
protected
def foo
end
private
def bar
end
end
Example: EnforcedStyle: indentedinternalmethods
# bad
class A
def test
puts 'hello'
puts 'world'
end
end
# bad
class A
def test
puts 'hello'
puts 'world'
end
protected
def foo
end
private
def bar
end
end
# good
class A
def test
puts 'hello'
puts 'world'
end
end
# good
class A
def test
puts 'hello'
puts 'world'
end
protected
def foo
end
private
def bar
end
end
Tab detected in indentation. Open
def export
- Read upRead up
- Exclude checks
Checks that the indentation method is consistent. Either tabs only or spaces only are used for indentation.
Example: EnforcedStyle: spaces (default)
# bad
# This example uses a tab to indent bar.
def foo
bar
end
# good
# This example uses spaces to indent bar.
def foo
bar
end
Example: EnforcedStyle: tabs
# bad
# This example uses spaces to indent bar.
def foo
bar
end
# good
# This example uses a tab to indent bar.
def foo
bar
end
Prefer double-quoted strings inside interpolations. Open
"#{lock.include?(:col) ? '$' : ''}#{column_name(col)}#{lock.include?(:row) ? '$' : ''}#{row}"
- Read upRead up
- Exclude checks
Checks that quotes inside string, symbol, and regexp interpolations match the configured preference.
Example: EnforcedStyle: single_quotes (default)
# bad
string = "Tests #{success ? "PASS" : "FAIL"}"
symbol = :"Tests #{success ? "PASS" : "FAIL"}"
heredoc = <<~TEXT
Tests #{success ? "PASS" : "FAIL"}
TEXT
regexp = /Tests #{success ? "PASS" : "FAIL"}/
# good
string = "Tests #{success ? 'PASS' : 'FAIL'}"
symbol = :"Tests #{success ? 'PASS' : 'FAIL'}"
heredoc = <<~TEXT
Tests #{success ? 'PASS' : 'FAIL'}
TEXT
regexp = /Tests #{success ? 'PASS' : 'FAIL'}/
Example: EnforcedStyle: double_quotes
# bad
string = "Tests #{success ? 'PASS' : 'FAIL'}"
symbol = :"Tests #{success ? 'PASS' : 'FAIL'}"
heredoc = <<~TEXT
Tests #{success ? 'PASS' : 'FAIL'}
TEXT
regexp = /Tests #{success ? 'PASS' : 'FAIL'}/
# good
string = "Tests #{success ? "PASS" : "FAIL"}"
symbol = :"Tests #{success ? "PASS" : "FAIL"}"
heredoc = <<~TEXT
Tests #{success ? "PASS" : "FAIL"}
TEXT
regexp = /Tests #{success ? "PASS" : "FAIL"}/
Prefer double-quoted strings inside interpolations. Open
"#{lock.include?(:col) ? '$' : ''}#{column_name(col)}#{lock.include?(:row) ? '$' : ''}#{row}"
- Read upRead up
- Exclude checks
Checks that quotes inside string, symbol, and regexp interpolations match the configured preference.
Example: EnforcedStyle: single_quotes (default)
# bad
string = "Tests #{success ? "PASS" : "FAIL"}"
symbol = :"Tests #{success ? "PASS" : "FAIL"}"
heredoc = <<~TEXT
Tests #{success ? "PASS" : "FAIL"}
TEXT
regexp = /Tests #{success ? "PASS" : "FAIL"}/
# good
string = "Tests #{success ? 'PASS' : 'FAIL'}"
symbol = :"Tests #{success ? 'PASS' : 'FAIL'}"
heredoc = <<~TEXT
Tests #{success ? 'PASS' : 'FAIL'}
TEXT
regexp = /Tests #{success ? 'PASS' : 'FAIL'}/
Example: EnforcedStyle: double_quotes
# bad
string = "Tests #{success ? 'PASS' : 'FAIL'}"
symbol = :"Tests #{success ? 'PASS' : 'FAIL'}"
heredoc = <<~TEXT
Tests #{success ? 'PASS' : 'FAIL'}
TEXT
regexp = /Tests #{success ? 'PASS' : 'FAIL'}/
# good
string = "Tests #{success ? "PASS" : "FAIL"}"
symbol = :"Tests #{success ? "PASS" : "FAIL"}"
heredoc = <<~TEXT
Tests #{success ? "PASS" : "FAIL"}
TEXT
regexp = /Tests #{success ? "PASS" : "FAIL"}/
Redundant begin
block detected. Open
begin
- Read upRead up
- Exclude checks
Checks for redundant begin
blocks.
Currently it checks for code like this:
Example:
# bad
def redundant
begin
ala
bala
rescue StandardError => e
something
end
end
# good
def preferred
ala
bala
rescue StandardError => e
something
end
# bad
begin
do_something
end
# good
do_something
# bad
# When using Ruby 2.5 or later.
do_something do
begin
something
rescue => ex
anything
end
end
# good
# In Ruby 2.5 or later, you can omit `begin` in `do-end` block.
do_something do
something
rescue => ex
anything
end
# good
# Stabby lambdas don't support implicit `begin` in `do-end` blocks.
-> do
begin
foo
rescue Bar
baz
end
end
Unnecessary spacing detected. Open
return v unless accessors && accessors.length > 0
- Read upRead up
- Exclude checks
Checks for extra/unnecessary whitespace.
Example:
# good if AllowForAlignment is true
name = "RuboCop"
# Some comment and an empty line
website += "/rubocop/rubocop" unless cond
puts "rubocop" if debug
# bad for any configuration
set_app("RuboCop")
website = "https://github.com/rubocop/rubocop"
# good only if AllowBeforeTrailingComments is true
object.method(arg) # this is a comment
# good even if AllowBeforeTrailingComments is false or not set
object.method(arg) # this is a comment
# good with either AllowBeforeTrailingComments or AllowForAlignment
object.method(arg) # this is a comment
another_object.method(arg) # this is another comment
some_object.method(arg) # this is some comment
Missing top-level documentation comment for class NtqExcelsior::Exporter
. Open
class Exporter
- Read upRead up
- Exclude checks
Checks for missing top-level documentation of classes and modules. Classes with no body are exempt from the check and so are namespace modules - modules that have nothing in their bodies except classes, other modules, constant definitions or constant visibility declarations.
The documentation requirement is annulled if the class or module has
a #:nodoc:
comment next to it. Likewise, #:nodoc: all
does the
same for all its children.
Example:
# bad
class Person
# ...
end
module Math
end
# good
# Description/Explanation of Person class
class Person
# ...
end
# allowed
# Class without body
class Person
end
# Namespace - A namespace can be a class or a module
# Containing a class
module Namespace
# Description/Explanation of Person class
class Person
# ...
end
end
# Containing constant visibility declaration
module Namespace
class Private
end
private_constant :Private
end
# Containing constant definition
module Namespace
Public = Class.new
end
# Macro calls
module Namespace
extend Foo
end
Example: AllowedConstants: ['ClassMethods']
# good
module A
module ClassMethods
# ...
end
end
Missing frozen string literal comment. Open
require 'caxlsx'
- Read upRead up
- Exclude checks
Helps you transition from mutable string literals
to frozen string literals.
It will add the # frozen_string_literal: true
magic comment to the top
of files to enable frozen string literals. Frozen string literals may be
default in future Ruby. The comment will be added below a shebang and
encoding comment. The frozen string literal comment is only valid in Ruby 2.3+.
Note that the cop will accept files where the comment exists but is set
to false
instead of true
.
To require a blank line after this comment, please see
Layout/EmptyLineAfterMagicComment
cop.
Safety:
This cop's autocorrection is unsafe since any strings mutations will
change from being accepted to raising FrozenError
, as all strings
will become frozen by default, and will need to be manually refactored.
Example: EnforcedStyle: always (default)
# The `always` style will always add the frozen string literal comment
# to a file, regardless of the Ruby version or if `freeze` or `<<` are
# called on a string literal.
# bad
module Bar
# ...
end
# good
# frozen_string_literal: true
module Bar
# ...
end
# good
# frozen_string_literal: false
module Bar
# ...
end
Example: EnforcedStyle: never
# The `never` will enforce that the frozen string literal comment does
# not exist in a file.
# bad
# frozen_string_literal: true
module Baz
# ...
end
# good
module Baz
# ...
end
Example: EnforcedStyle: always_true
# The `always_true` style enforces that the frozen string literal
# comment is set to `true`. This is a stricter option than `always`
# and forces projects to use frozen string literals.
# bad
# frozen_string_literal: false
module Baz
# ...
end
# bad
module Baz
# ...
end
# good
# frozen_string_literal: true
module Bar
# ...
end
Prefer double-quoted strings unless you need single quotes to avoid extra backslashes for escaping. Open
config[:error] = list_config[:error] || ''
- Read upRead up
- Exclude checks
Checks if uses of quotes match the configured preference.
Example: EnforcedStyle: single_quotes (default)
# bad
"No special symbols"
"No string interpolation"
"Just text"
# good
'No special symbols'
'No string interpolation'
'Just text'
"Wait! What's #{this}!"
Example: EnforcedStyle: double_quotes
# bad
'Just some text'
'No special chars or interpolation'
# good
"Just some text"
"No special chars or interpolation"
"Every string in #{project} uses double_quotes"
Use 2 (not 0) spaces for indentation. Open
def export
- Read upRead up
- Exclude checks
Checks for indentation that doesn't use the specified number of spaces.
See also the IndentationConsistency cop which is the companion to this one.
Example:
# bad
class A
def test
puts 'hello'
end
end
# good
class A
def test
puts 'hello'
end
end
Example: AllowedPatterns: ['^\s*module']
# bad
module A
class B
def test
puts 'hello'
end
end
end
# good
module A
class B
def test
puts 'hello'
end
end
end
Shadowing outer local variable - index
. Open
@data.each_with_index do |record, index|
- Read upRead up
- Exclude checks
Checks for the use of local variable names from an outer scope
in block arguments or block-local variables. This mirrors the warning
given by ruby -cw
prior to Ruby 2.6:
"shadowing outer local variable - foo".
NOTE: Shadowing of variables in block passed to Ractor.new
is allowed
because Ractor
should not access outer variables.
eg. following style is encouraged:
```ruby
worker_id, pipe = env
Ractor.new(worker_id, pipe) do |worker_id, pipe|
end
```
Example:
# bad
def some_method
foo = 1
2.times do |foo| # shadowing outer `foo`
do_something(foo)
end
end
Example:
# good
def some_method
foo = 1
2.times do |bar|
do_something(bar)
end
end
Group together all attr_accessor
attributes. Open
attr_accessor :context
- Read upRead up
- Exclude checks
Checks for grouping of accessors in class
and module
bodies.
By default it enforces accessors to be placed in grouped declarations,
but it can be configured to enforce separating them in multiple declarations.
NOTE: If there is a method call before the accessor method it is always allowed as it might be intended like Sorbet.
Example: EnforcedStyle: grouped (default)
# bad
class Foo
attr_reader :bar
attr_reader :bax
attr_reader :baz
end
# good
class Foo
attr_reader :bar, :bax, :baz
end
# good
class Foo
# may be intended comment for bar.
attr_reader :bar
sig { returns(String) }
attr_reader :bax
may_be_intended_annotation :baz
attr_reader :baz
end
Example: EnforcedStyle: separated
# bad
class Foo
attr_reader :bar, :baz
end
# good
class Foo
attr_reader :bar
attr_reader :baz
end
Freeze mutable objects assigned to constants. Open
DEFAULT_STYLES = {
date_format: {
format_code: 'dd-mm-yyyy'
},
time_format: {
- Read upRead up
- Exclude checks
Checks whether some constant value isn't a mutable literal (e.g. array or hash).
Strict mode can be used to freeze all constants, rather than just literals. Strict mode is considered an experimental feature. It has not been updated with an exhaustive list of all methods that will produce frozen objects so there is a decent chance of getting some false positives. Luckily, there is no harm in freezing an already frozen object.
From Ruby 3.0, this cop honours the magic comment 'shareableconstantvalue'. When this magic comment is set to any acceptable value other than none, it will suppress the offenses raised by this cop. It enforces frozen state.
NOTE: Regexp and Range literals are frozen objects since Ruby 3.0.
NOTE: From Ruby 3.0, interpolated strings are not frozen when
# frozen-string-literal: true
is used, so this cop enforces explicit
freezing for such strings.
NOTE: From Ruby 3.0, this cop allows explicit freezing of constants when
the shareable_constant_value
directive is used.
Safety:
This cop's autocorrection is unsafe since any mutations on objects that
are made frozen will change from being accepted to raising FrozenError
,
and will need to be manually refactored.
Example: EnforcedStyle: literals (default)
# bad
CONST = [1, 2, 3]
# good
CONST = [1, 2, 3].freeze
# good
CONST = <<~TESTING.freeze
This is a heredoc
TESTING
# good
CONST = Something.new
Example: EnforcedStyle: strict
# bad
CONST = Something.new
# bad
CONST = Struct.new do
def foo
puts 1
end
end
# good
CONST = Something.new.freeze
# good
CONST = Struct.new do
def foo
puts 1
end
end.freeze
Example:
# Magic comment - shareable_constant_value: literal
# bad
CONST = [1, 2, 3]
# good
# shareable_constant_value: literal
CONST = [1, 2, 3]
Use columns_with_children.size.positive?
instead of columns_with_children.size > 0
. Open
return count unless columns_with_children && columns_with_children.size > 0
- Read upRead up
- Exclude checks
Checks for usage of comparison operators (==
,
>
, <
) to test numbers as zero, positive, or negative.
These can be replaced by their respective predicate methods.
This cop can also be configured to do the reverse.
This cop can be customized allowed methods with AllowedMethods
.
By default, there are no methods to allowed.
This cop disregards #nonzero?
as its value is truthy or falsey,
but not true
and false
, and thus not always interchangeable with
!= 0
.
This cop allows comparisons to global variables, since they are often
populated with objects which can be compared with integers, but are
not themselves Integer
polymorphic.
Safety:
This cop is unsafe because it cannot be guaranteed that the receiver defines the predicates or can be compared to a number, which may lead to a false positive for non-standard classes.
Example: EnforcedStyle: predicate (default)
# bad
foo == 0
0 > foo
bar.baz > 0
# good
foo.zero?
foo.negative?
bar.baz.positive?
Example: EnforcedStyle: comparison
# bad
foo.zero?
foo.negative?
bar.baz.positive?
# good
foo == 0
0 > foo
bar.baz > 0
Example: AllowedMethods: [] (default) with EnforcedStyle: predicate
# bad
foo == 0
0 > foo
bar.baz > 0
Example: AllowedMethods: [==] with EnforcedStyle: predicate
# good
foo == 0
# bad
0 > foo
bar.baz > 0
Example: AllowedPatterns: [] (default) with EnforcedStyle: comparison
# bad
foo.zero?
foo.negative?
bar.baz.positive?
Example: AllowedPatterns: ['zero'] with EnforcedStyle: predicate
# good
# bad
foo.zero?
# bad
foo.negative?
bar.baz.positive?
Prefer double-quoted strings inside interpolations. Open
"#{lock.include?(:col) ? '$' : ''}#{column_name(col)}#{lock.include?(:row) ? '$' : ''}#{row}"
- Read upRead up
- Exclude checks
Checks that quotes inside string, symbol, and regexp interpolations match the configured preference.
Example: EnforcedStyle: single_quotes (default)
# bad
string = "Tests #{success ? "PASS" : "FAIL"}"
symbol = :"Tests #{success ? "PASS" : "FAIL"}"
heredoc = <<~TEXT
Tests #{success ? "PASS" : "FAIL"}
TEXT
regexp = /Tests #{success ? "PASS" : "FAIL"}/
# good
string = "Tests #{success ? 'PASS' : 'FAIL'}"
symbol = :"Tests #{success ? 'PASS' : 'FAIL'}"
heredoc = <<~TEXT
Tests #{success ? 'PASS' : 'FAIL'}
TEXT
regexp = /Tests #{success ? 'PASS' : 'FAIL'}/
Example: EnforcedStyle: double_quotes
# bad
string = "Tests #{success ? 'PASS' : 'FAIL'}"
symbol = :"Tests #{success ? 'PASS' : 'FAIL'}"
heredoc = <<~TEXT
Tests #{success ? 'PASS' : 'FAIL'}
TEXT
regexp = /Tests #{success ? 'PASS' : 'FAIL'}/
# good
string = "Tests #{success ? "PASS" : "FAIL"}"
symbol = :"Tests #{success ? "PASS" : "FAIL"}"
heredoc = <<~TEXT
Tests #{success ? "PASS" : "FAIL"}
TEXT
regexp = /Tests #{success ? "PASS" : "FAIL"}/
Do not use do
with multi-line while
. Open
while index >= 26 do
- Read upRead up
- Exclude checks
Checks for uses of do
in multi-line while/until
statements.
Example:
# bad
while x.any? do
do_something(x.pop)
end
# good
while x.any?
do_something(x.pop)
end
Example:
# bad
until x.empty? do
do_something(x.pop)
end
# good
until x.empty?
do_something(x.pop)
end