brew vendor-gems: commit updates.

This commit is contained in:
BrewTestBot 2022-09-12 18:15:56 +00:00
parent e8e220128d
commit 31af2df104
No known key found for this signature in database
GPG Key ID: 82D7D104050B0F0F
133 changed files with 1307 additions and 524 deletions

View File

@ -89,7 +89,7 @@ $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/unicode-display_width
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-1.35.1/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-performance-1.14.3/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-rails-2.16.0/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-rspec-2.12.1/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-rspec-2.13.1/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-sorbet-0.6.11/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/ruby-macho-3.0.0/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/simplecov-html-0.12.3/lib"

View File

@ -1,77 +0,0 @@
# frozen_string_literal: true
module RuboCop
module Cop
module RSpec
module Capybara
# Checks for there is a more specific matcher offered by Capybara.
#
# @example
#
# # bad
# expect(page).to have_selector('button')
# expect(page).to have_no_selector('button.cls')
# expect(page).to have_css('button')
# expect(page).to have_no_css('a.cls', exact_text: 'foo')
# expect(page).to have_css('table.cls')
# expect(page).to have_css('select')
#
# # good
# expect(page).to have_button
# expect(page).to have_no_button(class: 'cls')
# expect(page).to have_button
# expect(page).to have_no_link('foo', class: 'cls')
# expect(page).to have_table(class: 'cls')
# expect(page).to have_select
#
class SpecificMatcher < Base
MSG = 'Prefer `%<good_matcher>s` over `%<bad_matcher>s`.'
RESTRICT_ON_SEND = %i[have_selector have_no_selector have_css
have_no_css].freeze
SPECIFIC_MATCHER = {
'button' => 'button',
'a' => 'link',
'table' => 'table',
'select' => 'select'
}.freeze
# @!method first_argument(node)
def_node_matcher :first_argument, <<-PATTERN
(send nil? _ (str $_) ... )
PATTERN
def on_send(node)
return unless (arg = first_argument(node))
return unless (matcher = specific_matcher(arg))
return if acceptable_pattern?(arg)
add_offense(node, message: message(node, matcher))
end
private
def specific_matcher(arg)
splitted_arg = arg[/^\w+/, 0]
SPECIFIC_MATCHER[splitted_arg]
end
def acceptable_pattern?(arg)
arg.match?(/\[.+=\w+\]/) || arg.match?(/[ >,+]/)
end
def message(node, matcher)
format(MSG,
good_matcher: good_matcher(node, matcher),
bad_matcher: node.method_name)
end
def good_matcher(node, matcher)
node.method_name
.to_s
.gsub(/selector|css/, matcher.to_s)
end
end
end
end
end
end

View File

