brew vendor-gems: commit updates.

This commit is contained in:
BrewTestBot 2022-11-05 16:01:02 +00:00 committed by Bo Anderson
parent d4ff683691
commit 2be1c8cc78
No known key found for this signature in database
GPG Key ID: 3DB94E204E137D65
143 changed files with 1392 additions and 430 deletions

View File

@ -107,7 +107,7 @@ $:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/rubocop-1.35.1/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/rubocop-performance-1.15.0/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/rubocop-rails-2.16.1/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/rubocop-rspec-2.13.2/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/rubocop-rspec-2.15.0/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/rubocop-sorbet-0.6.11/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/ruby-macho-3.0.0/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/simplecov-html-0.12.3/lib")

View File

@ -1,158 +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', 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

@ -1,100 +0,0 @@
# frozen_string_literal: true
module RuboCop
module Cop
module RSpec
# Checks for usage of implicit subject (`is_expected` / `should`).
#
# This cop can be configured using the `EnforcedStyle` option
#
# @example `EnforcedStyle: single_line_only` (default)
# # bad
# it do
# is_expected.to be_truthy
# end
#
# # good
# it { is_expected.to be_truthy }
# it do
# expect(subject).to be_truthy
# end
#
# @example `EnforcedStyle: single_statement_only`
# # bad
# it do
# foo = 1
# is_expected.to be_truthy
# end
#
# # good
# it do
# foo = 1
# expect(subject).to be_truthy
# end
# it do
# is_expected.to be_truthy
# end
#
# @example `EnforcedStyle: disallow`
# # bad
# it { is_expected.to be_truthy }
#
# # good
# it { expect(subject).to be_truthy }
#
class ImplicitSubject < Base
extend AutoCorrector
include ConfigurableEnforcedStyle
MSG = "Don't use implicit subject."
RESTRICT_ON_SEND = %i[is_expected should should_not].freeze
# @!method implicit_subject?(node)
def_node_matcher :implicit_subject?, <<-PATTERN
(send nil? {:should :should_not :is_expected} ...)
PATTERN
def on_send(node)
return unless implicit_subject?(node)
return if valid_usage?(node)
add_offense(node) do |corrector|
autocorrect(corrector, node)
end
end
private
def autocorrect(corrector, node)
replacement = 'expect(subject)'
case node.method_name
when :should
replacement += '.to'
when :should_not
replacement += '.not_to'
end
corrector.replace(node.loc.selector, replacement)
end
def valid_usage?(node)
example = node.ancestors.find { |parent| example?(parent) }
return false if example.nil?
example.method?(:its) || allowed_by_style?(example)
end
def allowed_by_style?(example)
case style
when :single_line_only
example.single_line?
when :single_statement_only
!example.body.begin_type?
else
false
end
end
end
end
end
end

View File

@ -1,76 +0,0 @@
# frozen_string_literal: true
module RuboCop
module Cop
module RSpec
# Checks for explicitly referenced test subjects.
#
# RSpec lets you declare an "implicit subject" using `subject { ... }`
# which allows for tests like `it { is_expected.to be_valid }`.
# If you need to reference your test subject you should explicitly
# name it using `subject(:your_subject_name) { ... }`. Your test subjects
# should be the most important object in your tests so they deserve
# a descriptive name.
#
# This cop can be configured in your configuration using the
# `IgnoreSharedExamples` which will not report offenses for implicit
# subjects in shared example groups.
#
# @example
# # bad
# RSpec.describe User do
# subject { described_class.new }
#
# it 'is valid' do
# expect(subject.valid?).to be(true)
# end
# end
#
# # good
# RSpec.describe Foo do
# subject(:user) { described_class.new }
#
# it 'is valid' do
# expect(user.valid?).to be(true)
# end
# end
#
# # also good
# RSpec.describe Foo do
# subject(:user) { described_class.new }
#
# it { is_expected.to be_valid }
# end
#
class NamedSubject < Base
MSG = 'Name your test subject if you need to reference it explicitly.'
# @!method example_or_hook_block?(node)
def_node_matcher :example_or_hook_block?,
block_pattern('{#Examples.all #Hooks.all}')
# @!method shared_example?(node)
def_node_matcher :shared_example?,
block_pattern('#SharedGroups.examples')
# @!method subject_usage(node)
def_node_search :subject_usage, '$(send nil? :subject)'
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
if !example_or_hook_block?(node) || ignored_shared_example?(node)
return
end
subject_usage(node) do |subject_node|
add_offense(subject_node.loc.selector)
end
end
def ignored_shared_example?(node)
cop_config['IgnoreSharedExamples'] &&
node.each_ancestor(:block).any?(&method(:shared_example?))
end
end
end
end
end

View File

@ -1,17 +0,0 @@
# frozen_string_literal: true
module RuboCop
module RSpec
module FactoryBot
# Contains node matchers for common FactoryBot DSL.
module Language
extend RuboCop::NodePattern::Macros
# @!method factory_bot?(node)
def_node_matcher :factory_bot?, <<~PATTERN
(const {nil? cbase} {:FactoryGirl :FactoryBot})
PATTERN
end
end
end
end

View File

