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 7, 2020
1 parent 6d4ec21 commit 85cf302
Show file tree
Hide file tree
Showing 54 changed files with 381 additions and 498 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
20 changes: 9 additions & 11 deletions lib/rubocop/cop/rspec/align_left_let_brace.rb
Expand Up @@ -18,26 +18,24 @@ 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

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

Expand Down
20 changes: 9 additions & 11 deletions lib/rubocop/cop/rspec/align_right_let_brace.rb
Expand Up @@ -18,26 +18,24 @@ 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

def autocorrect(let)
lambda do |corrector|
corrector.insert_before(
let.loc.end,
token_aligner.indent_for(let)
)
add_offense(let.loc.end) do |corrector|
corrector.insert_before(
let.loc.end,
token_aligner.indent_for(let)
)
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|
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)
return unless node.chained?

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
as_is_matcher(node.parent) do |to_sym, matcher_node|
rewrite_expectation(corrector, node, to_sym, matcher_node)
end
end

private
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

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
15 changes: 6 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 @@ -72,16 +74,11 @@ def on_block(node)
next if enabled?(match)

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

def autocorrect(node)
lambda do |corrector|
corrector.replace(node.loc.selector, MAP[node.method_name].to_s)
) do |corrector|
corrector.replace(send_node.loc.selector, MAP[match].to_s)
end
end
end

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(context.parent.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
15 changes: 6 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,11 @@ 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|
block = hook.parent
range = range_with_surrounding_space(range: block.loc.expression)
corrector.remove(range)
end
end
end
end
Expand Down
8 changes: 5 additions & 3 deletions lib/rubocop/cop/rspec/empty_line_after_example.rb
Expand Up @@ -42,6 +42,7 @@ module RSpec
# end
#
class EmptyLineAfterExample < Cop
extend AutoCorrector
include RuboCop::RSpec::BlankLineSeparation

MSG = 'Add an empty line after `%<example>s`.'
Expand All @@ -52,9 +53,10 @@ def on_block(node)
return if allowed_one_liner?(node)

missing_separating_line(node) do |location|
add_offense(node,
location: location,
message: format(MSG, example: node.method_name))
msg = format(MSG, example: node.method_name)
add_offense(location, message: msg) do |corrector|
corrector.insert_after(location.end, "\n")
end
end
end

Expand Down

0 comments on commit 85cf302

Please sign in to comment.