Skip to content

Commit

Permalink
Use the new Autocorrection API
Browse files Browse the repository at this point in the history
The autocorrection API was changed in Rubocop v0.87.0 (pull request rubocop/rubocop#7868).

Here, I change the superclass of `RuboCop::Cop::RSpec::Cop` from
`::RuboCop::Cop::Cop` to `::RuboCop::Cop::Base`.

This has a few consequences:

- Our `#message` methods get called with a different argument than
  before. It *can* be customized by defining a `#callback_argument`
  method, but I think it is clearer to avoid callbacks altogether.
- Our `#autocorrect` methods don't get called anymore. Instead, we
  extend `Autocorrector`, and the `corrector` is being yielded when
  calling `#add_offense`, so the code is mostly moved in there. For some
  cases, this means that some code can be removed, which is nice. For
  some cases, it means that the methods get too long, or the code
  complexity gets too high, and in those cases I chose to just call out
  to an `#autocorrect` method anyway, but of course passing the
  `corrector` and any usable local variables along.

This also means we bump the dependency of RuboCop quite a bit, from
'>= 0.68.1' to '>= 0.87.0'.
  • Loading branch information
bquorning committed Jul 9, 2020
1 parent e6857d8 commit ac953d8
Show file tree
Hide file tree
Showing 54 changed files with 385 additions and 522 deletions.
2 changes: 1 addition & 1 deletion .rubocop_todo.yml
Expand Up @@ -14,4 +14,4 @@ InternalAffairs/MethodNameEqual:
# Offense count: 1
# Configuration parameters: CountComments.
Metrics/ClassLength:
Max: 104
Max: 106
29 changes: 11 additions & 18 deletions lib/rubocop/cop/rspec/align_left_let_brace.rb
Expand Up @@ -18,35 +18,28 @@ module RSpec
# let(:a) { b }
#
class AlignLeftLetBrace < Cop
extend AutoCorrector

MSG = 'Align left let brace'

def self.autocorrect_incompatible_with
[Layout::ExtraSpacing]
end

def investigate(_processed_source)
def on_new_investigation
return if processed_source.blank?

token_aligner.offending_tokens.each do |let|
add_offense(let, location: :begin)
end
end
token_aligner =
RuboCop::RSpec::AlignLetBrace.new(processed_source.ast, :begin)

def autocorrect(let)
lambda do |corrector|
corrector.insert_before(
let.loc.begin,
token_aligner.indent_for(let)
)
token_aligner.offending_tokens.each do |let|
add_offense(let.loc.begin) do |corrector|
corrector.insert_before(
let.loc.begin, token_aligner.indent_for(let)
)
end
end
end

private

def token_aligner
@token_aligner ||=
RuboCop::RSpec::AlignLetBrace.new(processed_source.ast, :begin)
end
end
end
end
Expand Down
29 changes: 11 additions & 18 deletions lib/rubocop/cop/rspec/align_right_let_brace.rb
Expand Up @@ -18,35 +18,28 @@ module RSpec
# let(:a) { b }
#
class AlignRightLetBrace < Cop
extend AutoCorrector

MSG = 'Align right let brace'

def self.autocorrect_incompatible_with
[Layout::ExtraSpacing]
end

def investigate(_processed_source)
def on_new_investigation
return if processed_source.blank?

token_aligner.offending_tokens.each do |let|
add_offense(let, location: :end)
end
end
token_aligner =
RuboCop::RSpec::AlignLetBrace.new(processed_source.ast, :end)

def autocorrect(let)
lambda do |corrector|
corrector.insert_before(
let.loc.end,
token_aligner.indent_for(let)
)
token_aligner.offending_tokens.each do |let|
add_offense(let.loc.end) do |corrector|
corrector.insert_before(
let.loc.end, token_aligner.indent_for(let)
)
end
end
end

private

def token_aligner
@token_aligner ||=
RuboCop::RSpec::AlignLetBrace.new(processed_source.ast, :end)
end
end
end
end
Expand Down
2 changes: 1 addition & 1 deletion lib/rubocop/cop/rspec/be.rb
Expand Up @@ -28,7 +28,7 @@ class Be < Cop

def on_send(node)
be_without_args(node) do |matcher|
add_offense(matcher, location: :selector)
add_offense(matcher.loc.selector)
end
end
end
Expand Down
10 changes: 5 additions & 5 deletions lib/rubocop/cop/rspec/be_eql.rb
Expand Up @@ -36,6 +36,8 @@ module RSpec
# coerce objects for comparison.
#
class BeEql < Cop
extend AutoCorrector

MSG = 'Prefer `be` over `eql`.'

def_node_matcher :eql_type_with_identity, <<-PATTERN
Expand All @@ -44,13 +46,11 @@ class BeEql < Cop

def on_send(node)
eql_type_with_identity(node) do |eql|
add_offense(eql, location: :selector)
add_offense(eql.loc.selector) do |corrector|
corrector.replace(eql.loc.selector, 'be')
end
end
end

def autocorrect(node)
->(corrector) { corrector.replace(node.loc.selector, 'be') }
end
end
end
end
Expand Down
34 changes: 18 additions & 16 deletions lib/rubocop/cop/rspec/capybara/current_path_expectation.rb
Expand Up @@ -24,6 +24,8 @@ module Capybara
# expect(page).to have_current_path(/widgets/)
#
class CurrentPathExpectation < Cop
extend AutoCorrector

MSG = 'Do not set an RSpec expectation on `current_path` in ' \
'Capybara feature specs - instead, use the ' \
'`have_current_path` matcher on `page`'
Expand All @@ -47,30 +49,30 @@ class CurrentPathExpectation < Cop

def on_send(node)
expectation_set_on_current_path(node) do
add_offense(node, location: :selector)
add_offense(node.loc.selector) do |corrector|
next unless node.chained?

autocorrect(corrector, node)
end
end
end

def autocorrect(node)
lambda do |corrector|
return unless node.chained?
private

as_is_matcher(node.parent) do |to_sym, matcher_node|
rewrite_expectation(corrector, node, to_sym, matcher_node)
end
def autocorrect(corrector, node)
as_is_matcher(node.parent) do |to_sym, matcher_node|
rewrite_expectation(corrector, node, to_sym, matcher_node)
end

regexp_str_matcher(node.parent) do |to_sym, matcher_node, regexp|
rewrite_expectation(corrector, node, to_sym, matcher_node)
convert_regexp_str_to_literal(corrector, matcher_node, regexp)
end
regexp_str_matcher(node.parent) do |to_sym, matcher_node, regexp|
rewrite_expectation(corrector, node, to_sym, matcher_node)
convert_regexp_str_to_literal(corrector, matcher_node, regexp)
end
end

private

def rewrite_expectation(corrector, node, to_symbol, matcher_node)
current_path_node = node.first_argument
corrector.replace(current_path_node.loc.expression, 'page')
corrector.replace(current_path_node, 'page')
corrector.replace(node.parent.loc.selector, 'to')
matcher_method = if to_symbol == :to
'have_current_path'
Expand All @@ -84,7 +86,7 @@ def rewrite_expectation(corrector, node, to_symbol, matcher_node)
def convert_regexp_str_to_literal(corrector, matcher_node, regexp_str)
str_node = matcher_node.first_argument
regexp_expr = Regexp.new(regexp_str).inspect
corrector.replace(str_node.loc.expression, regexp_expr)
corrector.replace(str_node, regexp_expr)
end

# `have_current_path` with no options will include the querystring
Expand All @@ -97,7 +99,7 @@ def add_ignore_query_options(corrector, node)
return if %i[regexp str].include?(expectation_last_child.type)

corrector.insert_after(
expectation_last_child.loc.expression,
expectation_last_child,
', ignore_query: true'
)
end
Expand Down
17 changes: 8 additions & 9 deletions lib/rubocop/cop/rspec/capybara/feature_methods.rb
Expand Up @@ -41,6 +41,8 @@ module Capybara
# end
# end
class FeatureMethods < Cop
extend AutoCorrector

MSG = 'Use `%<replacement>s` instead of `%<method>s`.'

# https://git.io/v7Kwr
Expand Down Expand Up @@ -71,18 +73,15 @@ def on_block(node)
feature_method(node) do |send_node, match|
next if enabled?(match)

add_offense(
send_node,
location: :selector,
message: format(MSG, method: match, replacement: MAP[match])
)
add_offense(send_node.loc.selector) do |corrector|
corrector.replace(send_node.loc.selector, MAP[match].to_s)
end
end
end

def autocorrect(node)
lambda do |corrector|
corrector.replace(node.loc.selector, MAP[node.method_name].to_s)
end
def message(range)
name = range.source.to_sym
format(MSG, method: name, replacement: MAP[name])
end

private
Expand Down
12 changes: 5 additions & 7 deletions lib/rubocop/cop/rspec/context_method.rb
Expand Up @@ -24,6 +24,8 @@ module RSpec
# # ...
# end
class ContextMethod < Cop
extend AutoCorrector

MSG = 'Use `describe` for testing methods.'

def_node_matcher :context_method, <<-PATTERN
Expand All @@ -32,13 +34,9 @@ class ContextMethod < Cop

def on_block(node)
context_method(node) do |context|
add_offense(context)
end
end

def autocorrect(node)
lambda do |corrector|
corrector.replace(node.parent.loc.selector, 'describe')
add_offense(context) do |corrector|
corrector.replace(node.send_node.loc.selector, 'describe')
end
end
end

Expand Down
2 changes: 1 addition & 1 deletion lib/rubocop/cop/rspec/cop.rb
Expand Up @@ -17,7 +17,7 @@ module RSpec
# # Patterns:
# # - '_test.rb$'
# # - '(?:^|/)test/'
class Cop < ::RuboCop::Cop::Cop
class Cop < ::RuboCop::Cop::Base
include RuboCop::RSpec::Language
include RuboCop::RSpec::Language::NodePattern

Expand Down
17 changes: 10 additions & 7 deletions lib/rubocop/cop/rspec/described_class.rb
Expand Up @@ -55,6 +55,7 @@ module RSpec
# end
#
class DescribedClass < Cop
extend AutoCorrector
include ConfigurableEnforcedStyle

DESCRIBED_CLASS = 'described_class'
Expand Down Expand Up @@ -85,22 +86,24 @@ def on_block(node)
return unless body

find_usage(body) do |match|
add_offense(match, message: message(match.const_name))
msg = message(match.const_name)
add_offense(match, message: msg) do |corrector|
autocorrect(corrector, match)
end
end
end

def autocorrect(node)
private

def autocorrect(corrector, match)
replacement = if style == :described_class
DESCRIBED_CLASS
else
@described_class.const_name
end
lambda do |corrector|
corrector.replace(node.loc.expression, replacement)
end
end

private
corrector.replace(match, replacement)
end

def find_usage(node, &block)
yield(node) if offensive?(node)
Expand Down
15 changes: 4 additions & 11 deletions lib/rubocop/cop/rspec/dialect.rb
Expand Up @@ -42,6 +42,7 @@ module RSpec
# # ...
# end
class Dialect < Cop
extend AutoCorrector
include MethodPreference

MSG = 'Prefer `%<prefer>s` over `%<current>s`.'
Expand All @@ -52,24 +53,16 @@ def on_send(node)
return unless rspec_method?(node)
return unless preferred_methods[node.method_name]

add_offense(node)
end
msg = format(MSG, prefer: preferred_method(node.method_name),
current: node.method_name)

def autocorrect(node)
lambda do |corrector|
add_offense(node, message: msg) do |corrector|
current = node.loc.selector
preferred = preferred_method(current.source)

corrector.replace(current, preferred)
end
end

private

def message(node)
format(MSG, prefer: preferred_method(node.method_name),
current: node.method_name)
end
end
end
end
Expand Down
14 changes: 5 additions & 9 deletions lib/rubocop/cop/rspec/empty_hook.rb
Expand Up @@ -23,6 +23,7 @@ module RSpec
# end
# after(:all) { cleanup_feed }
class EmptyHook < Cop
extend AutoCorrector
include RuboCop::Cop::RangeHelp

MSG = 'Empty hook detected.'
Expand All @@ -33,15 +34,10 @@ class EmptyHook < Cop

def on_block(node)
empty_hook?(node) do |hook|
add_offense(hook)
end
end

def autocorrect(node)
lambda do |corrector|
block = node.parent
range = range_with_surrounding_space(range: block.loc.expression)
corrector.remove(range)
add_offense(hook) do |corrector|
range = range_with_surrounding_space(range: node.loc.expression)
corrector.remove(range)
end
end
end
end
Expand Down

0 comments on commit ac953d8

Please sign in to comment.