Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RSpec aliases runtime matchers #956

Merged
merged 1 commit into from
Nov 3, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* Remove deprecated class `::RuboCop::Cop::RSpec::Cop`. ([@bquorning][])
* Retire `RSpec/InvalidPredicateMatcher` cop. ([@pirj][])
* Remove the code responsible for filtering files to inspect. ([@pirj][])
* Make RSpec language elements configurable. ([@sl4vr][])

## 2.0.0.pre (2020-10-22)

Expand Down Expand Up @@ -580,3 +581,4 @@ Compatibility release so users can upgrade RuboCop to 0.51.0. No new features.
[@koic]: https://github.com/koic
[@Rafix02]: https://github.com/Rafix02
[@PhilCoggins]: https://github.com/PhilCoggins
[@sl4vr]: https://github.com/sl4vr
77 changes: 77 additions & 0 deletions config/default.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,83 @@ RSpec:
Include:
- "**/*_spec.rb"
- "**/spec/**/*"
Language:
ExampleGroups:
Regular:
- describe
- context
- feature
- example_group
Skipped:
- xdescribe
- xcontext
- xfeature
Focused:
- fdescribe
- fcontext
- ffeature
Examples:
Regular:
- it
- specify
- example
- scenario
- its
Focused:
- fit
- fspecify
- fexample
- fscenario
- focus
Skipped:
- xit
- xspecify
- xexample
- xscenario
- skip
Pending:
- pending
Expectations:
- expect
- is_expected
- expect_any_instance_of
Helpers:
- let
- let!
Hooks:
- prepend_before
- before
- append_before
- around
- prepend_after
- after
- append_after
HookScopes:
- each
- example
- context
- all
- suite
Includes:
Examples:
- it_behaves_like
- it_should_behave_like
- include_examples
Context:
- include_context
Runners:
- to
- to_not
- not_to
SharedGroups:
Examples:
- shared_examples
- shared_examples_for
Context:
- shared_context
Subjects:
- subject
- subject!

RSpec/AlignLeftLetBrace:
Description: Checks that left braces for adjacent single line lets are aligned.
Expand Down
3 changes: 1 addition & 2 deletions lib/rubocop-rspec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,12 @@

require 'rubocop'

require_relative 'rubocop/rspec'
require_relative 'rubocop/rspec/version'
require_relative 'rubocop/rspec/inject'
require_relative 'rubocop/rspec/node'
require_relative 'rubocop/rspec/wording'
require_relative 'rubocop/rspec/language'
require_relative 'rubocop/rspec/language/node_pattern'
require_relative 'rubocop/rspec/language'

require_relative 'rubocop/cop/rspec/mixin/top_level_group'
require_relative 'rubocop/cop/rspec/mixin/variable'
Expand Down
10 changes: 7 additions & 3 deletions lib/rubocop/cop/rspec/align_left_let_brace.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,9 @@ def self.autocorrect_incompatible_with
end

def on_new_investigation
super
return if processed_source.blank?

token_aligner =
RuboCop::RSpec::AlignLetBrace.new(processed_source.ast, :begin)