@ -12,8 +12,6 @@ RSpec:
- Expectations
- Helpers
- Hooks
- HookScopes
- Runners
- Subjects
ExampleGroups:
inherit_mode:
@ -81,12 +79,6 @@ RSpec:
- prepend_after
- after
- append_after
HookScopes:
- each
- example
- context
- all
- suite
Includes:
inherit_mode:
merge:
@ -98,10 +90,6 @@ RSpec:
- include_examples
Context:
- include_context
Runners:
- to
- to_not
- not_to
SharedGroups:
inherit_mode:
merge:
@ -194,7 +182,7 @@ RSpec/ChangeByZero:
Description: Prefer negated matchers over `to change.by(0)`.
Enabled: pending
VersionAdded: '2.11'
VersionChanged: '2.13'
VersionChanged: '2.14'
Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ChangeByZero
NegatedMatcher: ~
@ -383,8 +371,10 @@ RSpec/ExampleWording:
have: has
HAVE: HAS
IgnoredWords: []
DisallowedExamples:
- works
VersionAdded: '1.0'
VersionChanged: '1.2'
VersionChanged: '2.13'
StyleGuide: https://rspec.rubystyle.guide/#should-in-example-docstrings
Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ExampleWording
@ -492,8 +482,9 @@ RSpec/ImplicitSubject:
- single_line_only
- single_statement_only
- disallow
- require_implicit
VersionAdded: '1.29'
VersionChanged: '1.30'
VersionChanged: '2.13'
Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ImplicitSubject
RSpec/InstanceSpy:
@ -621,8 +612,13 @@ RSpec/MultipleSubjects:
RSpec/NamedSubject:
Description: Checks for explicitly referenced test subjects.
Enabled: true
EnforcedStyle: always
SupportedStyles:
- always
- named_only
IgnoreSharedExamples: true
VersionAdded: 1.5.3
VersionChanged: '2.15'
StyleGuide: https://rspec.rubystyle.guide/#use-subject
Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/NamedSubject
@ -640,7 +636,11 @@ RSpec/NoExpectationExample:
Enabled: pending
Safe: false
VersionAdded: '2.13'
VersionChanged: '2.14'
Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/NoExpectationExample
AllowedPatterns:
- "^expect_"
- "^assert_"
RSpec/NotToNot:
Description: Checks for consistent method usage for negating expectations.
@ -763,6 +763,12 @@ RSpec/SingleArgumentMessageChain:
VersionChanged: '1.10'
Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/SingleArgumentMessageChain
RSpec/SortMetadata:
Description: Sort RSpec metadata alphabetically.
Enabled: pending
VersionAdded: '2.14'
Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/SortMetadata
RSpec/StubbedMock:
Description: Checks that message expectations do not have a configured response.
Enabled: true
@ -807,7 +813,6 @@ RSpec/VariableName:
- snake_case
- camelCase
AllowedPatterns: []
IgnoredPatterns: []
VersionAdded: '1.40'
VersionChanged: '2.13'
Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/VariableName
@ -866,6 +871,22 @@ RSpec/Capybara/FeatureMethods:
VersionChanged: '2.0'
Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Capybara/FeatureMethods
RSpec/Capybara/NegationMatcher:
Description: Enforces use of `have_no_*` or `not_to` for negated expectations.
Enabled: pending
VersionAdded: '2.14'
EnforcedStyle: not_to
SupportedStyles:
- have_no
- not_to
Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Capybara/NegationMatcher
RSpec/Capybara/SpecificActions:
Description: Checks for there is a more specific actions offered by Capybara.
Enabled: pending
VersionAdded: '2.14'
Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Capybara/SpecificActions
RSpec/Capybara/SpecificFinders:
Description: Checks if there is a more specific finder offered by Capybara.
Enabled: pending
@ -901,6 +922,16 @@ RSpec/FactoryBot/AttributeDefinedStatically:
VersionChanged: '2.0'
Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/FactoryBot/AttributeDefinedStatically
RSpec/FactoryBot/ConsistentParenthesesStyle:
Description: Use a consistent style for parentheses in factory bot calls.
Enabled: pending
EnforcedStyle: require_parentheses
SupportedStyles:
- require_parentheses
- omit_parentheses
VersionAdded: '2.14'
Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/FactoryBot/ConsistentParenthesesStyle
RSpec/FactoryBot/CreateList:
Description: Checks for create_list usage.
Enabled: true
@ -954,6 +985,29 @@ RSpec/Rails/HaveHttpStatus:
VersionAdded: '2.12'
Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Rails/HaveHttpStatus
RSpec/Rails/InferredSpecType:
Description: Identifies redundant spec type.
Enabled: pending
Safe: false
VersionAdded: '2.14'
Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Rails/InferredSpecType
Inferences:
channels: channel
controllers: controller
features: feature
generator: generator
helpers: helper
jobs: job
mailboxes: mailbox
mailers: mailer
models: model
requests: request
integration: request
api: request
routing: routing
system: system
views: view
RSpec/Rails/HttpStatus:
Description: Enforces use of symbolic or numeric value to describe HTTP status.
Enabled: true

View File

@ -23,6 +23,8 @@ 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/cop/rspec/mixin/skip_or_pending'
require_relative 'rubocop/cop/rspec/mixin/capybara_help'
require_relative 'rubocop/rspec/concept'
require_relative 'rubocop/rspec/example_group'

View File