@ -1,77 +0,0 @@
# frozen_string_literal: true
module RuboCop
module Cop
module RSpec
# Checks that `context` docstring starts with an allowed prefix.
#
# The default list of prefixes is minimal. Users are encouraged to tailor
# the configuration to meet project needs. Other acceptable prefixes may
# include `if`, `unless`, `for`, `before`, `after`, or `during`.
# They may consist of multiple words if desired.
#
# @see https://rspec.rubystyle.guide/#context-descriptions
# @see http://www.betterspecs.org/#contexts
#
# @example `Prefixes` configuration
#
# # .rubocop.yml
# # RSpec/ContextWording:
# # Prefixes:
# # - when
# # - with
# # - without
# # - if
# # - unless
# # - for
#
# @example
# # bad
# context 'the display name not present' do
# # ...
# end
#
# # good
# context 'when the display name is not present' do
# # ...
# end
class ContextWording < Base
MSG = 'Start context description with %<prefixes>s.'
# @!method context_wording(node)
def_node_matcher :context_wording, <<-PATTERN
(block (send #rspec? { :context :shared_context } $(str #bad_prefix?) ...) ...)
PATTERN
def on_block(node)
context_wording(node) do |context|
add_offense(context,
message: format(MSG, prefixes: joined_prefixes))
end
end
private
def bad_prefix?(description)
!prefix_regex.match?(description)
end
def joined_prefixes
quoted = prefixes.map { |prefix| "'#{prefix}'" }
return quoted.first if quoted.size == 1
quoted << "or #{quoted.pop}"
quoted.join(', ')
end
def prefixes
cop_config['Prefixes'] || []
end
def prefix_regex
/^#{Regexp.union(prefixes)}\b/
end
end
end
end
end

View File

@ -2,6 +2,7 @@
RSpec:
Enabled: true
StyleGuideBaseURL: https://rspec.rubystyle.guide
DocumentationBaseURL: https://docs.rubocop.org/rubocop-rspec
Include: &1
- "**/*_spec.rb"
- "**/spec/**/*"
@ -61,9 +62,14 @@ RSpec:
Pending:
- pending
Expectations:
- are_expected
- expect
- is_expected
- expect_any_instance_of
- is_expected
- should
- should_not
- should_not_receive
- should_receive
Helpers:
- let
- let!
@ -187,8 +193,21 @@ RSpec/BeforeAfterAll:
RSpec/ChangeByZero:
Description: Prefer negated matchers over `to change.by(0)`.
Enabled: pending
VersionAdded: 2.11.0
VersionAdded: '2.11'
VersionChanged: '2.13'
Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ChangeByZero
NegatedMatcher: ~
RSpec/ClassCheck:
Description: Enforces consistent use of `be_a` or `be_kind_of`.
StyleGuide: "#is-a-vs-kind-of"
Enabled: pending
VersionAdded: '2.13'
EnforcedStyle: be_a
SupportedStyles:
- be_a
- be_kind_of
Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ClassCheck
RSpec/ContextMethod:
Description: "`context` should not be used for specifying methods."
@ -204,8 +223,9 @@ RSpec/ContextWording:
- when
- with
- without
AllowedPatterns: []
VersionAdded: '1.20'
VersionChanged: 1.20.1
VersionChanged: '2.13'
StyleGuide: https://rspec.rubystyle.guide/#context-descriptions
Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ContextWording
@ -279,8 +299,9 @@ RSpec/Dialect:
RSpec/EmptyExampleGroup:
Description: Checks if an example group does not include any tests.
Enabled: true
SafeAutoCorrect: false
VersionAdded: '1.7'
VersionChanged: '2.0'
VersionChanged: '2.13'
Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/EmptyExampleGroup
RSpec/EmptyHook:
@ -315,8 +336,10 @@ RSpec/EmptyLineAfterHook:
Description: Checks if there is an empty line after hook blocks.
Enabled: true
VersionAdded: '1.27'
VersionChanged: '2.13'
StyleGuide: https://rspec.rubystyle.guide/#empty-line-after-let
Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/EmptyLineAfterHook
AllowConsecutiveOneLiners: true
RSpec/EmptyLineAfterSubject:
Description: Checks if there is an empty line after subject block.
@ -607,10 +630,18 @@ RSpec/NestedGroups:
Description: Checks for nested example groups.
Enabled: true
Max: 3
AllowedGroups: []
VersionAdded: '1.7'
VersionChanged: '1.10'
VersionChanged: '2.13'
Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/NestedGroups
RSpec/NoExpectationExample:
Description: Checks if an example contains any expectation.
Enabled: pending
Safe: false
VersionAdded: '2.13'
Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/NoExpectationExample
RSpec/NotToNot:
Description: Checks for consistent method usage for negating expectations.
Enabled: true
@ -775,9 +806,10 @@ RSpec/VariableName:
SupportedStyles:
- snake_case
- camelCase
AllowedPatterns: []
IgnoredPatterns: []
VersionAdded: '1.40'
VersionChanged: '1.43'
VersionChanged: '2.13'
Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/VariableName
RSpec/VerifiedDoubleReference:
@ -834,6 +866,12 @@ RSpec/Capybara/FeatureMethods:
VersionChanged: '2.0'
Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Capybara/FeatureMethods
RSpec/Capybara/SpecificFinders:
Description: Checks if there is a more specific finder offered by Capybara.
Enabled: pending
VersionAdded: '2.13'
Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Capybara/SpecificFinders
RSpec/Capybara/SpecificMatcher:
Description: Checks for there is a more specific matcher offered by Capybara.
Enabled: pending

View File

@ -0,0 +1,14 @@
#
# Configuration of obsolete/deprecated cops used by `ConfigObsoletion`.
#
# See: https://docs.rubocop.org/rubocop/extensions.html#config-obsoletions
#
# Cop parameters that have been changed
# Can be treated as a warning instead of a failure with `severity: warning`
changed_parameters:
- cops:
- RSpec/VariableName
parameters: IgnoredPatterns
alternative: AllowedPatterns
severity: warning

View File

@ -5,6 +5,7 @@ require 'yaml'
require 'rubocop'
require_relative 'rubocop/rspec'
require_relative 'rubocop/rspec/version'
require_relative 'rubocop/rspec/inject'
require_relative 'rubocop/rspec/node'
@ -20,6 +21,8 @@ require_relative 'rubocop/cop/rspec/mixin/final_end_location'
require_relative 'rubocop/cop/rspec/mixin/comments_help'
require_relative 'rubocop/cop/rspec/mixin/empty_line_separation'
require_relative 'rubocop/cop/rspec/mixin/inside_example_group'
require_relative 'rubocop/cop/rspec/mixin/namespace'
require_relative 'rubocop/cop/rspec/mixin/css_selector'
require_relative 'rubocop/rspec/concept'
require_relative 'rubocop/rspec/example_group'

View File

@ -6,16 +6,15 @@ module RuboCop
# Checks that left braces for adjacent single line lets are aligned.
#
# @example
# # bad
# let(:foobar) { blahblah }
# let(:baz) { bar }
# let(:a) { b }
#
# # bad
# let(:foobar) { blahblah }
# let(:baz) { bar }
# let(:a) { b }
#
# # good
# let(:foobar) { blahblah }
# let(:baz) { bar }
# let(:a) { b }
# # good
# let(:foobar) { blahblah }
# let(:baz) { bar }
# let(:a) { b }
#
class AlignLeftLetBrace < Base
extend AutoCorrector

View File

@ -6,16 +6,15 @@ module RuboCop
# Checks that right braces for adjacent single line lets are aligned.
#
# @example
# # bad
# let(:foobar) { blahblah }
# let(:baz) { bar }
# let(:a) { b }
#
# # bad
# let(:foobar) { blahblah }
# let(:baz) { bar }
# let(:a) { b }
#
# # good
# let(:foobar) { blahblah }
# let(:baz) { bar }
# let(:a) { b }
# # good
# let(:foobar) { blahblah }
# let(:baz) { bar }
# let(:a) { b }
#
class AlignRightLetBrace < Base
extend AutoCorrector

View File

@ -22,6 +22,7 @@ module RuboCop
# allow(my_instance).to receive(:foo)
# end
# end
#
class AnyInstance < Base
MSG = 'Avoid stubbing using `%<method>s`.'
RESTRICT_ON_SEND = %i[

View File

@ -25,23 +25,29 @@ module RuboCop
# some_method
# test.run
# end
#
class AroundBlock < Base
MSG_NO_ARG = 'Test object should be passed to around block.'
MSG_UNUSED_ARG = 'You should call `%<arg>s.call` ' \
'or `%<arg>s.run`.'
# @!method hook(node)
def_node_matcher :hook, <<-PATTERN
# @!method hook_block(node)
def_node_matcher :hook_block, <<-PATTERN
(block (send nil? :around sym ?) (args $...) ...)
PATTERN
# @!method hook_numblock(node)
def_node_matcher :hook_numblock, <<-PATTERN
(numblock (send nil? :around sym ?) ...)
PATTERN
# @!method find_arg_usage(node)
def_node_search :find_arg_usage, <<-PATTERN
{(send $... {:call :run}) (send _ _ $...) (yield $...) (block-pass $...)}
PATTERN
def on_block(node)
hook(node) do |(example_proxy)|
hook_block(node) do |(example_proxy)|
if example_proxy.nil?
add_no_arg_offense(node)
else
@ -50,6 +56,12 @@ module RuboCop
end
end
def on_numblock(node)
hook_numblock(node) do
check_for_numblock(node)
end
end
private
def add_no_arg_offense(node)
@ -68,6 +80,17 @@ module RuboCop
message: format(MSG_UNUSED_ARG, arg: name)
)
end
def check_for_numblock(block)
find_arg_usage(block) do |usage|
return if usage.include?(s(:lvar, :_1))
end
add_offense(
block.children.last,
message: format(MSG_UNUSED_ARG, arg: :_1)
)
end
end
end
end

View File

@ -10,7 +10,6 @@ module RuboCop
# cases it's better to specify what exactly is the expected value.
#
# @example
#
# # bad
# expect(foo).to be
#

View File

@ -10,7 +10,6 @@ module RuboCop
# the `be` matcher is preferable as it is a more strict test.
#
# @example
#
# # bad
# expect(foo).to eq(true)
# expect(foo).to eq(false)

View File

@ -11,7 +11,6 @@ module RuboCop
# preferable as it is a more strict test.
#
# @example
#
# # bad
# expect(foo).to eql(1)
# expect(foo).to eql(1.0)

View File

@ -23,6 +23,7 @@ module RuboCop
# before(:each) { Widget.create }
# after(:each) { Widget.delete_all }
# end
#
class BeforeAfterAll < Base
MSG = 'Beware of using `%<hook>s` as it may cause state to leak ' \
'between tests. If you are using `rspec-rails`, and ' \

View File

@ -14,14 +14,20 @@ module RuboCop
# which ensures that preceding actions (like `click_link`) have
# completed.
#
# This cop does not support autocorrection in some cases.
#
# @example
# # bad
# expect(current_path).to eq('/callback')
# expect(page.current_path).to match(/widgets/)
#
# # good
# expect(page).to have_current_path("/callback")
# expect(page).to have_current_path(/widgets/)
# expect(page).to have_current_path('/callback')
#
# # bad (does not support autocorrection)
# expect(page.current_path).to match(variable)
#
# # good
# expect(page).to have_current_path('/callback')
#
class CurrentPathExpectation < Base
extend AutoCorrector

View File

@ -40,6 +40,7 @@ module RuboCop
# # ...
# end
# end
#
class FeatureMethods < Base
extend AutoCorrector
include InsideExampleGroup
@ -68,7 +69,7 @@ module RuboCop
...)
PATTERN
def on_block(node)
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
return unless inside_example_group?(node)
feature_method(node) do |send_node, match|

View File

@ -0,0 +1,86 @@
# frozen_string_literal: true
module RuboCop
module Cop
module RSpec
module Capybara
# Checks if there is a more specific finder offered by Capybara.
#
# @example
# # bad
# find('#some-id')
# find('[visible][id=some-id]')
#
# # good
# find_by_id('some-id')
# find_by_id('some-id', visible: true)
#
class SpecificFinders < Base
extend AutoCorrector
include RangeHelp
MSG = 'Prefer `find_by` over `find`.'
RESTRICT_ON_SEND = %i[find].freeze
# @!method find_argument(node)
def_node_matcher :find_argument, <<~PATTERN
(send _ :find (str $_) ...)
PATTERN
def on_send(node)
find_argument(node) do |arg|
next if CssSelector.multiple_selectors?(arg)
on_attr(node, arg) if attribute?(arg)
on_id(node, arg) if CssSelector.id?(arg)
end
end
private
def on_attr(node, arg)
return unless (id = CssSelector.attributes(arg)['id'])
register_offense(node, replaced_arguments(arg, id))
end
def on_id(node, arg)
register_offense(node, "'#{arg.to_s.delete('#')}'")
end
def attribute?(arg)
CssSelector.attribute?(arg) &&
CssSelector.common_attributes?(arg)
end
def register_offense(node, arg_replacement)
add_offense(offense_range(node)) do |corrector|
corrector.replace(node.loc.selector, 'find_by_id')
corrector.replace(node.first_argument.loc.expression,
arg_replacement)
end
end
def replaced_arguments(arg, id)
options = to_options(CssSelector.attributes(arg))
options.empty? ? id : "#{id}, #{options}"
end
def to_options(attrs)
attrs.each.map do |key, value|
next if key == 'id'
"#{key}: #{value}"
end.compact.join(', ')
end
def offense_range(node)
range_between(node.loc.selector.begin_pos,
node.loc.end.end_pos)
end
end
end
end
end
end

View File

@ -0,0 +1,158 @@
# frozen_string_literal: true
module RuboCop
module Cop
module RSpec
module Capybara
# Checks for there is a more specific matcher offered by Capybara.
#
# @example
#
# # bad
# expect(page).to have_selector('button')
# expect(page).to have_no_selector('button.cls')
# expect(page).to have_css('button')
# expect(page).to have_no_css('a.cls', href: 'http://example.com')
# expect(page).to have_css('table.cls')
# expect(page).to have_css('select')
# expect(page).to have_css('input', exact_text: 'foo')
#
# # good
# expect(page).to have_button
# expect(page).to have_no_button(class: 'cls')
# expect(page).to have_button
# expect(page).to have_no_link('foo', class: 'cls', href: 'http://example.com')
# expect(page).to have_table(class: 'cls')
# expect(page).to have_select
# expect(page).to have_field('foo')
#
class SpecificMatcher < Base # rubocop:disable Metrics/ClassLength
MSG = 'Prefer `%<good_matcher>s` over `%<bad_matcher>s`.'
RESTRICT_ON_SEND = %i[have_selector have_no_selector have_css
have_no_css].freeze
SPECIFIC_MATCHER = {
'button' => 'button',
'a' => 'link',
'table' => 'table',
'select' => 'select',
'input' => 'field'
}.freeze
SPECIFIC_MATCHER_OPTIONS = {
'button' => (
CssSelector::COMMON_OPTIONS + %w[disabled name value title type]
).freeze,
'link' => (
CssSelector::COMMON_OPTIONS + %w[href alt title download]
).freeze,
'table' => (
CssSelector::COMMON_OPTIONS + %w[
caption with_cols cols with_rows rows
]
).freeze,
'select' => (
CssSelector::COMMON_OPTIONS + %w[
disabled name placeholder options enabled_options
disabled_options selected with_selected multiple with_options
]
).freeze,
'field' => (
CssSelector::COMMON_OPTIONS + %w[
checked unchecked disabled valid name placeholder
validation_message readonly with type multiple
]
).freeze
}.freeze
SPECIFIC_MATCHER_PSEUDO_CLASSES = %w[
not() disabled enabled checked unchecked
].freeze
# @!method first_argument(node)
def_node_matcher :first_argument, <<-PATTERN
(send nil? _ (str $_) ... )
PATTERN
# @!method option?(node)
def_node_search :option?, <<-PATTERN
(pair (sym %) _)
PATTERN
def on_send(node)
first_argument(node) do |arg|
next unless (matcher = specific_matcher(arg))
next if CssSelector.multiple_selectors?(arg)
next unless specific_matcher_option?(node, arg, matcher)
next unless specific_matcher_pseudo_classes?(arg)
add_offense(node, message: message(node, matcher))
end
end
private
def specific_matcher(arg)
splitted_arg = arg[/^\w+/, 0]
SPECIFIC_MATCHER[splitted_arg]
end
def specific_matcher_option?(node, arg, matcher)
attrs = CssSelector.attributes(arg).keys
return true if attrs.empty?
return false unless replaceable_matcher?(node, matcher, attrs)
attrs.all? do |attr|
SPECIFIC_MATCHER_OPTIONS.fetch(matcher, []).include?(attr)
end
end
def specific_matcher_pseudo_classes?(arg)
CssSelector.pseudo_classes(arg).all? do |pseudo_class|
replaceable_pseudo_class?(pseudo_class, arg)
end
end
def replaceable_pseudo_class?(pseudo_class, arg)
unless SPECIFIC_MATCHER_PSEUDO_CLASSES.include?(pseudo_class)
return false
end
case pseudo_class
when 'not()' then replaceable_pseudo_class_not?(arg)
else true
end
end
def replaceable_pseudo_class_not?(arg)
arg.scan(/not\(.*?\)/).all? do |not_arg|
CssSelector.attributes(not_arg).values.all? do |v|
v.is_a?(TrueClass) || v.is_a?(FalseClass)
end
end
end
def replaceable_matcher?(node, matcher, attrs)
case matcher
when 'link' then replaceable_to_have_link?(node, attrs)
else true
end
end
def replaceable_to_have_link?(node, attrs)
option?(node, :href) || attrs.include?('href')
end
def message(node, matcher)
format(MSG,
good_matcher: good_matcher(node, matcher),
bad_matcher: node.method_name)
end
def good_matcher(node, matcher)
node.method_name
.to_s
.gsub(/selector|css/, matcher.to_s)
end
end
end
end
end
end

View File

@ -16,7 +16,6 @@ module RuboCop
# https://www.rubydoc.info/gems/capybara/Capybara%2FNode%2FFinders:all[the documentation].
#
# @example
#
# # bad
# expect(page).to have_selector('.foo', visible: false)
# expect(page).to have_css('.foo', visible: true)

View File

@ -5,12 +5,20 @@ module RuboCop
module RSpec
# Prefer negated matchers over `to change.by(0)`.
#
# @example
# In the case of composite expectations, cop suggest using the
# negation matchers of `RSpec::Matchers#change`.
#
# By default the cop does not support autocorrect of
# compound expectations, but if you set the
# negated matcher for `change`, e.g. `not_change` with
# the `NegatedMatcher` option, the cop will perform the autocorrection.
#
# @example NegatedMatcher: ~ (default)
# # bad
# expect { run }.to change(Foo, :bar).by(0)
# expect { run }.to change { Foo.bar }.by(0)
#
# # bad - compound expectations
# # bad - compound expectations (does not support autocorrection)
# expect { run }
# .to change(Foo, :bar).by(0)
# .and change(Foo, :baz).by(0)
@ -31,10 +39,28 @@ module RuboCop
# .to not_change { Foo.bar }
# .and not_change { Foo.baz }
#
# @example NegatedMatcher: not_change
# # bad (support autocorrection to good case)
# expect { run }
# .to change(Foo, :bar).by(0)
# .and change(Foo, :baz).by(0)
# expect { run }
# .to change { Foo.bar }.by(0)
# .and change { Foo.baz }.by(0)
#
# # good
# define_negated_matcher :not_change, :change
# expect { run }
# .to not_change(Foo, :bar)
# .and not_change(Foo, :baz)
# expect { run }
# .to not_change { Foo.bar }
# .and not_change { Foo.baz }
#
class ChangeByZero < Base
extend AutoCorrector
MSG = 'Prefer `not_to change` over `to change.by(0)`.'
MSG_COMPOUND = 'Prefer negated matchers with compound expectations ' \
MSG_COMPOUND = 'Prefer %<preferred>s with compound expectations ' \
'over `change.by(0)`.'
RESTRICT_ON_SEND = %i[change].freeze
@ -55,6 +81,11 @@ module RuboCop
(int 0))
PATTERN
# @!method change_nodes(node)
def_node_search :change_nodes, <<-PATTERN
$(send nil? :change ...)
PATTERN
def on_send(node)
expect_change_with_arguments(node.parent) do
check_offense(node.parent)
@ -70,7 +101,9 @@ module RuboCop
def check_offense(node)
expression = node.loc.expression
if compound_expectations?(node)
add_offense(expression, message: MSG_COMPOUND)
add_offense(expression, message: message_compound) do |corrector|
autocorrect_compound(corrector, node)
end
else
add_offense(expression) do |corrector|
autocorrect(corrector, node)
@ -79,7 +112,7 @@ module RuboCop
end
def compound_expectations?(node)
%i[and or].include?(node.parent.method_name)
%i[and or & |].include?(node.parent.method_name)
end
def autocorrect(corrector, node)
@ -87,6 +120,28 @@ module RuboCop
range = node.loc.dot.with(end_pos: node.loc.expression.end_pos)
corrector.remove(range)
end
def autocorrect_compound(corrector, node)
return unless negated_matcher
change_nodes(node) do |change_node|
corrector.replace(change_node.loc.selector, negated_matcher)
range = node.loc.dot.with(end_pos: node.loc.expression.end_pos)
corrector.remove(range)
end
end
def negated_matcher
cop_config['NegatedMatcher']
end
def message_compound
format(MSG_COMPOUND, preferred: preferred_method)
end
def preferred_method
negated_matcher ? "`#{negated_matcher}`" : 'negated matchers'
end
end
end
end