token_aligner.offending_tokens.each do |let|
add_offense(let.loc.begin) do |corrector|
corrector.insert_before(
Expand All @@ -40,6 +38,12 @@ def on_new_investigation
end
end
end

private

def token_aligner
RuboCop::RSpec::AlignLetBrace.new(processed_source.ast, :begin)
end
end
end
end
Expand Down
10 changes: 7 additions & 3 deletions lib/rubocop/cop/rspec/align_right_let_brace.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,9 @@ def self.autocorrect_incompatible_with
end

def on_new_investigation
super
return if processed_source.blank?

token_aligner =
RuboCop::RSpec::AlignLetBrace.new(processed_source.ast, :end)

token_aligner.offending_tokens.each do |let|
add_offense(let.loc.end) do |corrector|
corrector.insert_before(
Expand All @@ -40,6 +38,12 @@ def on_new_investigation
end
end
end

private

def token_aligner
RuboCop::RSpec::AlignLetBrace.new(processed_source.ast, :end)
end
end
end
end
Expand Down
9 changes: 8 additions & 1 deletion lib/rubocop/cop/rspec/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,21 @@ module RSpec
# @abstract parent class to RSpec cops
class Base < ::RuboCop::Cop::Base
include RuboCop::RSpec::Language
include RuboCop::RSpec::Language::NodePattern
extend RuboCop::RSpec::Language::NodePattern

exclude_from_registry

# Invoke the original inherited hook so our cops are recognized
def self.inherited(subclass) # rubocop:disable Lint/MissingSuper
RuboCop::Cop::Base.inherited(subclass)
end

# Set the config for dynamic DSL configuration-aware helpers
# that have no other means of accessing the configuration.
def on_new_investigation
super
RuboCop::RSpec::Language.config = config['RSpec']['Language']
end
end
end
end
Expand Down
2 changes: 1 addition & 1 deletion lib/rubocop/cop/rspec/be.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class Be < Base
MSG = 'Don\'t use `be` without an argument.'

def_node_matcher :be_without_args, <<-PATTERN
(send _ #{Runners::ALL.node_pattern_union} $(send nil? :be))
(send _ #Runners.all $(send nil? :be))
PATTERN

def on_send(node)
Expand Down
4 changes: 2 additions & 2 deletions lib/rubocop/cop/rspec/capybara/current_path_expectation.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,13 @@ class CurrentPathExpectation < Base
# Supported matchers: eq(...) / match(/regexp/) / match('regexp')
def_node_matcher :as_is_matcher, <<-PATTERN
(send
#expectation_set_on_current_path $#{Runners::ALL.node_pattern_union}
#expectation_set_on_current_path $#Runners.all
${(send nil? :eq ...) (send nil? :match (regexp ...))})
PATTERN

def_node_matcher :regexp_str_matcher, <<-PATTERN
(send
#expectation_set_on_current_path $#{Runners::ALL.node_pattern_union}
#expectation_set_on_current_path $#Runners.all
$(send nil? :match (str $_)))
PATTERN

Expand Down
5 changes: 3 additions & 2 deletions lib/rubocop/cop/rspec/capybara/feature_methods.rb
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,9 @@ class FeatureMethods < Base
feature: :describe
}.freeze

def_node_matcher :capybara_speak,
SelectorSet.new(MAP.keys).node_pattern_union
def_node_matcher :capybara_speak, <<-PATTERN
{#{MAP.keys.map(&:inspect).join(' ')}}
PATTERN

def_node_matcher :spec?, <<-PATTERN
(block
Expand Down
3 changes: 1 addition & 2 deletions lib/rubocop/cop/rspec/described_class.rb
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,7 @@ class DescribedClass < Base
(block (send (const nil? {:Class :Module :Struct}) :new ...) ...)
PATTERN

def_node_matcher :rspec_block?,
RuboCop::RSpec::Language::ALL.block_pattern
def_node_matcher :rspec_block?, block_pattern('#ALL.all')

def_node_matcher :scope_changing_syntax?, '{def class module}'

Expand Down
3 changes: 1 addition & 2 deletions lib/rubocop/cop/rspec/described_class_module_wrapping.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,7 @@ module RSpec
class DescribedClassModuleWrapping < Base
MSG = 'Avoid opening modules and defining specs within them.'

def_node_search :find_rspec_blocks,
ExampleGroups::ALL.block_pattern
def_node_search :find_rspec_blocks, block_pattern('#ExampleGroups.all')

def on_module(node)
find_rspec_blocks(node) do
Expand Down
2 changes: 1 addition & 1 deletion lib/rubocop/cop/rspec/dialect.rb
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ class Dialect < Base

MSG = 'Prefer `%<prefer>s` over `%<current>s`.'

def_node_matcher :rspec_method?, ALL.send_pattern
def_node_matcher :rspec_method?, send_pattern('#ALL.all')

def on_send(node)
return unless rspec_method?(node)
sl4vr marked this conversation as resolved.
Show resolved Hide resolved
Expand Down
13 changes: 6 additions & 7 deletions lib/rubocop/cop/rspec/empty_example_group.rb
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ class EmptyExampleGroup < Base
# @param node [RuboCop::AST::Node]
# @yield [RuboCop::AST::Node] example group body
def_node_matcher :example_group_body, <<~PATTERN
(block #{ExampleGroups::ALL.send_pattern} args $_)
(block #{send_pattern('#ExampleGroups.all')} args $_)
PATTERN

# @!method example_or_group_or_include?(node)
Expand All @@ -95,11 +95,10 @@ class EmptyExampleGroup < Base
# @return [Array<RuboCop::AST::Node>] matching nodes
def_node_matcher :example_or_group_or_include?, <<~PATTERN
{
#{Examples::ALL.send_pattern}
#{Examples::ALL.block_pattern}
#{ExampleGroups::ALL.block_pattern}
#{Includes::ALL.send_pattern}
#{Includes::ALL.block_pattern}
#{block_pattern(
'{#Examples.all #ExampleGroups.all #Includes.all}'
)}
#{send_pattern('{#Examples.all #Includes.all}')}
(send nil? #custom_include? ...)
}
PATTERN
Expand All @@ -120,7 +119,7 @@ class EmptyExampleGroup < Base
# @param node [RuboCop::AST::Node]
# @return [Array<RuboCop::AST::Node>] matching nodes
def_node_matcher :examples_inside_block?, <<~PATTERN
(block !#{Hooks::ALL.send_pattern} _ #examples?)
(block !#{send_pattern('#Hooks.all')} _ #examples?)
PATTERN

# @!method examples_directly_or_in_block?(node)
Expand Down
2 changes: 1 addition & 1 deletion lib/rubocop/cop/rspec/empty_hook.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class EmptyHook < Base
MSG = 'Empty hook detected.'

def_node_matcher :empty_hook?, <<~PATTERN
(block $#{Hooks::ALL.send_pattern} _ nil?)
(block $#{send_pattern('#Hooks.all')} _ nil?)
PATTERN

def on_block(node)
Expand Down
2 changes: 1 addition & 1 deletion lib/rubocop/cop/rspec/empty_line_after_subject.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def on_block(node)

def in_spec_block?(node)
node.each_ancestor(:block).any? do |ancestor|
Examples::ALL.include?(ancestor.method_name)
Examples.all(ancestor.method_name)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code reads a bit weird. It looks like there’s a question mark missing, i.e. Examples.all?(ancestor.method_name), but that’s also not good.

Probably not something we need to fix now, but just an observation.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed. Those new helpers fit patterns more.
I can think of adding an include? alias for all to all of them, however, this will not provide a similar interface to Examples.regular.

Another way is to check if an argument has been passed (used in a pattern), or not. If not - just return a list, and this will make both Examples.all.include?(ancestor.method_name) and Examples.regular.include?(ancestor.method_name) possible.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Returning different types (boolean vs array) from the same method also isn’t great. Maybe we should call #all? from within out patterns? Also not really a great option :-/

I think we should just leave it for now.

end
end
end
Expand Down
2 changes: 1 addition & 1 deletion lib/rubocop/cop/rspec/expect_actual.rb
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ class ExpectActual < Base
def_node_matcher :expect_literal, <<~PATTERN
(send
(send nil? :expect $#literal?)
#{Runners::ALL.node_pattern_union}
#Runners.all
{
(send (send nil? $:be) :== $_)
(send nil? $_ $_ ...)
Expand Down
2 changes: 1 addition & 1 deletion lib/rubocop/cop/rspec/expect_in_hook.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ module RSpec
class ExpectInHook < Base
MSG = 'Do not use `%<expect>s` in `%<hook>s` hook'

def_node_search :expectation, Expectations::ALL.send_pattern
def_node_search :expectation, send_pattern('#Expectations.all')

def on_block(node)
return unless hook?(node)
Expand Down
20 changes: 13 additions & 7 deletions lib/rubocop/cop/rspec/focus.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,25 @@ module RSpec
class Focus < Base
MSG = 'Focused spec found.'

focused = ExampleGroups::FOCUSED + Examples::FOCUSED

def_node_matcher :focusable_selector?,
(ExampleGroups::GROUPS + ExampleGroups::SKIPPED +
Examples::EXAMPLES + Examples::SKIPPED +
Examples::PENDING).node_pattern_union
def_node_matcher :focusable_selector?, <<-PATTERN
{
#ExampleGroups.regular
#ExampleGroups.skipped
#Examples.regular
#Examples.skipped
#Examples.pending
}
PATTERN

def_node_matcher :metadata, <<-PATTERN
{(send #rspec? #focusable_selector? <$(sym :focus) ...>)
(send #rspec? #focusable_selector? ... (hash <$(pair (sym :focus) true) ...>))}
PATTERN

def_node_matcher :focused_block?, focused.send_pattern
def_node_matcher :focused_block?,
send_pattern(<<~PATTERN)
{#ExampleGroups.focused #Examples.focused}
PATTERN

def on_send(node)
focus_metadata(node) do |focus|
Expand Down
6 changes: 2 additions & 4 deletions lib/rubocop/cop/rspec/hook_argument.rb
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,11 @@ class HookArgument < Base
IMPLICIT_MSG = 'Omit the default `%<scope>p` argument for RSpec hooks.'
EXPLICIT_MSG = 'Use `%<scope>p` for RSpec hooks.'

def_node_matcher :hook?, Hooks::ALL.node_pattern_union

def_node_matcher :scoped_hook, <<-PATTERN
(block $(send _ #hook? (sym ${:each :example})) ...)
(block $(send _ #Hooks.all (sym ${:each :example})) ...)
PATTERN

def_node_matcher :unscoped_hook, '(block $(send _ #hook?) ...)'
def_node_matcher :unscoped_hook, '(block $(send _ #Hooks.all) ...)'

def on_block(node)
hook(node) do |method_send, scope_name|
Expand Down
4 changes: 2 additions & 2 deletions lib/rubocop/cop/rspec/hooks_before_examples.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ class HooksBeforeExamples < Base

def_node_matcher :example_or_group?, <<-PATTERN
{
#{(Examples::ALL + ExampleGroups::ALL).block_pattern}
#{Includes::EXAMPLES.send_pattern}
#{block_pattern('{#ExampleGroups.all #Examples.all}')}
#{send_pattern('#Includes.examples')}
}
PATTERN

Expand Down
2 changes: 1 addition & 1 deletion lib/rubocop/cop/rspec/implicit_expect.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class ImplicitExpect < Base
def_node_matcher :implicit_expect, <<-PATTERN
{
(send nil? ${:should :should_not} ...)
(send (send nil? $:is_expected) #{Runners::ALL.node_pattern_union} ...)
(send (send nil? $:is_expected) #Runners.all ...)
}
PATTERN

Expand Down