Skip to content

Commit

Permalink
Add cop AssignmentInsteadOfComparison (#38)
Browse files Browse the repository at this point in the history
  • Loading branch information
Drowze authored Dec 19, 2023
1 parent 19845a6 commit 4114564
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 1 deletion.
6 changes: 5 additions & 1 deletion config/default.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,8 @@ Overhaul/MutableReformDefaults:
Enabled: true
Include:
app/concepts/**/*.rb
VersionAdded: '<<next>>'
VersionAdded: '0.0.1'
Overhaul/AssignmentInsteadOfComparison:
Description: Detect enumerable comparison blocks returning an assignment.
Enabled: true
VersionAdded: '0.0.1'
48 changes: 48 additions & 0 deletions lib/rubocop/cop/overhaul/assignment_instead_of_comparison.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# frozen_string_literal: true

module RuboCop
module Cop
module Overhaul
# Checks whether the return value of an Enumerator block method (fetch,
# minmax, group, search and sort methods) isn't an assignment.
#
# @example
# # bad
# my_array.select { |x| x = 4 }
#
# # good
# my_array.select { |x| x == 4 }
#
class AssignmentInsteadOfComparison < RuboCop::Cop::Cop
MSG = "Do not return an assignment from the block of an Enumerable's search method."

RESTRICT_ENUM_METHODS = [
:take_while, :drop_while, # fetch
:min, :max, :min_by, :max_by, :minmax_by, # minmax
:group_by, :partition, :slice_after, :slice_before, :slice_when, :chunk, :chunk_while, # group
:find, :detect, :find_all, :filter, :select, :find_index, :reject, :uniq_by, # search
:sort, :sort_by # sort
].freeze

# @!method search_method_calls?(node)
def_node_matcher :search_method_calls, <<~PATTERN
(block
(call _ /#{RESTRICT_ENUM_METHODS.join("|")}/)
(args ...)
$...
)
PATTERN

def on_block(node)
search_method_calls(node) do |value|
value = value.first
block_return_operation = value.begin_type? ? value.children.last : value
next unless block_return_operation.lvasgn_type?

add_offense(block_return_operation)
end
end
end
end
end
end
1 change: 1 addition & 0 deletions lib/rubocop/cop/overhaul_cops.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# frozen_string_literal: true

require_relative "overhaul/mutable_reform_defaults"
require_relative "overhaul/assignment_instead_of_comparison"
35 changes: 35 additions & 0 deletions spec/rubocop/cop/overhaul/assignment_instead_of_comparison_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# frozen_string_literal: true

RSpec.describe RuboCop::Cop::Overhaul::AssignmentInsteadOfComparison, :config do
shared_examples "block returning comparison" do |block_statements|
it "allows #{block_statements}" do
source = "my_arr.#{method} { #{block_statements} }"
expect_no_offenses(source)
end
end

shared_examples "block returning assignment" do |block_statements|
it "registers an offense for #{block_statements}" do
*prefix, o = block_statements.split("; ")
prefix = prefix.join("; ")
prefix += "; " if prefix.length.positive?

expect_offense(<<~RUBY, o: o, block_statements: block_statements, prefix: prefix, method: method)
my_arr.%{method} { %{block_statements} }
_{method} _{prefix}^{o} Do not return an assignment from the block of an Enumerable's search method.
RUBY
end
end

described_class::RESTRICT_ENUM_METHODS.each do |method|
context "when method is #{method}" do
let(:method) { method }

it_behaves_like "block returning assignment", "x = 3"
it_behaves_like "block returning assignment", "var = 10; x = 3"

it_behaves_like "block returning comparison", "x == 3"
it_behaves_like "block returning comparison", "x = 3; a"
end
end
end

0 comments on commit 4114564

Please sign in to comment.