View File

@ -0,0 +1,101 @@
# frozen_string_literal: true
module RuboCop
module Cop
module RSpec
# Enforces consistent use of `be_a` or `be_kind_of`.
#
# @example EnforcedStyle: be_a (default)
# # bad
# expect(object).to be_kind_of(String)
# expect(object).to be_a_kind_of(String)
#
# # good
# expect(object).to be_a(String)
# expect(object).to be_an(String)
#
# @example EnforcedStyle: be_kind_of
# # bad
# expect(object).to be_a(String)
# expect(object).to be_an(String)
#
# # good
# expect(object).to be_kind_of(String)
# expect(object).to be_a_kind_of(String)
#
class ClassCheck < Base
extend AutoCorrector
include ConfigurableEnforcedStyle
MSG = 'Prefer `%<preferred>s` over `%<current>s`.'
METHOD_NAMES_FOR_BE_A = ::Set[
:be_a,
:be_an
].freeze
METHOD_NAMES_FOR_KIND_OF = ::Set[
:be_a_kind_of,
:be_kind_of
].freeze
PREFERRED_METHOD_NAME_BY_STYLE = {
be_a: :be_a,
be_kind_of: :be_kind_of
}.freeze
RESTRICT_ON_SEND = %i[
be_a
be_a_kind_of
be_an
be_kind_of
].freeze
def on_send(node)
return unless offending?(node)
add_offense(
node.loc.selector,
message: format_message(node)
) do |corrector|
autocorrect(corrector, node)
end
end
private
def autocorrect(corrector, node)
corrector.replace(node.loc.selector, preferred_method_name)
end
def format_message(node)
format(
MSG,
current: node.method_name,
preferred: preferred_method_name
)
end
def offending?(node)
!node.receiver && !preferred_method_name?(node.method_name)
end
def preferred_method_name?(method_name)
preferred_method_names.include?(method_name)
end
def preferred_method_name
PREFERRED_METHOD_NAME_BY_STYLE[style]
end
def preferred_method_names
if style == :be_a
METHOD_NAMES_FOR_BE_A
else
METHOD_NAMES_FOR_KIND_OF
end
end
end
end
end
end

View File

