rubocop-rspec 3.7.0 → 3.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 645fbfddd891af3477e31993bc8da92fc57300cbcfcd8274ee0f68cfbbe97983
4
- data.tar.gz: 6a97e91acb933ecbe09691c090efbff715ca12adcaef7027e8d324411ec0d78d
3
+ metadata.gz: abe85fc893e4ec59cb9b5f1e999d35bb41692feacc4dba579d135b3eefd6e4c7
4
+ data.tar.gz: 953ba29bf3fce28b79943e69039b638574d74432dac8b896f3dc8e589a20581c
5
5
  SHA512:
6
- metadata.gz: ca10e4b0b7e285136c60aa0035a018407263968fcced15155999ef5e2b6ac4edac45bcbd6c82dd355616a40ef110f9191cc986d5a8922aaab42c8118bff55c89
7
- data.tar.gz: 7a22acf8143f309128504884a1634e23504b40821aabf14d9b20392c6c11ce7a34ad3ab48945e1b023594a794677bdf6526e7236f705fd331ab244a746375453
6
+ metadata.gz: acdf813781e2081ec34540e83a9a48fc289dab5cc8bff69d9610beb4a3f21c30955794eb4226d40b9f0460a04d38665c2aa4ce0857f35d8bd3a7325d91a861be
7
+ data.tar.gz: 752074b0fdce204596efc71e2358982c73c2fccff07da5da364c88b8ad5e99d5a8bfdbc855a9dd422169adeddf278266352f732092b5aa86d14502016ca77837
data/CHANGELOG.md CHANGED
@@ -2,6 +2,16 @@
2
2
 
3
3
  ## Master (Unreleased)
4
4
 
5
+ ## 3.8.0 (2025-11-12)
6
+
7
+ - Add new cop `RSpec/LeakyLocalVariable`. ([@lovro-bikic])
8
+ - Bump RuboCop requirement to +1.81. ([@ydah])
9
+ - Fix a false positive for `RSpec/LetSetup` when `let!` used in outer scope. ([@ydah])
10
+ - Fix a false positive for `RSpec/ReceiveNever` cop when `allow(...).to receive(...).never`. ([@ydah])
11
+ - Fix detection of nameless doubles with methods in `RSpec/VerifiedDoubles`. ([@ushi-as])
12
+ - Improve an offense message for `RSpec/RepeatedExample` cop. ([@ydah])
13
+ - Let `RSpec/SpecFilePathFormat` leverage ActiveSupport inflections when configured. ([@corsonknowles], [@bquorning])
14
+
5
15
  ## 3.7.0 (2025-09-01)
6
16
 
7
17
  - Mark `RSpec/IncludeExamples` as `SafeAutoCorrect: false`. ([@yujideveloper])
@@ -1077,6 +1087,7 @@ Compatibility release so users can upgrade RuboCop to 0.51.0. No new features.
1077
1087
  [@tmaier]: https://github.com/tmaier
1078
1088
  [@topalovic]: https://github.com/topalovic
1079
1089
  [@twalpole]: https://github.com/twalpole
1090
+ [@ushi-as]: https://github.com/ushi-as
1080
1091
  [@vzvu3k6k]: https://github.com/vzvu3k6k
1081
1092
  [@walf443]: https://github.com/walf443
1082
1093
  [@yasu551]: https://github.com/yasu551
data/config/default.yml CHANGED
@@ -610,6 +610,12 @@ RSpec/LeakyConstantDeclaration:
610
610
  StyleGuide: https://rspec.rubystyle.guide/#declare-constants
611
611
  Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/LeakyConstantDeclaration
612
612
 
613
+ RSpec/LeakyLocalVariable:
614
+ Description: Checks for local variables from outer scopes used inside examples.
615
+ Enabled: pending
616
+ VersionAdded: '3.8'
617
+ Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/LeakyLocalVariable
618
+
613
619
  RSpec/LetBeforeExamples:
614
620
  Description: Checks for `let` definitions that come after an example.