@ -0,0 +1,106 @@
# frozen_string_literal: true
module RuboCop
module Cop
module RSpec
module Capybara
# Enforces use of `have_no_*` or `not_to` for negated expectations.
#
# @example EnforcedStyle: not_to (default)
# # bad
# expect(page).to have_no_selector
# expect(page).to have_no_css('a')
#
# # good
# expect(page).not_to have_selector
# expect(page).not_to have_css('a')
#
# @example EnforcedStyle: have_no
# # bad
# expect(page).not_to have_selector
# expect(page).not_to have_css('a')
#
# # good
# expect(page).to have_no_selector
# expect(page).to have_no_css('a')
#
class NegationMatcher < Base
extend AutoCorrector
include ConfigurableEnforcedStyle
MSG = 'Use `expect(...).%<runner>s %<matcher>s`.'
CAPYBARA_MATCHERS = %w[
selector css xpath text title current_path link button
field checked_field unchecked_field select table
sibling ancestor
].freeze
POSITIVE_MATCHERS =
Set.new(CAPYBARA_MATCHERS) { |element| :"have_#{element}" }.freeze
NEGATIVE_MATCHERS =
Set.new(CAPYBARA_MATCHERS) { |element| :"have_no_#{element}" }
.freeze
RESTRICT_ON_SEND = (POSITIVE_MATCHERS + NEGATIVE_MATCHERS).freeze
# @!method not_to?(node)
def_node_matcher :not_to?, <<~PATTERN
(send ... :not_to
(send nil? %POSITIVE_MATCHERS ...))
PATTERN
# @!method have_no?(node)
def_node_matcher :have_no?, <<~PATTERN
(send ... :to
(send nil? %NEGATIVE_MATCHERS ...))
PATTERN
def on_send(node)
return unless offense?(node.parent)
matcher = node.method_name.to_s
add_offense(offense_range(node),
message: message(matcher)) do |corrector|
corrector.replace(node.parent.loc.selector, replaced_runner)
corrector.replace(node.loc.selector,
replaced_matcher(matcher))
end
end
private
def offense?(node)
(style == :have_no && not_to?(node)) ||
(style == :not_to && have_no?(node))
end
def offense_range(node)
node.parent.loc.selector.with(end_pos: node.loc.selector.end_pos)
end
def message(matcher)
format(MSG,
runner: replaced_runner,
matcher: replaced_matcher(matcher))
end
def replaced_runner
case style
when :have_no
'to'
when :not_to
'not_to'
end
end
def replaced_matcher(matcher)
case style
when :have_no
matcher.sub('have_', 'have_no_')
when :not_to
matcher.sub('have_no_', 'have_')
end
end
end
end
end
end
end

View File

@ -0,0 +1,85 @@
# frozen_string_literal: true
module RuboCop
module Cop
module RSpec
module Capybara
# Checks for there is a more specific actions offered by Capybara.
#
# @example
#
# # bad
# find('a').click
# find('button.cls').click
# find('a', exact_text: 'foo').click
# find('div button').click
#
# # good
# click_link
# click_button(class: 'cls')
# click_link(exact_text: 'foo')
# find('div').click_button
#
class SpecificActions < Base
MSG = "Prefer `%<good_action>s` over `find('%<selector>s').click`."
RESTRICT_ON_SEND = %i[click].freeze
SPECIFIC_ACTION = {
'button' => 'button',
'a' => 'link'
}.freeze
# @!method click_on_selector(node)
def_node_matcher :click_on_selector, <<-PATTERN
(send _ :find (str $_) ...)
PATTERN
def on_send(node)
click_on_selector(node.receiver) do |arg|
next unless supported_selector?(arg)
# Always check the last selector in the case of multiple selectors
# separated by whitespace.
# because the `.click` is executed on the element to
# which the last selector points.
next unless (selector = last_selector(arg))
next unless (action = specific_action(selector))
next unless CapybaraHelp.specific_option?(node.receiver, arg,
action)
next unless CapybaraHelp.specific_pseudo_classes?(arg)
range = offense_range(node, node.receiver)
add_offense(range, message: message(action, selector))
end
end
private
def specific_action(selector)
SPECIFIC_ACTION[last_selector(selector)]
end
def supported_selector?(selector)
!selector.match?(/[>,+~]/)
end
def last_selector(arg)
arg.split.last[/^\w+/, 0]
end
def offense_range(node, receiver)
receiver.loc.selector.with(end_pos: node.loc.expression.end_pos)
end
def message(action, selector)
format(MSG,
good_action: good_action(action),
selector: selector)
end
def good_action(action)
"click_#{action}"
end
end
end
end
end
end

View File

@ -0,0 +1,81 @@
# 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
include CapybaraHelp
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
# @!method first_argument(node)
def_node_matcher :first_argument, <<-PATTERN
(send nil? _ (str $_) ... )
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_option?(node, arg, matcher)
next unless specific_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 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

@ -61,7 +61,7 @@ module RuboCop
extend AutoCorrector
MSG = 'Prefer `not_to change` over `to change.by(0)`.'
MSG_COMPOUND = 'Prefer %<preferred>s with compound expectations ' \
'over `change.by(0)`.'
'over `change.by(0)`.'
RESTRICT_ON_SEND = %i[change].freeze
# @!method expect_change_with_arguments(node)

View File