@ -23,6 +23,7 @@ module RuboCop
# describe '.foo_bar' do
# # ...
# end
#
class ContextMethod < Base
extend AutoCorrector
@ -33,7 +34,7 @@ module RuboCop
(block (send #rspec? :context $(str #method_name?) ...) ...)
PATTERN
def on_block(node)
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
context_method(node) do |context|
add_offense(context) do |corrector|
corrector.replace(node.send_node.loc.selector, 'describe')

View File

@ -0,0 +1,108 @@
# frozen_string_literal: true
module RuboCop
module Cop
module RSpec
# Checks that `context` docstring starts with an allowed prefix.
#
# The default list of prefixes is minimal. Users are encouraged to tailor
# the configuration to meet project needs. Other acceptable prefixes may
# include `if`, `unless`, `for`, `before`, `after`, or `during`.
# They may consist of multiple words if desired.
#
# @see https://rspec.rubystyle.guide/#context-descriptions
# @see http://www.betterspecs.org/#contexts
#
# @example `Prefixes` configuration
# # .rubocop.yml
# # RSpec/ContextWording:
# # Prefixes:
# # - when
# # - with
# # - without
# # - if
# # - unless
# # - for
#
# @example
# # bad
# context 'the display name not present' do
# # ...
# end
#
# # good
# context 'when the display name is not present' do
# # ...
# end
#
# This cop can be customized allowed context description pattern
# with `AllowedPatterns`. By default, there are no checking by pattern.
#
# @example `AllowedPatterns` configuration
#
# # .rubocop.yml
# # RSpec/ContextWording:
# # AllowedPatterns:
# # - /とき$/
#
# @example
# # bad
# context '条件を満たす' do
# # ...
# end
#
# # good
# context '条件を満たすとき' do
# # ...
# end
#
class ContextWording < Base
include AllowedPattern
MSG = 'Context description should match %<patterns>s.'
# @!method context_wording(node)
def_node_matcher :context_wording, <<-PATTERN
(block (send #rspec? { :context :shared_context } $(str $_) ...) ...)
PATTERN
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
context_wording(node) do |context, description|
if bad_pattern?(description)
message = format(MSG, patterns: expect_patterns)
add_offense(context, message: message)
end
end
end
private
def allowed_patterns
super + prefix_regexes
end
def prefix_regexes
@prefix_regexes ||= prefixes.map { |pre| /^#{Regexp.escape(pre)}\b/ }
end
def bad_pattern?(description)
return false if allowed_patterns.empty?
!matches_allowed_pattern?(description)
end
def expect_patterns
inspected = allowed_patterns.map(&:inspect)
return inspected.first if inspected.size == 1
inspected << "or #{inspected.pop}"
inspected.join(', ')
end
def prefixes
Array(cop_config.fetch('Prefixes', []))
end
end
end
end
end

View File

@ -10,7 +10,6 @@ module RuboCop
# Ignores Rails and Aruba `type` metadata by default.
#
# @example `IgnoredMetadata` configuration
#
# # .rubocop.yml
# # RSpec/DescribeClass:
# # IgnoredMetadata:
@ -34,6 +33,7 @@ module RuboCop
#
# describe "A feature example", type: :feature do
# end
#
class DescribeClass < Base
include TopLevelGroup

View File

@ -16,6 +16,7 @@ module RuboCop
#
# describe MyClass, '.my_class_method' do
# end
#
class DescribeMethod < Base
include TopLevelGroup

View File

@ -57,6 +57,7 @@ module RuboCop
class DescribedClass < Base
extend AutoCorrector
include ConfigurableEnforcedStyle
include Namespace
DESCRIBED_CLASS = 'described_class'
MSG = 'Use `%<replacement>s` instead of `%<src>s`.'
@ -81,7 +82,7 @@ module RuboCop
def_node_search :contains_described_class?,
'(send nil? :described_class)'
def on_block(node)
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
# In case the explicit style is used, we need to remember what's
# being described.
@described_class, body = described_constant(node)
@ -160,7 +161,8 @@ module RuboCop
end
def full_const_name(node)
collapse_namespace(namespace(node), const_name(node))
symbolized_namespace = namespace(node).map(&:to_sym)
collapse_namespace(symbolized_namespace, const_name(node))
end
# @param namespace [Array<Symbol>]
@ -200,18 +202,6 @@ module RuboCop
[nil, name]
end
end
# @param node [RuboCop::AST::Node]
# @return [Array<Symbol>]
# @example
# namespace(node) # => [:A, :B, :C]
def namespace(node)
node
.each_ancestor(:class, :module)
.reverse_each
.flat_map { |ancestor| ancestor.defined_module_name.split('::') }
.map(&:to_sym)
end
end
end
end

View File

@ -41,6 +41,7 @@ module RuboCop
# describe 'display name presence' do
# # ...
# end
#
class Dialect < Base
extend AutoCorrector
include MethodPreference

View File

@ -6,7 +6,6 @@ module RuboCop
# Checks if an example group does not include any tests.
#
# @example usage
#
# # bad
# describe Bacon do
# let(:bacon) { Bacon.new(chunkiness) }
@ -35,7 +34,12 @@ module RuboCop
# describe Bacon do
# pending 'will add tests later'
# end
#
class EmptyExampleGroup < Base
extend AutoCorrector
include RangeHelp
MSG = 'Empty example group detected.'
# @!method example_group_body(node)
@ -119,7 +123,7 @@ module RuboCop
# describe { it { i_run_as_well } }
#
# @example source that does not match
# before { it { whatever here wont run anyway } }
# before { it { whatever here won't run anyway } }
#
# @param node [RuboCop::AST::Node]
# @return [Array<RuboCop::AST::Node>] matching nodes
@ -130,12 +134,16 @@ module RuboCop
}
PATTERN
def on_block(node)
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
return if node.each_ancestor(:def, :defs).any?
return if node.each_ancestor(:block).any? { |block| example?(block) }
example_group_body(node) do |body|
add_offense(node.send_node) if offensive?(body)
next unless offensive?(body)
add_offense(node.send_node) do |corrector|
corrector.remove(removed_range(node))
end
end
end
@ -163,6 +171,13 @@ module RuboCop
def examples_in_branches?(condition_node)
condition_node.branches.any? { |branch| examples?(branch) }
end
def removed_range(node)
range_by_whole_lines(
node.location.expression,
include_final_newline: true
)
end
end
end
end

View File

@ -22,6 +22,7 @@ module RuboCop
# create_feed
# end
# after(:all) { cleanup_feed }
#
class EmptyHook < Base
extend AutoCorrector
include RuboCop::Cop::RangeHelp
@ -33,7 +34,7 @@ module RuboCop
(block $#{send_pattern('#Hooks.all')} _ nil?)
PATTERN
def on_block(node)
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
empty_hook?(node) do |hook|
add_offense(hook) do |corrector|
corrector.remove(

View File

@ -30,7 +30,6 @@ module RuboCop
# end
#
# @example with AllowConsecutiveOneLiners configuration
#
# # rubocop.yml
# # RSpec/EmptyLineAfterExample:
# # AllowConsecutiveOneLiners: false
@ -47,7 +46,7 @@ module RuboCop
MSG = 'Add an empty line after `%<example>s`.'
def on_block(node)
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
return unless example?(node)
return if allowed_one_liner?(node)
@ -65,19 +64,15 @@ module RuboCop
end
def consecutive_one_liner?(node)
node.line_count == 1 && next_one_line_example?(node)
node.single_line? && next_one_line_example?(node)
end
def next_one_line_example?(node)
next_sibling = next_sibling(node)
next_sibling = node.right_sibling
return unless next_sibling
return unless example?(next_sibling)
next_sibling.line_count == 1
end
def next_sibling(node)
node.parent.children[node.sibling_index + 1]
next_sibling.single_line?
end
end
end

View File

@ -29,7 +29,7 @@ module RuboCop
MSG = 'Add an empty line after `%<example_group>s`.'
def on_block(node)
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
return unless example_group?(node)
missing_separating_line_offense(node) do |method|

View File

@ -16,13 +16,14 @@ module RuboCop
# let(:something) { other }
#
# it { does_something }
#
class EmptyLineAfterFinalLet < Base
extend AutoCorrector
include EmptyLineSeparation
MSG = 'Add an empty line after the last `%<let>s`.'
def on_block(node)
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
return unless example_group_with_body?(node)
final_let = node.body.child_nodes.reverse.find { |child| let?(child) }

View File

@ -5,6 +5,9 @@ module RuboCop
module RSpec
# Checks if there is an empty line after hook blocks.
#
# `AllowConsecutiveOneLiners` configures whether adjacent
# one-line definitions are considered an offense.
#
# @example
# # bad
# before { do_something }
@ -19,11 +22,23 @@ module RuboCop
# it { does_something }
#
# # good
# before { do_something }
# after { do_something }
#
# it { does_something }
#
# # good
# # fair - it's ok to have non-separated one-liners hooks
# around { |test| test.run }
# after { do_something }
#
# it { does_something }
#
# @example with AllowConsecutiveOneLiners configuration
# # rubocop.yml
# # RSpec/EmptyLineAfterHook:
# # AllowConsecutiveOneLiners: false
#
# # bad
# around { |test| test.run }
# after { do_something }
#
# it { does_something }
@ -31,21 +46,36 @@ module RuboCop
# # good
# around { |test| test.run }
#
# after { do_something }
#
# it { does_something }
#
class EmptyLineAfterHook < Base
extend AutoCorrector
include ConfigurableEnforcedStyle
include EmptyLineSeparation
MSG = 'Add an empty line after `%<hook>s`.'
def on_block(node)
return unless hook?(node)
return if cop_config['AllowConsecutiveOneLiners'] &&
chained_single_line_hooks?(node)
missing_separating_line_offense(node) do |method|
format(MSG, hook: method)
end
end
alias on_numblock on_block
private
def chained_single_line_hooks?(node)
next_node = node.right_sibling
hook?(next_node) && node.single_line? && next_node.single_line?
end
end
end
end

View File

@ -14,6 +14,7 @@ module RuboCop
# subject(:obj) { described_class }
#
# let(:foo) { bar }
#
class EmptyLineAfterSubject < Base
extend AutoCorrector
include EmptyLineSeparation
@ -21,7 +22,7 @@ module RuboCop
MSG = 'Add an empty line after `%<subject>s`.'
def on_block(node)
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
return unless subject?(node)
return unless inside_example_group?(node)

View File

@ -47,12 +47,13 @@ module RuboCop
# content.
# HEREDOC
# end # 5 points
#
class ExampleLength < Base
include CodeLength
LABEL = 'Example'
def on_block(node)
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
return unless example?(node)
check_code_length(node)

View File

@ -47,6 +47,7 @@ module RuboCop
# result = service.call
# expect(result).to be(true)
# end
#
class ExampleWithoutDescription < Base
include ConfigurableEnforcedStyle
@ -57,7 +58,7 @@ module RuboCop
# @!method example_description(node)
def_node_matcher :example_description, '(send nil? _ $(str $_))'
def on_block(node)
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
return unless example?(node)
check_example_without_description(node.send_node)

View File

@ -29,6 +29,7 @@ module RuboCop
# # good
# it 'does things' do
# end
#
class ExampleWording < Base
extend AutoCorrector
@ -46,7 +47,7 @@ module RuboCop
} ...) ...)
PATTERN
def on_block(node)
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
it_description(node) do |description_node, message|
if message.match?(SHOULD_PREFIX)
add_wording_offense(description_node, MSG_SHOULD)

View File

@ -22,6 +22,7 @@ module RuboCop
# # good
# context 'when a condition is met' do
# end
#
class ExcessiveDocstringSpacing < Base
extend AutoCorrector

View File

@ -18,6 +18,9 @@ module RuboCop
# expect(pattern).to eq(/foo/)
# expect(name).to eq("John")
#
# # bad (not supported autocorrection)
# expect(false).to eq(true)
#
class ExpectActual < Base
extend AutoCorrector

View File

@ -69,7 +69,7 @@ module RuboCop
end
end
def on_block(node)
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
return unless style == :method_call
expect_change_with_block(node) do |receiver, message|

View File

@ -20,13 +20,14 @@ module RuboCop
# it do
# expect(something).to eq 'foo'
# end
#
class ExpectInHook < Base
MSG = 'Do not use `%<expect>s` in `%<hook>s` hook'
# @!method expectation(node)
def_node_search :expectation, send_pattern('#Expectations.all')
def on_block(node)
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
return unless hook?(node)
return if node.body.nil?
@ -36,6 +37,8 @@ module RuboCop
end
end
alias on_numblock on_block
private
def message(expect, hook)

View File

@ -14,6 +14,7 @@ module RuboCop
#
# # good
# expect { my_app.print_report }.to output('Hello World').to_stdout
#
class ExpectOutput < Base
MSG = 'Use `expect { ... }.to output(...).to_%<name>s` ' \
'instead of mutating $%<name>s.'

View File

@ -24,6 +24,7 @@ module RuboCop
#
# # good
# count { 1 }
#
class AttributeDefinedStatically < Base
extend AutoCorrector
@ -39,7 +40,7 @@ module RuboCop
(block (send _ #attribute_defining_method? ...) _ { (begin $...) $(send ...) } )
PATTERN
def on_block(node)
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
attributes = factory_attributes(node) || []
attributes = [attributes] unless attributes.is_a?(Array) # rubocop:disable Style/ArrayCoercion, Lint/RedundantCopDisableDirective

View File

@ -30,6 +30,7 @@ module RuboCop
#
# # good
# 3.times { create :user }
#
class CreateList < Base
extend AutoCorrector
include ConfigurableEnforcedStyle
@ -39,20 +40,23 @@ module RuboCop
MSG_N_TIMES = 'Prefer %<number>s.times.'
RESTRICT_ON_SEND = %i[create_list].freeze
# @!method n_times_block?(node)
def_node_matcher :n_times_block?, <<-PATTERN
# @!method array_new_or_n_times_block?(node)
def_node_matcher :array_new_or_n_times_block?, <<-PATTERN
(block
(send (int _) :times)
{
(send (const {nil? | cbase} :Array) :new (int _)) |
(send (int _) :times)
}
...
)
PATTERN
# @!method n_times_block_with_arg_and_used?(node)
def_node_matcher :n_times_block_with_arg_and_used?, <<-PATTERN
# @!method block_with_arg_and_used?(node)
def_node_matcher :block_with_arg_and_used?, <<-PATTERN
(block
(send (int _) :times)
_
(args (arg _value))
`_value
`_value
)
PATTERN
@ -71,11 +75,11 @@ module RuboCop
(send {nil? #factory_bot?} :create_list (sym _) (int $_) ...)
PATTERN
def on_block(node)
def on_block(node) # rubocop:todo InternalAffairs/NumblockHandler
return unless style == :create_list
return unless n_times_block?(node)
return if n_times_block_with_arg_and_used?(node)
return unless array_new_or_n_times_block?(node)
return if block_with_arg_and_used?(node)
return unless node.body
return if arguments_include_method_call?(node.body)
return unless contains_only_factory?(node.body)
@ -183,7 +187,7 @@ module RuboCop
def call_with_block_replacement(node)
block = node.body
arguments = build_arguments(block, node.receiver.source)
arguments = build_arguments(block, count_from(node))
replacement = format_receiver(block.receiver)
replacement += format_method_call(block, 'create_list', arguments)
replacement += format_block(block)
@ -203,7 +207,7 @@ module RuboCop
block = node.body
factory, *options = *block.arguments
arguments = "#{factory.source}, #{node.receiver.source}"
arguments = "#{factory.source}, #{count_from(node)}"
options = build_options_string(options)
arguments += ", #{options}" unless options.empty?
@ -212,6 +216,16 @@ module RuboCop
replacement
end
def count_from(node)
count_node =
if node.receiver.int_type?
node.receiver
else
node.send_node.first_argument
end
count_node.source
end
def format_block(node)
if node.body.begin_type?
format_multiline_block(node)

View File

@ -58,6 +58,7 @@ module RuboCop
#
class FilePath < Base
include TopLevelGroup
include Namespace
MSG = 'Spec path should end with `%<suffix>s`.'
@ -101,7 +102,7 @@ module RuboCop
def pattern_for(example_group, method_name)
if spec_suffix_only? || !example_group.const_type?
return pattern_for_spec_suffix_only?
return pattern_for_spec_suffix_only
end
[
@ -111,7 +112,7 @@ module RuboCop
].join
end
def pattern_for_spec_suffix_only?
def pattern_for_spec_suffix_only
'.*_spec\.rb'
end
@ -123,8 +124,10 @@ module RuboCop
end
def expected_path(constant)
constants = namespace(constant) + constant.const_name.split('::')
File.join(
constant.const_name.split('::').map do |name|
constants.map do |name|
custom_transform.fetch(name) { camel_to_snake_case(name) }
end
)

View File

@ -5,6 +5,8 @@ module RuboCop
module RSpec
# Checks if examples are focused.
#
# This cop does not support autocorrection in some cases.
#
# @example
# # bad
# describe MyClass, focus: true do
@ -19,6 +21,22 @@ module RuboCop
# # good
# describe MyClass do
# end
#
# # bad
# fdescribe 'test' do; end
#
# # good
# describe 'test' do; end
#
# # bad
# fdescribe 'test' do; end
#
# # good
# describe 'test' do; end
#
# # bad (does not support autocorrection)
# focus 'test' do; end
#
class Focus < Base
extend AutoCorrector
include RangeHelp

View File

@ -57,6 +57,7 @@ module RuboCop
# before(:example) do
# # ...
# end
#
class HookArgument < Base
extend AutoCorrector
include ConfigurableEnforcedStyle
@ -66,11 +67,13 @@ module RuboCop
# @!method scoped_hook(node)
def_node_matcher :scoped_hook, <<-PATTERN
(block $(send _ #Hooks.all (sym ${:each :example})) ...)
({block numblock} $(send _ #Hooks.all (sym ${:each :example})) ...)
PATTERN
# @!method unscoped_hook(node)
def_node_matcher :unscoped_hook, '(block $(send _ #Hooks.all) ...)'
def_node_matcher :unscoped_hook, <<-PATTERN
({block numblock} $(send _ #Hooks.all) ...)
PATTERN
def on_block(node)
hook(node) do |method_send, scope_name|
@ -86,6 +89,8 @@ module RuboCop
end
end
alias on_numblock on_block
private
def check_implicit(method_send)

View File

@ -6,8 +6,7 @@ module RuboCop
# Checks for before/around/after hooks that come after an example.
#
# @example
# # Bad
#
# # bad
# it 'checks what foo does' do
# expect(foo).to be
# end
@ -15,7 +14,7 @@ module RuboCop
# before { prepare }
# after { clean_up }
#
# # Good
# # good
# before { prepare }
# after { clean_up }
#
@ -32,6 +31,7 @@ module RuboCop
def_node_matcher :example_or_group?, <<-PATTERN
{
#{block_pattern('{#ExampleGroups.all #Examples.all}')}
#{numblock_pattern('{#ExampleGroups.all #Examples.all}')}
#{send_pattern('#Includes.examples')}
}
PATTERN
@ -42,6 +42,8 @@ module RuboCop
check_hooks(node.body) if multiline_block?(node.body)
end
alias on_numblock on_block
private
def multiline_block?(block)
@ -52,13 +54,12 @@ module RuboCop
first_example = find_first_example(node)
return unless first_example
node.each_child_node do |child|
next if child.sibling_index < first_example.sibling_index
next unless hook?(child)
first_example.right_siblings.each do |sibling|
next unless hook?(sibling)
msg = format(MSG, hook: child.method_name)
add_offense(child, message: msg) do |corrector|
autocorrect(corrector, child, first_example)
msg = format(MSG, hook: sibling.method_name)
add_offense(sibling, message: msg) do |corrector|
autocorrect(corrector, sibling, first_example)
end
end
end

View File

@ -6,7 +6,6 @@ module RuboCop
# Checks for equality assertions with identical expressions on both sides.
#
# @example
#
# # bad
# expect(foo.bar).to eq(foo.bar)
# expect(foo.bar).to eql(foo.bar)

View File

@ -16,6 +16,7 @@ module RuboCop
# it 'changes something to a new value' do
# expect { do_something }.to change(something).to(new_value)
# end
#
class ImplicitBlockExpectation < Base
MSG = 'Avoid implicit block expectations.'
RESTRICT_ON_SEND = %i[is_expected should should_not].freeze

View File

@ -9,7 +9,6 @@ module RuboCop
# and supports the `--auto-gen-config` flag.
#
# @example `EnforcedStyle: is_expected` (default)
#
# # bad
# it { should be_truthy }
#
@ -17,7 +16,6 @@ module RuboCop
# it { is_expected.to be_truthy }
#
# @example `EnforcedStyle: should`
#
# # bad
# it { is_expected.to be_truthy }
#

View File

@ -42,7 +42,7 @@ module RuboCop
...)
PATTERN
def on_block(node)
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
return unless example?(node)
null_double(node) do |var, receiver|

View File

@ -24,7 +24,6 @@ module RuboCop
# end
#
# @example with AssignmentOnly configuration
#
# # rubocop.yml
# # RSpec/InstanceVariable:
# # AssignmentOnly: false

View File

@ -18,6 +18,7 @@ module RuboCop
#
# # good
# it_should_behave_like 'a foo'
#
class ItBehavesLike < Base
extend AutoCorrector
include ConfigurableEnforcedStyle

View File

@ -15,6 +15,7 @@ module RuboCop
# it 'validates users' do
# expect([user1, user2, user3]).to all(be_valid)
# end
#
class IteratedExpectation < Base
MSG = 'Prefer using the `all` matcher instead ' \
'of iterating over an array.'
@ -28,6 +29,13 @@ module RuboCop
)
PATTERN
# @!method each_numblock?(node)
def_node_matcher :each_numblock?, <<-PATTERN
(numblock
(send ... :each) _ $(...)
)
PATTERN
# @!method expectation?(node)
def_node_matcher :expectation?, <<-PATTERN
(send (send nil? :expect (lvar %)) :to ...)
@ -41,6 +49,14 @@ module RuboCop
end
end
def on_numblock(node)
each_numblock?(node) do |body|
if single_expectation?(body, :_1) || only_expectations?(body, :_1)
add_offense(node.send_node)
end
end
end
private
def single_expectation?(body, arg)

View File

@ -7,29 +7,29 @@ module RuboCop
#
# @example
# # bad
# let(:params) { blah }
# subject { described_class.new(params) }
# let(:params) { blah }
# subject { described_class.new(params) }
#
# before { do_something }
# subject { described_class.new(params) }
# before { do_something }
# subject { described_class.new(params) }
#
# it { expect_something }
# subject { described_class.new(params) }
# it { expect_something_else }
# it { expect_something }
# subject { described_class.new(params) }
# it { expect_something_else }
#
#
# # good
# subject { described_class.new(params) }
# let(:params) { blah }
# subject { described_class.new(params) }
# let(:params) { blah }
#
# # good
# subject { described_class.new(params) }
# before { do_something }
# subject { described_class.new(params) }
# before { do_something }
#
# # good
# subject { described_class.new(params) }
# it { expect_something }
# it { expect_something_else }
# subject { described_class.new(params) }
# it { expect_something }
# it { expect_something_else }
#
class LeadingSubject < Base
extend AutoCorrector
@ -37,7 +37,7 @@ module RuboCop
MSG = 'Declare `subject` above any other `%<offending>s` declarations.'
def on_block(node)
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
return unless subject?(node)
return unless inside_example_group?(node)

View File

@ -6,7 +6,7 @@ module RuboCop
# Checks for `let` definitions that come after an example.
#
# @example
# # Bad
# # bad
# let(:foo) { bar }
#
# it 'checks what foo does' do
@ -19,7 +19,7 @@ module RuboCop
# expect(some).to be
# end
#
# # Good
# # good
# let(:foo) { bar }
# let(:some) { other }
#
@ -43,7 +43,7 @@ module RuboCop
}
PATTERN
def on_block(node)
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
return unless example_group_with_body?(node)
check_let_declarations(node.body) if multiline_block?(node.body)
@ -59,12 +59,11 @@ module RuboCop
first_example = find_first_example(node)
return unless first_example
node.each_child_node do |child|
next if child.sibling_index < first_example.sibling_index
next unless let?(child)
first_example.right_siblings.each do |sibling|
next unless let?(sibling)
add_offense(child) do |corrector|
autocorrect(corrector, child, first_example)
add_offense(sibling) do |corrector|
autocorrect(corrector, sibling, first_example)
end
end
end

View File

@ -6,20 +6,20 @@ module RuboCop
# Checks unreferenced `let!` calls being used for test setup.
#
# @example
# # Bad
# # bad
# let!(:my_widget) { create(:widget) }
#
# it 'counts widgets' do
# expect(Widget.count).to eq(1)
# end
#
# # Good
# # good
# it 'counts widgets' do
# create(:widget)
# expect(Widget.count).to eq(1)
# end
#
# # Good
# # good
# before { create(:widget) }
#
# it 'counts widgets' do
@ -49,7 +49,7 @@ module RuboCop
# @!method method_called?(node)
def_node_search :method_called?, '(send nil? %)'
def on_block(node)
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
return unless example_or_shared_group_or_including?(node)
unused_let_bang(node) do |let|

View File

@ -9,7 +9,7 @@ module RuboCop
# # bad
# allow(foo).to receive_message_chain(:bar, :baz).and_return(42)
#
# # better
# # good
# thing = Thing.new(baz: 42)
# allow(foo).to receive(:bar).and_return(thing)
#

View File

@ -19,10 +19,11 @@ module RuboCop
#
# describe "A feature example" do
# end
#
class MissingExampleGroupArgument < Base
MSG = 'The first argument to `%<method>s` should not be empty.'
def on_block(node)
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
return unless example_group?(node)
return if node.send_node.arguments?

View File

@ -0,0 +1,99 @@
# frozen_string_literal: true
module RuboCop
module Cop
module RSpec
# Helps parsing css selector.
module CssSelector
COMMON_OPTIONS = %w[
above below left_of right_of near count minimum maximum between text
id class style visible obscured exact exact_text normalize_ws match
wait filter_set focused
].freeze
module_function
# @param selector [String]
# @return [Boolean]
# @example
# id?('#some-id') # => true
# id?('.some-class') # => false
def id?(selector)
selector.start_with?('#')
end
# @param selector [String]
# @return [Boolean]
# @example
# attribute?('[attribute]') # => true
# attribute?('attribute') # => false
def attribute?(selector)
selector.start_with?('[')
end
# @param selector [String]
# @return [Array<String>]
# @example
# attributes('a[foo-bar_baz]') # => {"foo-bar_baz=>true}
# attributes('button[foo][bar]') # => {"foo"=>true, "bar"=>true}
# attributes('table[foo=bar]') # => {"foo"=>"'bar'"}
def attributes(selector)
selector.scan(/\[(.*?)\]/).flatten.to_h do |attr|
key, value = attr.split('=')
[key, normalize_value(value)]
end
end
# @param selector [String]
# @return [Boolean]
# @example
# common_attributes?('a[focused]') # => true
# common_attributes?('button[focused][visible]') # => true
# common_attributes?('table[id=some-id]') # => true
# common_attributes?('h1[invalid]') # => false
def common_attributes?(selector)
attributes(selector).keys.difference(COMMON_OPTIONS).none?
end
# @param selector [String]
# @return [Array<String>]
# @example
# pseudo_classes('button:not([disabled])') # => ['not()']
# pseudo_classes('a:enabled:not([valid])') # => ['enabled', 'not()']
def pseudo_classes(selector)
# Attributes must be excluded or else the colon in the `href`s URL
# will also be picked up as pseudo classes.
# "a:not([href='http://example.com']):enabled" => "a:not():enabled"
ignored_attribute = selector.gsub(/\[.*?\]/, '')
# "a:not():enabled" => ["not()", "enabled"]
ignored_attribute.scan(/:([^:]*)/).flatten
end
# @param selector [String]
# @return [Boolean]
# @example
# multiple_selectors?('a.cls b#id') # => true
# multiple_selectors?('a.cls') # => false
def multiple_selectors?(selector)
selector.match?(/[ >,+]/)
end
# @param value [String]
# @return [Boolean, String]
# @example
# normalize_value('true') # => true
# normalize_value('false') # => false
# normalize_value(nil) # => false
# normalize_value("foo") # => "'foo'"
def normalize_value(value)
case value
when 'true' then true
when 'false' then false
when nil then true
else "'#{value}'"
end
end
end
end
end
end

View File

@ -0,0 +1,23 @@
# frozen_string_literal: true
module RuboCop
module Cop
module RSpec
# Helps to find namespace of the node.
module Namespace
private
# @param node [RuboCop::AST::Node]
# @return [Array<String>]
# @example
# namespace(node) # => ['A', 'B', 'C']
def namespace(node)
node
.each_ancestor(:class, :module)
.reverse_each
.flat_map { |ancestor| ancestor.defined_module_name.split('::') }
end
end
end
end
end

View File

@ -22,6 +22,7 @@ module RuboCop
# describe '.do_something_else' do
# end
# end
#
class MultipleDescribes < Base
include TopLevelGroup

View File

@ -11,7 +11,6 @@ module RuboCop
# and works with `--auto-gen-config`.
#
# @example
#
# # bad
# describe UserCreator do
# it 'builds a user' do
@ -32,7 +31,6 @@ module RuboCop
# end
#
# @example `aggregate_failures: true` (default)
#
# # good - the cop ignores when RSpec aggregates failures
# describe UserCreator do
# it 'builds a user', :aggregate_failures do
@ -42,7 +40,6 @@ module RuboCop
# end
#
# @example `aggregate_failures: false`
#
# # Detected as an offense
# describe UserCreator do
# it 'builds a user', aggregate_failures: false do
@ -52,7 +49,6 @@ module RuboCop
# end
#
# @example configuration
#
# # .rubocop.yml
# # RSpec/MultipleExpectations:
# # Max: 2
@ -88,7 +84,7 @@ module RuboCop
(block (send nil? :aggregate_failures ...) ...)
PATTERN
def on_block(node)
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
return unless example?(node)
return if example_with_aggregate_failures?(node)

View File

@ -56,7 +56,6 @@ module RuboCop
# end
#
# @example when disabling AllowSubject configuration
#
# # rubocop.yml
# # RSpec/MultipleMemoizedHelpers:
# # AllowSubject: false
@ -72,7 +71,6 @@ module RuboCop
# end
#
# @example with Max configuration
#
# # rubocop.yml
# # RSpec/MultipleMemoizedHelpers:
# # Max: 1
@ -89,7 +87,7 @@ module RuboCop
MSG = 'Example group has too many memoized helpers [%<count>d/%<max>d]'
def on_block(node)
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
return unless spec_group?(node)
count = all_helpers(node).uniq.count

View File

@ -6,7 +6,6 @@ module RuboCop
# Checks if an example group defines `subject` multiple times.
#
# @example
#
# # bad
# describe Foo do
# subject(:user) { User.new }
@ -19,6 +18,21 @@ module RuboCop
# subject(:post) { Post.new }
# end
#
# # bad (does not support autocorrection)
# describe Foo do
# subject!(:user) { User.new }
# subject!(:post) { Post.new }
# end
#
# # good
# describe Foo do
# before do
# User.new
# Post.new
# end
# end
#
# This cop does not support autocorrection in some cases.
# The autocorrect behavior for this cop depends on the type of
# duplication:
#
@ -33,13 +47,14 @@ module RuboCop
# - If subjects are defined with `subject!` then we don't autocorrect.
# This is enough of an edge case that people can just move this to
# a `before` hook on their own
#
class MultipleSubjects < Base
extend AutoCorrector
include RangeHelp
MSG = 'Do not set more than one subject per example group'
def on_block(node)
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
return unless example_group?(node)
subjects = RuboCop::RSpec::ExampleGroup.new(node).subjects

View File

@ -41,6 +41,7 @@ module RuboCop
#
# it { is_expected.to be_valid }
# end
#
class NamedSubject < Base
MSG = 'Name your test subject if you need to reference it explicitly.'
@ -55,7 +56,7 @@ module RuboCop
# @!method subject_usage(node)
def_node_search :subject_usage, '$(send nil? :subject)'
def on_block(node)
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
if !example_or_hook_block?(node) || ignored_shared_example?(node)
return
end

View File

@ -36,7 +36,7 @@ module RuboCop
# end
# end
#
# # better
# # good
# context 'using some feature as an admin' do
# let(:some) { :various }
# let(:feature) { :setup }
@ -53,34 +53,40 @@ module RuboCop
# it 'yada yada'
# end
#
# @example configuration
#
# # .rubocop.yml
# # RSpec/NestedGroups:
# # Max: 2
#
# context 'when using some feature' do
# let(:some) { :various }
# let(:feature) { :setup }
#
# context 'when user is signed in' do
# let(:user) do
# UserCreate.call(user_attributes)
# @example `Max: 3` (default)
# # bad
# describe Foo do
# context 'foo' do
# context 'bar' do
# context 'baz' do # flagged by rubocop
# end
# end
# end
# end
#
# let(:user_attributes) do
# {
# name: 'John',
# age: 22,
# role: role
# }
# @example `Max: 2`
# # bad
# describe Foo do
# context 'foo' do
# context 'bar' do # flagged by rubocop
# context 'baz' do # flagged by rubocop
# end
# end
# end
# end
#
# context 'when user is an admin' do # flagged by rubocop
# let(:role) { 'admin' }
# @example `AllowedGroups: [] (default)`
# describe Foo do # <-- nested groups 1
# context 'foo' do # <-- nested groups 2
# context 'bar' do # <-- nested groups 3
# end
# end
# end
#
# it 'blah blah'
# it 'yada yada'
# @example `AllowedGroups: [path]`
# describe Foo do # <-- nested groups 1
# path '/foo' do # <-- nested groups 1 (not counted)
# context 'bar' do # <-- nested groups 2
# end
# end
# end
@ -113,13 +119,23 @@ module RuboCop
example_group = example_group?(node)
yield node, nesting if example_group && nesting > max_nesting
next_nesting = example_group ? nesting + 1 : nesting
next_nesting = if count_up_nesting?(node, example_group)
nesting + 1
else
nesting
end
node.each_child_node(:block, :begin) do |child|
find_nested_example_groups(child, nesting: next_nesting, &block)
end
end
def count_up_nesting?(node, example_group)
example_group &&
(node.block_type? &&
!allowed_groups.include?(node.method_name))
end
def message(nesting)
format(MSG, total: nesting, max: max_nesting)
end
@ -136,6 +152,10 @@ module RuboCop
cop_config.fetch('Max', 3)
end
end
def allowed_groups
@allowed_groups ||= cop_config.fetch('AllowedGroups', [])
end
end
end
end

View File

@ -0,0 +1,64 @@
# frozen_string_literal: true
module RuboCop
module Cop
module RSpec
# Checks if an example contains any expectation.
#
# All RSpec's example and expectation methods are covered by default.
# If you are using your own custom methods,
# add the following configuration:
#
# RSpec:
# Language:
# Examples:
# Regular:
# - custom_it
# Expectations:
# - custom_expect
#
# @example
# # bad
# it do
# a?
# end
#
# # good
# it do
# expect(a?).to be(true)
# end
#
class NoExpectationExample < Base
MSG = 'No expectation found in this example.'
# @!method regular_or_focused_example?(node)
# @param [RuboCop::AST::Node] node
# @return [Boolean]
def_node_matcher :regular_or_focused_example?, <<~PATTERN
{
#{block_pattern('{#Examples.regular | #Examples.focused}')}
#{numblock_pattern('{#Examples.regular | #Examples.focused}')}
}
PATTERN
# @!method including_any_expectation?(node)
# @param [RuboCop::AST::Node] node
# @return [Boolean]
def_node_search(
:including_any_expectation?,
send_pattern('#Expectations.all')
)
# @param [RuboCop::AST::BlockNode] node
def on_block(node)
return unless regular_or_focused_example?(node)
return if including_any_expectation?(node)
add_offense(node)
end
alias on_numblock on_block
end
end
end
end

View File

@ -6,7 +6,6 @@ module RuboCop
# Checks for consistent method usage for negating expectations.
#
# @example `EnforcedStyle: not_to` (default)
#
# # bad
# it '...' do
# expect(false).to_not be_true
@ -18,7 +17,6 @@ module RuboCop
# end
#
# @example `EnforcedStyle: to_not`
#
# # bad
# it '...' do
# expect(false).not_to be_true
@ -28,6 +26,7 @@ module RuboCop
# it '...' do
# expect(false).to_not be_true
# end
#
class NotToNot < Base
extend AutoCorrector
include ConfigurableEnforcedStyle

View File

@ -21,6 +21,7 @@ module RuboCop
# let(:foo) { bar }
# let(:baz) { baz }
# let!(:other) { other }
#
class OverwritingSetup < Base
MSG = '`%<name>s` is already defined.'
@ -30,7 +31,7 @@ module RuboCop
# @!method first_argument_name(node)
def_node_matcher :first_argument_name, '(send _ _ ({str sym} $_))'
def on_block(node)
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
return unless example_group_with_body?(node)
find_duplicates(node.body) do |duplicate, name|

View File

@ -31,6 +31,7 @@ module RuboCop
# # good
# describe MyClass do
# end
#
class Pending < Base
MSG = 'Pending spec found.'

View File

@ -276,6 +276,7 @@ module RuboCop
#
# # good - the above code is rewritten to it by this cop
# expect(foo.something?).to be_truthy
#
class PredicateMatcher < Base
extend AutoCorrector
include ConfigurableEnforcedStyle
@ -291,7 +292,7 @@ module RuboCop
end
end
def on_block(node)
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
check_explicit(node) if style == :explicit
end

View File

@ -7,7 +7,6 @@ module RuboCop
# Checks that tests use RSpec `before` hook over Rails `setup` method.
#
# @example
#
# # bad
# setup do
# allow(foo).to receive(:bar)
@ -30,7 +29,7 @@ module RuboCop
(args) _)
PATTERN
def on_block(node)
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
setup_call(node) do |setup|
add_offense(node) do |corrector|
corrector.replace setup, 'before'

View File

@ -6,22 +6,21 @@ module RuboCop
# Check for `once` and `twice` receive counts matchers usage.
#
# @example
# # bad
# expect(foo).to receive(:bar).exactly(1).times
# expect(foo).to receive(:bar).exactly(2).times
# expect(foo).to receive(:bar).at_least(1).times
# expect(foo).to receive(:bar).at_least(2).times
# expect(foo).to receive(:bar).at_most(1).times
# expect(foo).to receive(:bar).at_most(2).times
#
# # bad
# expect(foo).to receive(:bar).exactly(1).times
# expect(foo).to receive(:bar).exactly(2).times
# expect(foo).to receive(:bar).at_least(1).times
# expect(foo).to receive(:bar).at_least(2).times
# expect(foo).to receive(:bar).at_most(1).times
# expect(foo).to receive(:bar).at_most(2).times
#
# # good
# expect(foo).to receive(:bar).once
# expect(foo).to receive(:bar).twice
# expect(foo).to receive(:bar).at_least(:once)
# expect(foo).to receive(:bar).at_least(:twice)
# expect(foo).to receive(:bar).at_most(:once)
# expect(foo).to receive(:bar).at_most(:twice).times
# # good
# expect(foo).to receive(:bar).once
# expect(foo).to receive(:bar).twice
# expect(foo).to receive(:bar).at_least(:once)
# expect(foo).to receive(:bar).at_least(:twice)
# expect(foo).to receive(:bar).at_most(:once)
# expect(foo).to receive(:bar).at_most(:twice).times
#
class ReceiveCounts < Base
extend AutoCorrector

View File

@ -6,12 +6,11 @@ module RuboCop
# Prefer `not_to receive(...)` over `receive(...).never`.
#
# @example
# # bad
# expect(foo).to receive(:bar).never
#
# # bad
# expect(foo).to receive(:bar).never
#
# # good
# expect(foo).not_to receive(:bar)
# # good
# expect(foo).not_to receive(:bar)
#
class ReceiveNever < Base
extend AutoCorrector

View File

@ -6,44 +6,43 @@ module RuboCop
# Check for repeated description strings in example groups.
#
# @example
#
# # bad
# RSpec.describe User do
# it 'is valid' do
# # ...
# end
#
# it 'is valid' do
# # ...
# end
# # bad
# RSpec.describe User do
# it 'is valid' do
# # ...
# end
#
# # good
# RSpec.describe User do
# it 'is valid when first and last name are present' do
# # ...
# end
# it 'is valid' do
# # ...
# end
# end
#
# it 'is valid when last name only is present' do
# # ...
# end
# # good
# RSpec.describe User do
# it 'is valid when first and last name are present' do
# # ...
# end
#
# # good
# RSpec.describe User do
# it 'is valid' do
# # ...
# end
#
# it 'is valid', :flag do
# # ...
# end
# it 'is valid when last name only is present' do
# # ...
# end
# end
#
# # good
# RSpec.describe User do
# it 'is valid' do
# # ...
# end
#
# it 'is valid', :flag do
# # ...
# end
# end
#
class RepeatedDescription < Base
MSG = "Don't repeat descriptions within an example group."
def on_block(node)
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
return unless example_group?(node)
repeated_descriptions(node).each do |repeated_description|

View File

@ -18,7 +18,7 @@ module RuboCop
class RepeatedExample < Base
MSG = "Don't repeat examples within an example group."
def on_block(node)
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
return unless example_group?(node)
repeated_examples(node).each do |repeated_example|

View File

@ -6,42 +6,41 @@ module RuboCop
# Check for repeated describe and context block body.
#
# @example
# # bad
# describe 'cool feature x' do
# it { cool_predicate }
# end
#
# # bad
# describe 'cool feature x' do
# it { cool_predicate }
# end
# describe 'cool feature y' do
# it { cool_predicate }
# end
#
# describe 'cool feature y' do
# it { cool_predicate }
# end
# # good
# describe 'cool feature' do
# it { cool_predicate }
# end
#
# # good
# describe 'cool feature' do
# it { cool_predicate }
# end
# describe 'another cool feature' do
# it { another_predicate }
# end
#
# describe 'another cool feature' do
# it { another_predicate }
# end
# # good
# context 'when case x', :tag do
# it { cool_predicate }
# end
#
# # good
# context 'when case x', :tag do
# it { cool_predicate }
# end
# context 'when case y' do
# it { cool_predicate }
# end
#
# context 'when case y' do
# it { cool_predicate }
# end
# # good
# context Array do
# it { is_expected.to respond_to :each }
# end
#
# # good
# context Array do
# it { is_expected.to respond_to :each }
# end
#
# context Hash do
# it { is_expected.to respond_to :each }
# end
# context Hash do
# it { is_expected.to respond_to :each }
# end
#
class RepeatedExampleGroupBody < Base
MSG = 'Repeated %<group>s block body on line(s) %<loc>s'

View File

@ -6,42 +6,41 @@ module RuboCop
# Check for repeated example group descriptions.
#
# @example
# # bad
# describe 'cool feature' do
# # example group
# end
#
# # bad
# describe 'cool feature' do
# # example group
# end
# describe 'cool feature' do
# # example group
# end
#
# describe 'cool feature' do
# # example group
# end
# # bad
# context 'when case x' do
# # example group
# end
#
# # bad
# context 'when case x' do
# # example group
# end
# describe 'when case x' do
# # example group
# end
#
# describe 'when case x' do
# # example group
# end
# # good
# describe 'cool feature' do
# # example group
# end
#
# # good
# describe 'cool feature' do
# # example group
# end
# describe 'another cool feature' do
# # example group
# end
#
# describe 'another cool feature' do
# # example group
# end
# # good
# context 'when case x' do
# # example group
# end
#
# # good
# context 'when case x' do
# # example group
# end
#
# context 'when another case' do
# # example group
# end
# context 'when another case' do
# # example group
# end
#
class RepeatedExampleGroupDescription < Base
MSG = 'Repeated %<group>s block description on line(s) %<loc>s'

View File

@ -6,45 +6,44 @@ module RuboCop
# Check for repeated include of shared examples.
#
# @example
# # bad
# describe 'foo' do
# include_examples 'cool stuff'
# include_examples 'cool stuff'
# end
#
# # bad
# describe 'foo' do
# include_examples 'cool stuff'
# include_examples 'cool stuff'
# end
# # bad
# describe 'foo' do
# it_behaves_like 'a cool', 'thing'
# it_behaves_like 'a cool', 'thing'
# end
#
# # bad
# describe 'foo' do
# it_behaves_like 'a cool', 'thing'
# it_behaves_like 'a cool', 'thing'
# end
# # bad
# context 'foo' do
# it_should_behave_like 'a duck'
# it_should_behave_like 'a duck'
# end
#
# # bad
# context 'foo' do
# it_should_behave_like 'a duck'
# it_should_behave_like 'a duck'
# end
# # good
# describe 'foo' do
# include_examples 'cool stuff'
# end
#
# # good
# describe 'foo' do
# include_examples 'cool stuff'
# end
# describe 'bar' do
# include_examples 'cool stuff'
# end
#
# describe 'bar' do
# include_examples 'cool stuff'
# end
# # good
# describe 'foo' do
# it_behaves_like 'a cool', 'thing'
# it_behaves_like 'a cool', 'person'
# end
#
# # good
# describe 'foo' do
# it_behaves_like 'a cool', 'thing'
# it_behaves_like 'a cool', 'person'
# end
#
# # good
# context 'foo' do
# it_should_behave_like 'a duck'
# it_should_behave_like 'a goose'
# end
# # good
# context 'foo' do
# it_should_behave_like 'a duck'
# it_should_behave_like 'a goose'
# end
#
class RepeatedIncludeExample < Base
MSG = 'Repeated include of shared_examples %<name>s ' \

View File

@ -59,7 +59,7 @@ module RuboCop
check_and_return_call(node)
end
def on_block(node)
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
return unless style == :and_return
return unless stub_with_block?(node)

Some files were not shown because too many files have changed in this diff Show More