615
621
  Enabled: true
@@ -933,7 +939,13 @@ RSpec/SpecFilePathFormat:
933
939
  IgnoreMethods: false
934
940
  IgnoreMetadata:
935
941
  type: routing
942
+ InflectorPath: "./config/initializers/inflections.rb"
943
+ SupportedInflectors:
944
+ - default
945
+ - active_support
946
+ EnforcedInflector: default
936
947
  VersionAdded: '2.24'
948
+ VersionChanged: '3.8'
937
949
  Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/SpecFilePathFormat
938
950
 
939
951
  RSpec/SpecFilePathSuffix:
@@ -67,7 +67,7 @@ module RuboCop
67
67
 
68
68
  # @!method context_wording(node)
69
69
  def_node_matcher :context_wording, <<~PATTERN
70
- (block (send #rspec? { :context :shared_context } $({str dstr xstr} ...) ...) ...)
70
+ (block (send #rspec? { :context :shared_context } $(any_str ...) ...) ...)
71
71
  PATTERN
72
72
 
73
73
  def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
@@ -10,8 +10,19 @@ module RuboCop
10
10
  #
11
11
  # @see http://betterspecs.org/#should
12
12
  #
13
- # The autocorrect is experimental - use with care! It can be configured
14
- # with CustomTransform (e.g. have => has) and IgnoredWords (e.g. only).
13
+ # @safety
14
+ # The autocorrect is experimental - use with care! It can be configured
15
+ # with CustomTransform (e.g. have => has) and IgnoredWords (e.g. only).
16
+ #
17
+ # While the autocorrect will not break your code (it only modifies test
18
+ # description strings, not the actual test logic), it may produce
19
+ # grammatically incorrect English in some cases. Always review the diff
20
+ # when using autocorrect to ensure the descriptions remain natural and
21
+ # accurate.
22
+ #
23
+ # This is not classified as an unsafe autocorrect because it does not
24
+ # affect code behavior, but manual review of changes is strongly
25
+ # recommended.
15
26
  #
16
27
  # Use the DisallowedExamples setting to prevent unclear or insufficient
17
28
  # descriptions. Please note that this config will not be treated as
@@ -0,0 +1,138 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module RSpec
6
+ # Checks for local variables from outer scopes used inside examples.
7
+ #
8
+ # Local variables assigned outside an example but used within it act
9
+ # as shared state, which can make tests non-deterministic.
10
+ #
11
+ # @example
12
+ # # bad - outside variable used in a hook
13
+ # user = create(:user)
14
+ #
15
+ # before { user.update(admin: true) }
16
+ #
17
+ # # good
18
+ # let(:user) { create(:user) }
19
+ #
20
+ # before { user.update(admin: true) }
21
+ #
22
+ # # bad - outside variable used in an example
23
+ # user = create(:user)
24
+ #
25
+ # it 'is persisted' do
26
+ # expect(user).to be_persisted
27
+ # end
28
+ #
29
+ # # good
30
+ # let(:user) { create(:user) }
31
+ #
32
+ # it 'is persisted' do
33
+ # expect(user).to be_persisted
34
+ # end
35
+ #
36
+ # # also good - assigning the variable within the example
37
+ # it 'is persisted' do
38
+ # user = create(:user)
39
+ #
40
+ # expect(user).to be_persisted
41
+ # end
42
+ #
43
+ # # bad - outside variable passed to included examples
44
+ # attrs = ['foo', 'bar']
45
+ #
46
+ # it_behaves_like 'some examples', attrs
47
+ #
48
+ # # good
49
+ # it_behaves_like 'some examples' do
50
+ # let(:attrs) { ['foo', 'bar'] }
51
+ # end
52
+ #
53
+ # # good - when variable is used only as example description
54
+ # attribute = 'foo'
55
+ #
56
+ # it "#{attribute} is persisted" do
57
+ # expectations
58
+ # end
59
+ #
60
+ # # good - when variable is used only to include other examples
61
+ # examples = foo ? 'some examples' : 'other examples'
62
+ #
63
+ # it_behaves_like examples, another_argument
64
+ #
65
+ class LeakyLocalVariable < Base
66
+ MSG = 'Do not use local variables defined outside of ' \
67
+ 'examples inside of them.'
68
+
69
+ # @!method example_method?(node)
70
+ def_node_matcher :example_method?, <<~PATTERN
71
+ (send nil? #Examples.all _)
72
+ PATTERN
73
+
74
+ # @!method includes_method?(node)
75
+ def_node_matcher :includes_method?, <<~PATTERN
76
+ (send nil? #Includes.all ...)
77
+ PATTERN
78
+
79
+ def self.joining_forces
80
+ VariableForce
81
+ end
82
+
83
+ def after_leaving_scope(scope, _variable_table)
84
+ scope.variables.each_value { |variable| check_references(variable) }
85
+ end
86
+
87
+ private
88
+
89
+ def check_references(variable)
90
+ variable.assignments.each do |assignment|
91
+ next if part_of_example_scope?(assignment.node)
92
+
93
+ assignment.references.each do |reference|
94
+ next unless inside_describe_block?(reference)
95
+ next unless part_of_example_scope?(reference)
96
+ next if allowed_reference?(reference)
97
+
98
+ add_offense(assignment.node)
99
+ end
100
+ end
101
+ end
102
+
103
+ def allowed_reference?(node)
104
+ node.each_ancestor.any? do |ancestor|
105
+ next true if example_method?(ancestor)
106
+ if includes_method?(ancestor)
107
+ next allowed_includes_arguments?(ancestor, node)
108
+ end
109
+
110
+ false
111
+ end
112
+ end
113
+
114
+ def allowed_includes_arguments?(node, argument)
115
+ node.arguments[1..].all? do |argument_node|
116
+ next true if argument_node.type?(:dstr, :dsym)
117
+
118
+ argument_node != argument &&
119
+ argument_node.each_descendant.none?(argument)
120
+ end
121
+ end
122
+
123
+ def part_of_example_scope?(node)
124
+ node.each_ancestor.any? { |ancestor| example_scope?(ancestor) }
125
+ end
126
+
127
+ def example_scope?(node)
128
+ subject?(node) || let?(node) || hook?(node) || example?(node) ||
129
+ include?(node)
130
+ end
131
+
132
+ def inside_describe_block?(node)
133
+ node.each_ancestor(:block).any? { |ancestor| spec_group?(ancestor) }
134
+ end
135
+ end
136
+ end
137
+ end
138
+ end
@@ -25,6 +25,18 @@ module RuboCop
25
25
  # it 'counts widgets' do
26
26
  # expect(Widget.count).to eq(1)
27
27
  # end
28
+ #
29
+ # # good
30
+ # describe 'a widget' do
31
+ # let!(:my_widget) { create(:widget) }
32
+ # context 'when visiting its page' do
33
+ # let!(:my_widget) { create(:widget, name: 'Special') }
34
+ # it 'counts widgets' do
35
+ # expect(Widget.count).to eq(1)
36
+ # end
37
+ # end
38
+ # end
39
+ #
28
40
  class LetSetup < Base
29
41
  MSG = 'Do not use `let!` to setup objects not referenced in tests.'
30
42
 
@@ -59,6 +71,8 @@ module RuboCop
59
71
 
60
72
  def unused_let_bang(node)
61
73
  child_let_bang(node) do |method_send, method_name|
74
+ next if overrides_outer_let_bang?(node, method_name)
75
+
62
76
  yield(method_send) unless method_called?(node, method_name.to_sym)
63
77
  end
64
78
  end
@@ -68,6 +82,22 @@ module RuboCop
68
82
  let_bang(let, &block)
69
83
  end
70
84
  end
85
+
86
+ def overrides_outer_let_bang?(node, method_name)
87
+ node.each_ancestor(:block).any? do |ancestor|
88
+ next unless example_or_shared_group_or_including?(ancestor)
89
+
90
+ outer_let_bang?(ancestor, method_name)
91
+ end
92
+ end
93
+
94
+ def outer_let_bang?(ancestor_node, method_name)
95
+ RuboCop::RSpec::ExampleGroup.new(ancestor_node).lets.any? do |let|
96
+ let_bang(let) do |_send, name|
97
+ name == method_name
98
+ end
99
+ end
100
+ end
71
101
  end
72
102
  end
73
103
  end
@@ -7,7 +7,7 @@ module RuboCop
7
7
  module FinalEndLocation
8
8
  def final_end_location(start_node)
9
9
  heredoc_endings =
10
- start_node.each_node(:str, :dstr, :xstr)
10
+ start_node.each_node(:any_str)
11
11
  .select(&:heredoc?)
12
12
  .map { |node| node.loc.heredoc_end }
13
13
 
@@ -13,7 +13,7 @@ module RuboCop
13
13
  # @!method variable_definition?(node)
14
14
  def_node_matcher :variable_definition?, <<~PATTERN
15
15
  (send nil? {#Subjects.all #Helpers.all}
16
- $({sym str dsym dstr} ...) ...)
16
+ $({any_sym str dstr} ...) ...)
17
17
  PATTERN
18
18
  end
19
19
  end
@@ -181,9 +181,7 @@ module RuboCop
181
181
  end
182
182
 
183
183
  def heredoc_argument?(matcher)
184
- matcher.arguments.select do |arg|
185
- arg.type?(:str, :dstr, :xstr)
186
- end.any?(&:heredoc?)
184
+ matcher.arguments.select(&:any_str_type?).any?(&:heredoc?)
187
185
  end
188
186
 
189
187
  # @!method predicate_matcher?(node)
@@ -5,6 +5,11 @@ module RuboCop
5
5
  module RSpec
6
6
  # Prefer `not_to receive(...)` over `receive(...).never`.
7
7
  #
8
+ # This cop only flags usage with `expect`. It ignores `allow` because
9
+ # `allow(...).to receive(...).never` is a valid way to ensure a method
10
+ # is not called, while `allow(...).not_to receive(...)` would have
11
+ # different semantics.
12
+ #
8
13
  # @example
9
14
  # # bad
10
15
  # expect(foo).to receive(:bar).never
@@ -12,6 +17,9 @@ module RuboCop
12
17
  # # good
13
18
  # expect(foo).not_to receive(:bar)
14
19
  #
20
+ # # not flagged by this cop
21
+ # allow(foo).to receive(:bar).never
22
+ #
15
23
  class ReceiveNever < Base
16
24
  extend AutoCorrector
17
25
  MSG = 'Use `not_to receive` instead of `never`.'
@@ -20,8 +28,20 @@ module RuboCop
20
28
  # @!method method_on_stub?(node)
21
29
  def_node_search :method_on_stub?, '(send nil? :receive ...)'
22
30
 
31
+ # @!method expect_to_receive?(node)
32
+ def_node_matcher :expect_to_receive?, <<~PATTERN
33
+ (send
34
+ {
35
+ (send #rspec? {:expect :expect_any_instance_of} ...)
36
+ (block (send #rspec? :expect) ...)
37
+ (send nil? :is_expected)
38
+ }
39
+ :to ...)
40
+ PATTERN
41
+
23
42
  def on_send(node)
24
43
  return unless node.method?(:never) && method_on_stub?(node)
44
+ return unless used_with_expect?(node)
25
45
 
26
46
  add_offense(node.loc.selector) do |corrector|
27
47
  autocorrect(corrector, node)
@@ -30,6 +50,12 @@ module RuboCop
30
50
 
31
51
  private
32
52
 
53
+ def used_with_expect?(node)
54
+ node.each_ancestor(:send).any? do |ancestor|
55
+ expect_to_receive?(ancestor)
56
+ end
57
+ end
58
+
33
59
  def autocorrect(corrector, node)
34
60
  corrector.replace(node.parent.loc.selector, 'not_to')
35
61
  range = node.loc.dot.with(end_pos: node.loc.selector.end_pos)
@@ -16,36 +16,55 @@ module RuboCop
16
16
  # end
17
17
  #
18
18
  class RepeatedExample < Base
19
- MSG = "Don't repeat examples within an example group."
19
+ MSG = "Don't repeat examples within an example group. " \
20
+ 'Repeated on line(s) %<lines>s.'
20
21
 
21
22
  def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
22
23
  return unless example_group?(node)
23
24
 
24
- repeated_examples(node).each do |repeated_example|
25
- add_offense(repeated_example)
25
+ find_repeated_examples(node).each do |repeated_examples|
26
+ add_offenses_for_repeated_group(repeated_examples)
26
27
  end
27
28
  end
28
29
 
29
30
  private
30
31
 
31
- def repeated_examples(node)
32
- RuboCop::RSpec::ExampleGroup.new(node)
33
- .examples
34
- .group_by { |example| example_signature(example) }
32
+ def find_repeated_examples(node)
33
+ examples = RuboCop::RSpec::ExampleGroup.new(node).examples
34
+
35
+ examples
36
+ .group_by { |example| build_example_signature(example) }
35
37
  .values
36
- .reject(&:one?)
37
- .flatten
38
- .map(&:to_node)
38
+ .select { |group| group.size > 1 }
39
39
  end
40
40
 
41
- def example_signature(example)
42
- key_parts = [example.metadata, example.implementation]
43
-
41
+ def build_example_signature(example)
42
+ signature = [example.metadata, example.implementation]
44
43
  if example.definition.method?(:its)
45
- key_parts << example.definition.arguments
44
+ signature << example.definition.arguments
45
+ end
46
+ signature
47
+ end
48
+
49
+ def add_offenses_for_repeated_group(repeated_examples)
50
+ repeated_examples.each do |example|
51
+ other_lines = extract_other_lines(repeated_examples, example)
52
+ add_offense(example.to_node, message: message(other_lines))
46
53
  end
54
+ end
55
+
56
+ def extract_other_lines(examples_group, current_example)
57
+ current_node = current_example.to_node
58
+
59
+ examples_group
60
+ .reject { |ex| ex.to_node.equal?(current_node) }
61
+ .map { |ex| ex.to_node.first_line }
62
+ .uniq
63
+ .sort
64
+ end
47
65
 
48
- key_parts
66
+ def message(other_lines)
67
+ format(MSG, lines: other_lines.join(', '))
49
68
  end
50
69
  end
51
70
  end
@@ -30,7 +30,7 @@ module RuboCop
30
30
 
31
31
  # @!method match_ambiguous_trailing_metadata?(node)
32
32
  def_node_matcher :match_ambiguous_trailing_metadata?, <<~PATTERN
33
- (send _ _ _ ... !{hash sym str dstr xstr})
33
+ (send _ _ _ ... !{hash sym any_str})
34
34
  PATTERN
35
35
 
36
36
  def on_metadata(args, hash)
@@ -32,6 +32,12 @@ module RuboCop
32
32
  # # good
33
33
  # whatever_spec.rb # describe MyClass, type: :routing do; end
34
34
  #
35
+ # @example `EnforcedInflector: active_support`
36
+ # # Enable to use ActiveSupport's inflector for custom acronyms
37
+ # # like HTTP, etc. Set to "default" by default.
38
+ # # Configure `InflectorPath` with the path to the inflector file.
39
+ # # The default is ./config/initializers/inflections.rb.
40
+ #
35
41
  class SpecFilePathFormat < Base
36
42
  include TopLevelGroup
37
43
  include Namespace
@@ -59,6 +65,53 @@ module RuboCop
59
65
 
60
66
  private
61
67
 
68
+ # Inflector module that uses ActiveSupport for advanced inflection rules
69
+ module ActiveSupportInflector
70
+ def self.call(string)
71
+ ActiveSupport::Inflector.underscore(string)
72
+ end
73
+
74
+ def self.prepare_availability(config)
75
+ return if @prepared
76
+
77
+ @prepared = true
78
+
79
+ inflector_path = config.fetch('InflectorPath')
80
+
81
+ unless File.exist?(inflector_path)
82
+ raise "The configured `InflectorPath` #{inflector_path} does " \
83
+ 'not exist.'
84
+ end
85
+
86
+ require 'active_support/inflector'
87
+ require inflector_path
88
+ end
89
+ end
90
+
91
+ # Inflector module that uses basic regex-based conversion
92
+ module DefaultInflector
93
+ def self.call(string)
94
+ string
95
+ .gsub(/([^A-Z])([A-Z]+)/, '\1_\2')
96
+ .gsub(/([A-Z])([A-Z][^A-Z\d]+)/, '\1_\2')
97
+ .downcase
98
+ end
99
+ end
100
+
101
+ def inflector
102
+ case cop_config.fetch('EnforcedInflector')
103
+ when 'active_support'
104
+ ActiveSupportInflector.prepare_availability(cop_config)
105
+ ActiveSupportInflector
106
+ when 'default'
107
+ DefaultInflector
108
+ else
109
+ # :nocov:
110
+ :noop
111
+ # :nocov:
112
+ end
113
+ end
114
+
62
115
  def ensure_correct_file_path(send_node, class_name, arguments)
63
116
  pattern = correct_path_pattern(class_name, arguments)
64
117
  return if filename_ends_with?(pattern)
@@ -106,10 +159,7 @@ module RuboCop
106
159
  end
107
160
 
108
161
  def camel_to_snake_case(string)
109
- string
110
- .gsub(/([^A-Z])([A-Z]+)/, '\1_\2')
111
- .gsub(/([A-Z])([A-Z][^A-Z\d]+)/, '\1_\2')
112
- .downcase
162
+ inflector.call(string)
113
163
  end
114
164
 
115
165
  def custom_transform
@@ -60,16 +60,8 @@ module RuboCop
60
60
  end
61
61
 
62
62
  def style_offense?(variable)
63
- (style == :symbols && string?(variable)) ||
64
- (style == :strings && symbol?(variable))
65
- end
66
-
67
- def string?(node)
68
- node.str_type?
69
- end
70
-
71
- def symbol?(node)
72
- node.type?(:sym, :dsym)
63
+ (style == :symbols && variable.str_type?) ||
64
+ (style == :strings && variable.any_sym_type?)
73
65
  end
74
66
  end
75
67
  end
@@ -10,12 +10,12 @@ module RuboCop
10
10
  # @example
11
11
  # # bad
12
12
  # let(:foo) do
13
- # double(method_name: 'returned value')
13
+ # double("ClassName", method_name: 'returned value')
14
14
  # end
15
15
  #
16
16
  # # bad
17
17
  # let(:foo) do
18
- # double("ClassName", method_name: 'returned value')
18
+ # spy("ClassName", method_name: 'returned value')
19
19
  # end
20
20
  #
21
21
  # # good
@@ -23,6 +23,50 @@ module RuboCop
23
23
  # instance_double("ClassName", method_name: 'returned value')
24
24
  # end
25
25
  #
26
+ # # good
27
+ # let(:foo) do
28
+ # class_double("ClassName", method_name: 'returned value')
29
+ # end
30
+ #
31
+ # # good
32
+ # let(:foo) do
33
+ # object_double("some object", method_name: 'returned value')
34
+ # end
35
+ #
36
+ # @example `IgnoreNameless: true (default)`
37
+ # # good
38
+ # let(:foo) do
39
+ # double(method_name: 'returned value')
40
+ # end
41
+ #
42
+ # # good
43
+ # let(:foo) do
44
+ # double
45
+ # end
46
+ #
47
+ # @example `IgnoreNameless: false`
48
+ # # bad
49
+ # let(:foo) do
50
+ # double(method_name: 'returned value')
51
+ # end
52
+ #
53
+ # # bad
54
+ # let(:foo) do
55
+ # double
56
+ # end
57
+ #
58
+ # @example `IgnoreSymbolicNames: false (default)`
59
+ # # bad
60
+ # let(:foo) do
61
+ # double(:foo)
62
+ # end
63
+ #
64
+ # @example `IgnoreSymbolicNames: true`
65
+ # # good
66
+ # let(:foo) do
67
+ # double(:foo)
68
+ # end
69
+ #
26
70
  class VerifiedDoubles < Base
27
71
  MSG = 'Prefer using verifying doubles over normal doubles.'
28
72
  RESTRICT_ON_SEND = %i[double spy].freeze
@@ -34,7 +78,7 @@ module RuboCop
34
78
 
35
79
  def on_send(node)
36
80
  unverified_double(node) do |name, *_args|
37
- return if name.nil? && cop_config['IgnoreNameless']
81
+ return if (name.nil? || hash?(name)) && cop_config['IgnoreNameless']
38
82
  return if symbol?(name) && cop_config['IgnoreSymbolicNames']
39
83
 
40
84
  add_offense(node)
@@ -46,6 +90,10 @@ module RuboCop
46
90
  def symbol?(name)
47
91
  name&.sym_type?
48
92
  end
93
+
94
+ def hash?(arg)
95
+ arg.hash_type?
96
+ end
49
97
  end
50
98
  end
51
99
  end
@@ -57,6 +57,7 @@ require_relative 'rspec/it_behaves_like'
57
57
  require_relative 'rspec/iterated_expectation'
58
58
  require_relative 'rspec/leading_subject'
59
59
  require_relative 'rspec/leaky_constant_declaration'
60
+ require_relative 'rspec/leaky_local_variable'
60
61
  require_relative 'rspec/let_before_examples'
61
62
  require_relative 'rspec/let_setup'
62
63
  require_relative 'rspec/match_array'
@@ -4,7 +4,7 @@ module RuboCop
4
4
  module RSpec
5
5
  # Version information for the RSpec RuboCop plugin.
6
6
  module Version
7
- STRING = '3.7.0'
7
+ STRING = '3.8.0'
8
8
  end
9
9
  end
10
10
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubocop-rspec
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.7.0
4
+ version: 3.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Backus
@@ -31,20 +31,14 @@ dependencies:
31
31
  requirements:
32
32
  - - "~>"
33
33
  - !ruby/object:Gem::Version
34
- version: '1.72'
35
- - - ">="
36
- - !ruby/object:Gem::Version
37
- version: 1.72.1
34
+ version: '1.81'
38
35
  type: :runtime
39
36
  prerelease: false
40
37
  version_requirements: !ruby/object:Gem::Requirement
41
38
  requirements:
42
39
  - - "~>"
43
40
  - !ruby/object:Gem::Version
44
- version: '1.72'
45
- - - ">="
46
- - !ruby/object:Gem::Version
47
- version: 1.72.1
41
+ version: '1.81'
48
42
  description: |
49
43
  Code style checking for RSpec files.
50
44
  A plugin for the RuboCop code style enforcing & linting tool.
@@ -123,6 +117,7 @@ files:
123
117
  - lib/rubocop/cop/rspec/iterated_expectation.rb
124
118
  - lib/rubocop/cop/rspec/leading_subject.rb
125
119
  - lib/rubocop/cop/rspec/leaky_constant_declaration.rb
120
+ - lib/rubocop/cop/rspec/leaky_local_variable.rb
126
121
  - lib/rubocop/cop/rspec/let_before_examples.rb
127
122
  - lib/rubocop/cop/rspec/let_setup.rb
128
123
  - lib/rubocop/cop/rspec/match_array.rb