@ -43,7 +43,7 @@ module RuboCop
# # .rubocop.yml
# # RSpec/ContextWording:
# # AllowedPatterns:
# # - /とき$/
# # - とき$
#
# @example
# # bad
@ -92,7 +92,9 @@ module RuboCop
end
def expect_patterns
inspected = allowed_patterns.map(&:inspect)
inspected = allowed_patterns.map do |pattern|
pattern.inspect.gsub(/\A"|"\z/, '/')
end
return inspected.first if inspected.size == 1
inspected << "or #{inspected.pop}"

View File

@ -6,12 +6,17 @@ module RuboCop
# Checks for common mistakes in example descriptions.
#
# This cop will correct docstrings that begin with 'should' and 'it'.
# This cop will also look for insufficient examples and call them out.
#
# @see http://betterspecs.org/#should
#
# The autocorrect is experimental - use with care! It can be configured
# with CustomTransform (e.g. have => has) and IgnoredWords (e.g. only).
#
# Use the DisallowedExamples setting to prevent unclear or insufficient
# descriptions. Please note that this config will not be treated as
# case sensitive.
#
# @example
# # bad
# it 'should find nothing' do
@ -30,11 +35,21 @@ module RuboCop
# it 'does things' do
# end
#
# @example `DisallowedExamples: ['works']` (default)
# # bad
# it 'works' do
# end
#
# # good
# it 'marks the task as done' do
# end
class ExampleWording < Base
extend AutoCorrector
MSG_SHOULD = 'Do not use should when describing your tests.'
MSG_IT = "Do not repeat 'it' when describing your tests."
MSG_INSUFFICIENT_DESCRIPTION = 'Your example description is ' \
'insufficient.'
SHOULD_PREFIX = /\Ashould(?:n't)?\b/i.freeze
IT_PREFIX = /\Ait /i.freeze
@ -53,6 +68,9 @@ module RuboCop
add_wording_offense(description_node, MSG_SHOULD)
elsif message.match?(IT_PREFIX)
add_wording_offense(description_node, MSG_IT)
elsif insufficient_docstring?(description_node)
add_offense(docstring(description_node),
message: MSG_INSUFFICIENT_DESCRIPTION)
end
end
end
@ -113,6 +131,19 @@ module RuboCop
def ignored_words
cop_config.fetch('IgnoredWords', [])
end
def insufficient_docstring?(description_node)
insufficient_examples.include?(preprocess(text(description_node)))
end
def insufficient_examples
examples = cop_config.fetch('DisallowedExamples', [])
examples.map! { |example| preprocess(example) }
end
def preprocess(message)
message.strip.squeeze(' ').downcase
end
end
end
end

View File

@ -0,0 +1,115 @@
# frozen_string_literal: true
module RuboCop
module Cop
module RSpec
module FactoryBot
# Use a consistent style for parentheses in factory bot calls.
#
# @example
#
# # bad
# create :user
# build(:user)
# create(:login)
# create :login
#
# @example `EnforcedStyle: require_parentheses` (default)
#
# # good
# create(:user)
# create(:user)
# create(:login)
# build(:login)
#
# @example `EnforcedStyle: omit_parentheses`
#
# # good
# create :user
# build :user
# create :login
# create :login
#
# # also good
# # when method name and first argument are not on same line
# create(
# :user
# )
# build(
# :user,
# name: 'foo'
# )
#
class ConsistentParenthesesStyle < Base
extend AutoCorrector
include ConfigurableEnforcedStyle
include RuboCop::RSpec::FactoryBot::Language
include RuboCop::Cop::Util
def self.autocorrect_incompatible_with
[Style::MethodCallWithArgsParentheses]
end
MSG_REQUIRE_PARENS = 'Prefer method call with parentheses'
MSG_OMIT_PARENS = 'Prefer method call without parentheses'
FACTORY_CALLS = RuboCop::RSpec::FactoryBot::Language::METHODS
RESTRICT_ON_SEND = FACTORY_CALLS
# @!method factory_call(node)
def_node_matcher :factory_call, <<-PATTERN
(send
{#factory_bot? nil?} %FACTORY_CALLS
{sym str send lvar} _*
)
PATTERN
def on_send(node)
return if ambiguous_without_parentheses?(node)
factory_call(node) do
if node.parenthesized?
process_with_parentheses(node)
else
process_without_parentheses(node)
end
end
end
def process_with_parentheses(node)
return unless style == :omit_parentheses
return unless same_line?(node, node.first_argument)
add_offense(node.loc.selector,
message: MSG_OMIT_PARENS) do |corrector|
remove_parentheses(corrector, node)
end
end
def process_without_parentheses(node)
return unless style == :require_parentheses
add_offense(node.loc.selector,
message: MSG_REQUIRE_PARENS) do |corrector|
add_parentheses(node, corrector)
end
end
def ambiguous_without_parentheses?(node)
node.parent&.send_type? ||
node.parent&.pair_type? ||
node.parent&.array_type?
end
private
def remove_parentheses(corrector, node)
corrector.replace(node.location.begin, ' ')
corrector.remove(node.location.end)
end
end
end
end
end
end

View File

@ -238,8 +238,8 @@ module RuboCop
indent = ' ' * node.body.loc.column
indent_end = ' ' * node.parent.loc.column
" do #{node.arguments.source}\n" \
"#{indent}#{node.body.source}\n" \
"#{indent_end}end"
"#{indent}#{node.body.source}\n" \
"#{indent_end}end"
end
def format_singleline_block(node)

View File

@ -54,25 +54,7 @@ module RuboCop
MSG = 'Use `%<method>s` from `FactoryBot::Syntax::Methods`.'
RESTRICT_ON_SEND = %i[
attributes_for
attributes_for_list
attributes_for_pair
build
build_list
build_pair
build_stubbed
build_stubbed_list
build_stubbed_pair
create
create_list
create_pair
generate
generate_list
null
null_list
null_pair
].to_set.freeze
RESTRICT_ON_SEND = RuboCop::RSpec::FactoryBot::Language::METHODS
def on_send(node)
return unless factory_bot?(node.receiver)

View File

@ -76,8 +76,6 @@ module RuboCop
return unless top_level_groups.one?
example_group(node) do |send_node, example_group, arguments|
next if routing_spec?(arguments)
ensure_correct_file_path(send_node, example_group, arguments)
end
end
@ -85,7 +83,7 @@ module RuboCop
private
def ensure_correct_file_path(send_node, example_group, arguments)
pattern = pattern_for(example_group, arguments.first)
pattern = pattern_for(example_group, arguments)
return if filename_ends_with?(pattern)
# For the suffix shown in the offense message, modify the regular
@ -97,11 +95,13 @@ module RuboCop
end
def routing_spec?(args)
args.any?(&method(:routing_metadata?))
args.any?(&method(:routing_metadata?)) || routing_spec_path?
end
def pattern_for(example_group, method_name)
if spec_suffix_only? || !example_group.const_type?
def pattern_for(example_group, arguments)
method_name = arguments.first
if spec_suffix_only? || !example_group.const_type? ||
routing_spec?(arguments)
return pattern_for_spec_suffix_only
end
@ -149,8 +149,7 @@ module RuboCop
end
def filename_ends_with?(pattern)
filename = File.expand_path(processed_source.buffer.name)
filename.match?("#{pattern}$")
expanded_file_path.match?("#{pattern}$")
end
def relevant_rubocop_rspec_file?(_file)
@ -160,6 +159,14 @@ module RuboCop
def spec_suffix_only?
cop_config['SpecSuffixOnly']
end
def routing_spec_path?
expanded_file_path.include?('spec/routing/')
end
def expanded_file_path
File.expand_path(processed_source.buffer.name)
end
end
end
end

View File

@ -0,0 +1,167 @@
# frozen_string_literal: true
module RuboCop
module Cop
module RSpec
# Checks for usage of implicit subject (`is_expected` / `should`).
#
# This cop can be configured using the `EnforcedStyle` option
#
# @example `EnforcedStyle: single_line_only` (default)
# # bad
# it do
# is_expected.to be_truthy
# end
#
# # good
# it { is_expected.to be_truthy }
# it do
# expect(subject).to be_truthy
# end
#
# @example `EnforcedStyle: single_statement_only`
# # bad
# it do
# foo = 1
# is_expected.to be_truthy
# end
#
# # good
# it do
# foo = 1
# expect(subject).to be_truthy
# end
# it do
# is_expected.to be_truthy
# end
#
# @example `EnforcedStyle: disallow`
# # bad
# it { is_expected.to be_truthy }
#
# # good
# it { expect(subject).to be_truthy }
#
# @example `EnforcedStyle: require_implicit`
# # bad
# it { expect(subject).to be_truthy }
#
# # good
# it { is_expected.to be_truthy }
#
# # bad
# it do
# expect(subject).to be_truthy
# end
#
# # good
# it do
# is_expected.to be_truthy
# end
#
# # good
# it { expect(named_subject).to be_truthy }
#
class ImplicitSubject < Base
extend AutoCorrector
include ConfigurableEnforcedStyle
MSG_REQUIRE_EXPLICIT = "Don't use implicit subject."
MSG_REQUIRE_IMPLICIT = "Don't use explicit subject."
RESTRICT_ON_SEND = %i[
expect
is_expected
should
should_not
].freeze
# @!method explicit_unnamed_subject?(node)
def_node_matcher :explicit_unnamed_subject?, <<-PATTERN
(send nil? :expect (send nil? :subject))
PATTERN
# @!method implicit_subject?(node)
def_node_matcher :implicit_subject?, <<-PATTERN
(send nil? {:should :should_not :is_expected} ...)
PATTERN
def on_send(node)
return unless invalid?(node)
add_offense(node) do |corrector|
autocorrect(corrector, node)
end
end
private
def autocorrect(corrector, node)
case node.method_name
when :expect
corrector.replace(node, 'is_expected')
when :is_expected
corrector.replace(node.location.selector, 'expect(subject)')
when :should
corrector.replace(node.location.selector, 'expect(subject).to')
when :should_not
corrector.replace(node.location.selector, 'expect(subject).not_to')
end
end
def message(_node)
case style
when :require_implicit
MSG_REQUIRE_IMPLICIT
else
MSG_REQUIRE_EXPLICIT
end
end
def invalid?(node)
case style
when :require_implicit
explicit_unnamed_subject?(node)
when :disallow
implicit_subject_in_non_its?(node)
when :single_line_only
implicit_subject_in_non_its_and_non_single_line?(node)
when :single_statement_only
implicit_subject_in_non_its_and_non_single_statement?(node)
end
end
def implicit_subject_in_non_its?(node)
implicit_subject?(node) && !its?(node)
end
def implicit_subject_in_non_its_and_non_single_line?(node)
implicit_subject_in_non_its?(node) && !single_line?(node)
end
def implicit_subject_in_non_its_and_non_single_statement?(node)
implicit_subject_in_non_its?(node) && !single_statement?(node)
end
def its?(node)
example_of(node)&.method?(:its)
end
def single_line?(node)
example_of(node)&.single_line?
end
def single_statement?(node)
!example_of(node)&.body&.begin_type?
end
def example_of(node)
node.each_ancestor.find do |ancestor|
example?(ancestor)
end
end
end
end
end
end

View File

@ -43,6 +43,14 @@ module RuboCop
}
PATTERN
# @!method include_examples?(node)
def_node_matcher :include_examples?, <<~PATTERN
{
#{block_pattern(':include_examples')}
#{send_pattern(':include_examples')}
}
PATTERN
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
return unless example_group_with_body?(node)
@ -51,6 +59,10 @@ module RuboCop
private
def example_group_with_include_examples?(body)
body.children.any? { |sibling| include_examples?(sibling) }
end
def multiline_block?(block)
block.begin_type?
end
@ -59,11 +71,13 @@ module RuboCop
first_example = find_first_example(node)
return unless first_example
correct = !example_group_with_include_examples?(node)
first_example.right_siblings.each do |sibling|
next unless let?(sibling)
add_offense(sibling) do |corrector|
autocorrect(corrector, sibling, first_example)
autocorrect(corrector, sibling, first_example) if correct
end
end
end

View File

@ -0,0 +1,80 @@
# frozen_string_literal: true
module RuboCop
module Cop
module RSpec
# Help methods for capybara.
module CapybaraHelp
module_function
# @param node [RuboCop::AST::SendNode]
# @param locator [String]
# @param element [String]
# @return [Boolean]
def specific_option?(node, locator, element)
attrs = CssSelector.attributes(locator).keys
return false unless replaceable_element?(node, element, attrs)
attrs.all? do |attr|
CssSelector.specific_options?(element, attr)
end
end
# @param locator [String]
# @return [Boolean]
def specific_pseudo_classes?(locator)
CssSelector.pseudo_classes(locator).all? do |pseudo_class|
replaceable_pseudo_class?(pseudo_class, locator)
end
end
# @param pseudo_class [String]
# @param locator [String]
# @return [Boolean]
def replaceable_pseudo_class?(pseudo_class, locator)
return false unless CssSelector.specific_pesudo_classes?(pseudo_class)
case pseudo_class
when 'not()' then replaceable_pseudo_class_not?(locator)
else true
end
end
# @param locator [String]
# @return [Boolean]
def replaceable_pseudo_class_not?(locator)
locator.scan(/not\(.*?\)/).all? do |negation|
CssSelector.attributes(negation).values.all? do |v|
v.is_a?(TrueClass) || v.is_a?(FalseClass)
end
end
end
# @param node [RuboCop::AST::SendNode]
# @param element [String]
# @param attrs [Array<String>]
# @return [Boolean]
def replaceable_element?(node, element, attrs)
case element
when 'link' then replaceable_to_link?(node, attrs)
else true
end
end
# @param node [RuboCop::AST::SendNode]
# @param attrs [Array<String>]
# @return [Boolean]
def replaceable_to_link?(node, attrs)
include_option?(node, :href) || attrs.include?('href')
end
# @param node [RuboCop::AST::SendNode]
# @param option [Symbol]
# @return [Boolean]
def include_option?(node, option)
node.each_descendant(:sym).find { |opt| opt.value == option }
end
end
end
end
end

View File

@ -10,9 +10,56 @@ module RuboCop
id class style visible obscured exact exact_text normalize_ws match
wait filter_set focused
].freeze
SPECIFIC_OPTIONS = {
'button' => (
COMMON_OPTIONS + %w[disabled name value title type]
).freeze,
'link' => (
COMMON_OPTIONS + %w[href alt title download]
).freeze,
'table' => (
COMMON_OPTIONS + %w[
caption with_cols cols with_rows rows
]
).freeze,
'select' => (
COMMON_OPTIONS + %w[
disabled name placeholder options enabled_options
disabled_options selected with_selected multiple with_options
]
).freeze,
'field' => (
COMMON_OPTIONS + %w[
checked unchecked disabled valid name placeholder
validation_message readonly with type multiple
]
).freeze
}.freeze
SPECIFIC_PSEUDO_CLASSES = %w[
not() disabled enabled checked unchecked
].freeze
module_function
# @param element [String]
# @param attribute [String]
# @return [Boolean]
# @example
# specific_pesudo_classes?('button', 'name') # => true
# specific_pesudo_classes?('link', 'invalid') # => false
def specific_options?(element, attribute)
SPECIFIC_OPTIONS.fetch(element, []).include?(attribute)
end
# @param pseudo_class [String]
# @return [Boolean]
# @example
# specific_pesudo_classes?('disabled') # => true
# specific_pesudo_classes?('first-of-type') # => false
def specific_pesudo_classes?(pseudo_class)
SPECIFIC_PSEUDO_CLASSES.include?(pseudo_class)
end
# @param selector [String]
# @return [Boolean]
# @example
@ -75,7 +122,7 @@ module RuboCop
# multiple_selectors?('a.cls b#id') # => true
# multiple_selectors?('a.cls') # => false
def multiple_selectors?(selector)
selector.match?(/[ >,+]/)
selector.match?(/[ >,+~]/)
end
# @param value [String]

