Showing 1,311 of 1,311 total issues
Do not return
in begin..end
blocks in assignment contexts. Open
return if email.blank?
- Read upRead up
- Create a ticketCreate a ticket
- Exclude checks
Checks for the presence of a return
inside a begin..end
block
in assignment contexts.
In this situation, the return
will result in an exit from the current
method, possibly leading to unexpected behavior.
Example:
# bad
@some_variable ||= begin
return some_value if some_condition_is_met
do_something
end
Example:
# good
@some_variable ||= begin
if some_condition_is_met
some_value
else
do_something
end
end
# good
some_variable = if some_condition_is_met
return if another_condition_is_met
some_value
else
do_something
end
Remove unnecessary existence check File.exist?
. Open
File.delete(pid_file) if File.exist?(pid_file)
- Read upRead up
- Create a ticketCreate a ticket
- Exclude checks
Checks for non-atomic file operation. And then replace it with a nearly equivalent and atomic method.
These can cause problems that are difficult to reproduce, especially in cases of frequent file operations in parallel, such as test runs with parallel_rspec.
For examples: creating a directory if there is none, has the following problems
An exception occurs when the directory didn't exist at the time of exist?
,
but someone else created it before mkdir
was executed.
Subsequent processes are executed without the directory that should be there
when the directory existed at the time of exist?
,
but someone else deleted it shortly afterwards.
Safety:
This cop is unsafe, because autocorrection change to atomic processing. The atomic processing of the replacement destination is not guaranteed to be strictly equivalent to that before the replacement.
Example:
# bad - race condition with another process may result in an error in `mkdir`
unless Dir.exist?(path)
FileUtils.mkdir(path)
end
# good - atomic and idempotent creation
FileUtils.mkdir_p(path)
# bad - race condition with another process may result in an error in `remove`
if File.exist?(path)
FileUtils.remove(path)
end
# good - atomic and idempotent removal
FileUtils.rm_f(path)
Wrap expressions with varying precedence with parentheses to avoid ambiguity. Open
hdr << "@page{@bottom-center{font-size: 75%;content: '" + _("Report date: %{report_date}") % {:report_date => run_date} + "'}}"
- Read upRead up
- Create a ticketCreate a ticket
- Exclude checks
Looks for expressions containing multiple binary operators
where precedence is ambiguous due to lack of parentheses. For example,
in 1 + 2 * 3
, the multiplication will happen before the addition, but
lexically it appears that the addition will happen first.
The cop does not consider unary operators (ie. !a
or -b
) or comparison
operators (ie. a =~ b
) because those are not ambiguous.
NOTE: Ranges are handled by Lint/AmbiguousRange
.
Example:
# bad
a + b * c
a || b && c
a ** b + c
# good (different precedence)
a + (b * c)
a || (b && c)
(a ** b) + c
# good (same precedence)
a + b + c
a * b / c % d
Avoid more than 3 levels of block nesting. Open
unless fld[:error].nil?
valid = false
next
end
- Read upRead up
- Create a ticketCreate a ticket
- Exclude checks
Checks for excessive nesting of conditional and looping constructs.
You can configure if blocks are considered using the CountBlocks
option. When set to false
(the default) blocks are not counted
towards the nesting level. Set to true
to count blocks as well.
The maximum level of nesting allowed is configurable.
Avoid more than 3 levels of block nesting. Open
[set_value, field_values[set_value]] if field_values.key?(set_value)
- Read upRead up
- Create a ticketCreate a ticket
- Exclude checks
Checks for excessive nesting of conditional and looping constructs.
You can configure if blocks are considered using the CountBlocks
option. When set to false
(the default) blocks are not counted
towards the nesting level. Set to true
to count blocks as well.
The maximum level of nesting allowed is configurable.
Use filter_map
instead. Open
pxe_server.pxe_images.collect do |p|
next if p.pxe_image_type.nil? || p.default_for_windows
# filter pxe images by provision_type to show vm/any or host/any
build_ci_hash_struct(p, [:name, :description]) if p.pxe_image_type.provision_type.blank? || p.pxe_image_type.provision_type == prov_typ
- Create a ticketCreate a ticket
- Exclude checks
Duplicate branch body detected. Open
else
- Read upRead up
- Create a ticketCreate a ticket
- Exclude checks
Checks that there are no repeated bodies
within if/unless
, case-when
, case-in
and rescue
constructs.
With IgnoreLiteralBranches: true
, branches are not registered
as offenses if they return a basic literal value (string, symbol,
integer, float, rational, complex, true
, false
, or nil
), or
return an array, hash, regexp or range that only contains one of
the above basic literal values.
With IgnoreConstantBranches: true
, branches are not registered
as offenses if they return a constant value.
Example:
# bad
if foo
do_foo
do_something_else
elsif bar
do_foo
do_something_else
end
# good
if foo || bar
do_foo
do_something_else
end
# bad
case x
when foo
do_foo
when bar
do_foo
else
do_something_else
end
# good
case x
when foo, bar
do_foo
else
do_something_else
end
# bad
begin
do_something
rescue FooError
handle_error
rescue BarError
handle_error
end
# good
begin
do_something
rescue FooError, BarError
handle_error
end
Example: IgnoreLiteralBranches: true
# good
case size
when "small" then 100
when "medium" then 250
when "large" then 1000
else 250
end
Example: IgnoreConstantBranches: true
# good
case size
when "small" then SMALL_SIZE
when "medium" then MEDIUM_SIZE
when "large" then LARGE_SIZE
else MEDIUM_SIZE
end
Avoid rescuing the Exception
class. Perhaps you meant to rescue StandardError
? Open
rescue Exception => e
safe_log("Error in before_exit: #{e.message}", :error)
- Read upRead up
- Create a ticketCreate a ticket
- Exclude checks
Checks for rescue
blocks targeting the Exception class.
Example:
# bad
begin
do_something
rescue Exception
handle_exception
end
Example:
# good
begin
do_something
rescue ArgumentError
handle_exception
end
Do not define constants this way within a block. Open
AGGREGATE_ALL_VM_ATTRS = [
:aggregate_all_vm_cpus,
:aggregate_all_vm_memory,
:aggregate_all_vm_disk_count,
:aggregate_all_vm_disk_space_allocated,
- Read upRead up
- Create a ticketCreate a ticket
- Exclude checks
Do not define constants within a block, since the block's scope does not isolate or namespace the constant in any way.
If you are trying to define that constant once, define it outside of the block instead, or use a variable or method if defining the constant in the outer scope would be problematic.
For meta-programming, use const_set
.
Example:
# bad
task :lint do
FILES_TO_LINT = Dir['lib/*.rb']
end
# bad
describe 'making a request' do
class TestRequest; end
end
# bad
module M
extend ActiveSupport::Concern
included do
LIST = []
end
end
# good
task :lint do
files_to_lint = Dir['lib/*.rb']
end
# good
describe 'making a request' do
let(:test_request) { Class.new }
# see also `stub_const` for RSpec
end
# good
module M
extend ActiveSupport::Concern
included do
const_set(:LIST, [])
end
end
Example: AllowedMethods: ['enums'] (default)
# good
# `enums` for Typed Enums via `T::Enum` in Sorbet.
# https://sorbet.org/docs/tenum
class TestEnum < T::Enum
enums do
Foo = new("foo")
end
end
Avoid more than 3 levels of block nesting. Open
[found.id, found.send(obj_key)] if found
- Read upRead up
- Create a ticketCreate a ticket
- Exclude checks
Checks for excessive nesting of conditional and looping constructs.
You can configure if blocks are considered using the CountBlocks
option. When set to false
(the default) blocks are not counted
towards the nesting level. Set to true
to count blocks as well.
The maximum level of nesting allowed is configurable.
Wrap expressions with varying precedence with parentheses to avoid ambiguity. Open
error << _(". %{details}") % {:details => fld[:required_regex_fail_details]} if fld[:required_regex_fail_details]
- Read upRead up
- Create a ticketCreate a ticket
- Exclude checks
Looks for expressions containing multiple binary operators
where precedence is ambiguous due to lack of parentheses. For example,
in 1 + 2 * 3
, the multiplication will happen before the addition, but
lexically it appears that the addition will happen first.
The cop does not consider unary operators (ie. !a
or -b
) or comparison
operators (ie. a =~ b
) because those are not ambiguous.
NOTE: Ranges are handled by Lint/AmbiguousRange
.
Example:
# bad
a + b * c
a || b && c
a ** b + c
# good (different precedence)
a + (b * c)
a || (b && c)
(a ** b) + c
# good (same precedence)
a + b + c
a * b / c % d
self
used in void context. Open
self
- Read upRead up
- Create a ticketCreate a ticket
- Exclude checks
Checks for operators, variables, literals, lambda, proc and nonmutating methods used in void context.
Example: CheckForMethodsWithNoSideEffects: false (default)
# bad
def some_method
some_num * 10
do_something
end
def some_method(some_var)
some_var
do_something
end
Example: CheckForMethodsWithNoSideEffects: true
# bad
def some_method(some_array)
some_array.sort
do_something(some_array)
end
# good
def some_method
do_something
some_num * 10
end
def some_method(some_var)
do_something
some_var
end
def some_method(some_array)
some_array.sort!
do_something(some_array)
end
Avoid immutable Array literals in loops. It is better to extract it into a local variable or a constant. Open
['snapshot', 'mem', 'disk'].each do |a|
- Create a ticketCreate a ticket
- Exclude checks
Avoid more than 3 levels of block nesting. Open
if f[:values].present?
sorted_values = f[:values].sort
selected_key = sorted_values.first.first
end
- Read upRead up
- Create a ticketCreate a ticket
- Exclude checks
Checks for excessive nesting of conditional and looping constructs.
You can configure if blocks are considered using the CountBlocks
option. When set to false
(the default) blocks are not counted
towards the nesting level. Set to true
to count blocks as well.
The maximum level of nesting allowed is configurable.
Use filter_map
instead. Open
datacenters = sources.collect { |h| find_datacenter_for_ci(h) }.compact
- Create a ticketCreate a ticket
- Exclude checks
Avoid rescuing the Exception
class. Perhaps you meant to rescue StandardError
? Open
rescue Exception => err
msg = "Error adjusting schedules: #{err.message}"
_log.error(msg)
_log.log_backtrace(err)
do_exit("#{msg}. Restarting.", 1)
- Read upRead up
- Create a ticketCreate a ticket
- Exclude checks
Checks for rescue
blocks targeting the Exception class.
Example:
# bad
begin
do_something
rescue Exception
handle_exception
end
Example:
# good
begin
do_something
rescue ArgumentError
handle_exception
end
Avoid rescuing the Exception
class. Perhaps you meant to rescue StandardError
? Open
rescue Exception => err
do_exit("Error heartbeating because #{err.class.name}: #{err.message}\n#{err.backtrace.join('\n')}", 1)
- Read upRead up
- Create a ticketCreate a ticket
- Exclude checks
Checks for rescue
blocks targeting the Exception class.
Example:
# bad
begin
do_something
rescue Exception
handle_exception
end
Example:
# good
begin
do_something
rescue ArgumentError
handle_exception
end
Use count
instead of find_all...length
. Open
dups = current.uniq.find_all { |u| current.find_all { |c| c == u }.length > 1 }
- Read upRead up
- Create a ticketCreate a ticket
- Exclude checks
This cop is used to identify usages of count
on an Enumerable
that
follow calls to select
or reject
. Querying logic can instead be
passed to the count
call.
Example:
# bad
[1, 2, 3].select { |e| e > 2 }.size
[1, 2, 3].reject { |e| e > 2 }.size
[1, 2, 3].select { |e| e > 2 }.length
[1, 2, 3].reject { |e| e > 2 }.length
[1, 2, 3].select { |e| e > 2 }.count { |e| e.odd? }
[1, 2, 3].reject { |e| e > 2 }.count { |e| e.even? }
array.select(&:value).count
# good
[1, 2, 3].count { |e| e > 2 }
[1, 2, 3].count { |e| e < 2 }
[1, 2, 3].count { |e| e > 2 && e.odd? }
[1, 2, 3].count { |e| e < 2 && e.even? }
Model.select('field AS field_one').count
Model.select(:value).count
ActiveRecord
compatibility:
ActiveRecord
will ignore the block that is passed to count
.
Other methods, such as select
, will convert the association to an
array and then run the block on the array. A simple work around to
make count
work with a block is to call to_a.count {...}
.
Example: Model.where(id: [1, 2, 3].select { |m| m.method == true }.size
becomes:
Model.where(id: [1, 2, 3]).to_a.count { |m| m.method == true }
Use filter_map
instead. Open
@fixed_ip_addresses ||= cloud_subnet_network_ports.collect(&:address).compact.uniq
- Create a ticketCreate a ticket
- Exclude checks
Avoid immutable Array literals in loops. It is better to extract it into a local variable or a constant. Open
name = obj.send([:name, :description, :object_id].detect { |m| obj.respond_to?(m) })
- Create a ticketCreate a ticket
- Exclude checks