View File

@ -0,0 +1,23 @@
# frozen_string_literal: true
module RuboCop
module Cop
module RSpec
# Helps check offenses with variable definitions
module SkipOrPending
extend RuboCop::NodePattern::Macros
# @!method skipped_in_metadata?(node)
def_node_matcher :skipped_in_metadata?, <<-PATTERN
{
(send _ _ <#skip_or_pending? ...>)
(send _ _ ... (hash <(pair #skip_or_pending? { true str }) ...>))
}
PATTERN
# @!method skip_or_pending?(node)
def_node_matcher :skip_or_pending?, '{(sym :skip) (sym :pending)}'
end
end
end
end

View File

@ -0,0 +1,151 @@
# frozen_string_literal: true
module RuboCop
module Cop
module RSpec
# Checks for explicitly referenced test subjects.
#
# RSpec lets you declare an "implicit subject" using `subject { ... }`
# which allows for tests like `it { is_expected.to be_valid }`.
# If you need to reference your test subject you should explicitly
# name it using `subject(:your_subject_name) { ... }`. Your test subjects
# should be the most important object in your tests so they deserve
# a descriptive name.
#
# This cop can be configured in your configuration using `EnforcedStyle`,
# and `IgnoreSharedExamples` which will not report offenses for implicit
# subjects in shared example groups.
#
# @example `EnforcedStyle: always` (default)
# # bad
# RSpec.describe User do
# subject { described_class.new }
#
# it 'is valid' do
# expect(subject.valid?).to be(true)
# end
# end
#
# # good
# RSpec.describe User do
# subject(:user) { described_class.new }
#
# it 'is valid' do
# expect(user.valid?).to be(true)
# end
# end
#
# # also good
# RSpec.describe User do
# subject(:user) { described_class.new }
#
# it { is_expected.to be_valid }
# end
#
# @example `EnforcedStyle: named_only`
# # bad
# RSpec.describe User do
# subject(:user) { described_class.new }
#
# it 'is valid' do
# expect(subject.valid?).to be(true)
# end
# end
#
# # good
# RSpec.describe User do
# subject(:user) { described_class.new }
#
# it 'is valid' do
# expect(user.valid?).to be(true)
# end
# end
#
# # also good
# RSpec.describe User do
# subject { described_class.new }
#
# it { is_expected.to be_valid }
# end
#
# # acceptable
# RSpec.describe User do
# subject { described_class.new }
#
# it 'is valid' do
# expect(subject.valid?).to be(true)
# end
# end
class NamedSubject < Base
include ConfigurableEnforcedStyle
MSG = 'Name your test subject if you need to reference it explicitly.'
# @!method example_or_hook_block?(node)
def_node_matcher :example_or_hook_block?,
block_pattern('{#Examples.all #Hooks.all}')
# @!method shared_example?(node)
def_node_matcher :shared_example?,
block_pattern('#SharedGroups.examples')
# @!method subject_usage(node)
def_node_search :subject_usage, '$(send nil? :subject)'
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
if !example_or_hook_block?(node) || ignored_shared_example?(node)
return
end
subject_usage(node) do |subject_node|
check_explicit_subject(subject_node)
end
end
private
def ignored_shared_example?(node)
cop_config['IgnoreSharedExamples'] &&
node.each_ancestor(:block).any?(&method(:shared_example?))
end
def check_explicit_subject(node)
return if allow_explicit_subject?(node)
add_offense(node.loc.selector)
end
def allow_explicit_subject?(node)
!always? && !named_only?(node)
end
def always?
style == :always
end
def named_only?(node)
style == :named_only &&
subject_definition_is_named?(node)
end
def subject_definition_is_named?(node)
subject = nearest_subject(node)
subject&.send_node&.arguments?
end
def nearest_subject(node)
node
.each_ancestor(:block)
.lazy
.map { |block_node| find_subject(block_node) }
.find(&:itself)
end
def find_subject(block_node)
block_node.body.child_nodes.find { |send_node| subject?(send_node) }
end
end
end
end
end

View File

@ -133,7 +133,7 @@ module RuboCop
def count_up_nesting?(node, example_group)
example_group &&
(node.block_type? &&
!allowed_groups.include?(node.method_name))
!allowed_groups.include?(node.method_name.to_s))
end
def message(nesting)

View File

@ -28,7 +28,37 @@ module RuboCop
# expect(a?).to be(true)
# end
#
# This cop can be customized with an allowed expectation methods pattern
# with an `AllowedPatterns` option. ^expect_ and ^assert_ are allowed
# by default.
#
# @example `AllowedPatterns` configuration
#
# # .rubocop.yml
# # RSpec/NoExpectationExample:
# # AllowedPatterns:
# # - ^expect_
# # - ^assert_
#
# @example
# # bad
# it do
# not_expect_something
# end
#
# # good
# it do
# expect_something
# end
#
# it do
# assert_something
# end
#
class NoExpectationExample < Base
include AllowedPattern
include SkipOrPending
MSG = 'No expectation found in this example.'
# @!method regular_or_focused_example?(node)
@ -41,26 +71,29 @@ module RuboCop
}
PATTERN
# @!method including_any_expectation?(node)
# @!method includes_expectation?(node)
# @param [RuboCop::AST::Node] node
# @return [Boolean]
def_node_search(
:including_any_expectation?,
send_pattern('#Expectations.all')
)
def_node_search :includes_expectation?, <<~PATTERN
{
#{send_pattern('#Expectations.all')}
(send nil? `#matches_allowed_pattern? ...)
}
PATTERN
# @!method including_any_skip_example?(node)
# @!method includes_skip_example?(node)
# @param [RuboCop::AST::Node] node
# @return [Boolean]
def_node_search :including_any_skip_example?, <<~PATTERN
def_node_search :includes_skip_example?, <<~PATTERN
(send nil? {:pending :skip} ...)
PATTERN
# @param [RuboCop::AST::BlockNode] node
def on_block(node)
return unless regular_or_focused_example?(node)
return if including_any_expectation?(node)
return if including_any_skip_example?(node)
return if includes_expectation?(node)
return if includes_skip_example?(node)
return if skipped_in_metadata?(node.send_node)
add_offense(node)
end

View File

@ -33,6 +33,8 @@ module RuboCop
# end
#
class Pending < Base
include SkipOrPending
MSG = 'Pending spec found.'
# @!method skippable?(node)
@ -41,17 +43,6 @@ module RuboCop
{#ExampleGroups.regular #Examples.regular}
PATTERN
# @!method skipped_in_metadata?(node)
def_node_matcher :skipped_in_metadata?, <<-PATTERN
{
(send _ _ <#skip_or_pending? ...>)
(send _ _ ... (hash <(pair #skip_or_pending? { true str }) ...>))
}
PATTERN
# @!method skip_or_pending?(node)
def_node_matcher :skip_or_pending?, '{(sym :skip) (sym :pending)}'
# @!method pending_block?(node)
def_node_matcher :pending_block?,
send_pattern(<<~PATTERN)

View File

@ -0,0 +1,145 @@
# frozen_string_literal: true
module RuboCop
module Cop
module RSpec
module Rails
# Identifies redundant spec type.
#
# After setting up rspec-rails, you will have enabled
# `config.infer_spec_type_from_file_location!` by default in
# spec/rails_helper.rb. This cop works in conjunction with this config.
# If you disable this config, disable this cop as well.
#
# @safety
# This cop is marked as unsafe because
# `config.infer_spec_type_from_file_location!` may not be enabled.
#
# @example
# # bad
# # spec/models/user_spec.rb
# RSpec.describe User, type: :model do
# end
#
# # good
# # spec/models/user_spec.rb
# RSpec.describe User do
# end
#
# # good
# # spec/models/user_spec.rb
# RSpec.describe User, type: :common do
# end
#
# @example `Inferences` configuration
# # .rubocop.yml
# # RSpec/InferredSpecType:
# # Inferences:
# # services: service
#
# # bad
# # spec/services/user_spec.rb
# RSpec.describe User, type: :service do
# end
#
# # good
# # spec/services/user_spec.rb
# RSpec.describe User do
# end
#
# # good
# # spec/services/user_spec.rb
# RSpec.describe User, type: :common do
# end
class InferredSpecType < Base
extend AutoCorrector
MSG = 'Remove redundant spec type.'
# @param [RuboCop::AST::BlockNode] node
def on_block(node)
return unless example_group?(node)
pair_node = describe_with_type(node)
return unless pair_node
return unless inferred_type?(pair_node)
removable_node = detect_removable_node(pair_node)
add_offense(removable_node) do |corrector|
autocorrect(corrector, removable_node)
end
end
alias on_numblock on_block
private
# @!method describe_with_type(node)
# @param [RuboCop::AST::BlockNode] node
# @return [RuboCop::AST::PairNode, nil]
def_node_matcher :describe_with_type, <<~PATTERN
(block
(send #rspec? #ExampleGroups.all
...
(hash <$(pair (sym :type) sym) ...>)
)
...
)
PATTERN
# @param [RuboCop::AST::Corrector] corrector
# @param [RuboCop::AST::Node] node
def autocorrect(corrector, node)
corrector.remove(remove_range(node))
end
# @param [RuboCop::AST::Node] node
# @return [Parser::Source::Range]
def remove_range(node)
if node.left_sibling
node.loc.expression.with(
begin_pos: node.left_sibling.loc.expression.end_pos
)
elsif node.right_sibling
node.loc.expression.with(
end_pos: node.right_sibling.loc.expression.begin_pos
)
end
end
# @param [RuboCop::AST::PairNode] node
# @return [RuboCop::AST::Node]
def detect_removable_node(node)
if node.parent.pairs.size == 1
node.parent
else
node
end
end
# @return [String]
def file_path
processed_source.file_path
end
# @param [RuboCop::AST::PairNode] node
# @return [Boolean]
def inferred_type?(node)
inferred_type_from_file_path.inspect == node.value.source
end
# @return [Symbol, nil]
def inferred_type_from_file_path
inferences.find do |prefix, type|
break type.to_sym if file_path.include?("spec/#{prefix}/")
end
end
# @return [Hash]
def inferences
cop_config['Inferences'] || {}
end
end
end
end
end
end

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