rubocop-rspec 3.3.0 → 3.6.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.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +26 -2
  3. data/README.md +7 -4
  4. data/config/default.yml +7 -12
  5. data/config/obsoletion.yml +5 -0
  6. data/lib/rubocop/cop/rspec/be_eq.rb +1 -1
  7. data/lib/rubocop/cop/rspec/be_eql.rb +1 -1
  8. data/lib/rubocop/cop/rspec/be_nil.rb +4 -0
  9. data/lib/rubocop/cop/rspec/change_by_zero.rb +3 -4
  10. data/lib/rubocop/cop/rspec/contain_exactly.rb +1 -0
  11. data/lib/rubocop/cop/rspec/context_wording.rb +6 -1
  12. data/lib/rubocop/cop/rspec/described_class.rb +4 -2
  13. data/lib/rubocop/cop/rspec/described_class_module_wrapping.rb +1 -1
  14. data/lib/rubocop/cop/rspec/empty_example_group.rb +6 -4
  15. data/lib/rubocop/cop/rspec/example_wording.rb +1 -3
  16. data/lib/rubocop/cop/rspec/excessive_docstring_spacing.rb +1 -1
  17. data/lib/rubocop/cop/rspec/expect_actual.rb +1 -1
  18. data/lib/rubocop/cop/rspec/expect_change.rb +21 -2
  19. data/lib/rubocop/cop/rspec/focus.rb +15 -17
  20. data/lib/rubocop/cop/rspec/hook_argument.rb +2 -2
  21. data/lib/rubocop/cop/rspec/hooks_before_examples.rb +1 -1
  22. data/lib/rubocop/cop/rspec/implicit_expect.rb +3 -3
  23. data/lib/rubocop/cop/rspec/implicit_subject.rb +8 -0
  24. data/lib/rubocop/cop/rspec/include_examples.rb +39 -0
  25. data/lib/rubocop/cop/rspec/indexed_let.rb +2 -0
  26. data/lib/rubocop/cop/rspec/match_array.rb +1 -0
  27. data/lib/rubocop/cop/rspec/message_spies.rb +4 -0
  28. data/lib/rubocop/cop/rspec/mixin/metadata.rb +5 -8
  29. data/lib/rubocop/cop/rspec/nested_groups.rb +2 -2
  30. data/lib/rubocop/cop/rspec/no_expectation_example.rb +1 -1
  31. data/lib/rubocop/cop/rspec/pending.rb +1 -1
  32. data/lib/rubocop/cop/rspec/pending_without_reason.rb +2 -8
  33. data/lib/rubocop/cop/rspec/predicate_matcher.rb +18 -8
  34. data/lib/rubocop/cop/rspec/receive_messages.rb +1 -2
  35. data/lib/rubocop/cop/rspec/redundant_around.rb +1 -1
  36. data/lib/rubocop/cop/rspec/return_from_stub.rb +5 -4
  37. data/lib/rubocop/cop/rspec/scattered_setup.rb +10 -2
  38. data/lib/rubocop/cop/rspec/sort_metadata.rb +22 -8
  39. data/lib/rubocop/cop/rspec/variable_definition.rb +1 -1
  40. data/lib/rubocop/cop/rspec/variable_name.rb +1 -1
  41. data/lib/rubocop/cop/rspec/verified_double_reference.rb +14 -53
  42. data/lib/rubocop/cop/rspec_cops.rb +1 -1
  43. data/lib/rubocop/rspec/config_formatter.rb +4 -9
  44. data/lib/rubocop/rspec/description_extractor.rb +2 -2
  45. data/lib/rubocop/rspec/hook.rb +3 -1
  46. data/lib/rubocop/rspec/language.rb +3 -6
  47. data/lib/rubocop/rspec/plugin.rb +37 -0
  48. data/lib/rubocop/rspec/version.rb +1 -1
  49. data/lib/rubocop/rspec/wording.rb +0 -2
  50. data/lib/rubocop/rspec.rb +0 -7
  51. data/lib/rubocop-rspec.rb +1 -3
  52. metadata +28 -10
  53. data/lib/rubocop/cop/rspec/string_as_instance_double_constant.rb +0 -45
  54. data/lib/rubocop/rspec/inject.rb +0 -18
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3ca108a17fe360c345896a230b0bec34f36430cfff3eb7b06d9fd28fa302da06
4
- data.tar.gz: 8eaf93b36c0cf29b2718e86fc8d99e85601f517966d008fd00d53f4315cd1745
3
+ metadata.gz: 4e4727f136d1a399d3108fd010c76ac61f7fce57e3c89cb2d97ad121d558af44
4
+ data.tar.gz: dcc8c7f61c420d5938807dae3a610f53c6be8c657687e38542f701db2aec4ce2
5
5
  SHA512:
6
- metadata.gz: f3375145facfb2e91f2cfee6949544947756e965f23fd713a09aba5f301b8558dc40be1b9cc3a66cb629c2b14f643a8bfb9aab12bff509dcfbcb2f9b05e801ac
7
- data.tar.gz: 75ea9be799c2868fbc4b7333b20d95ecf3934f0d8d38339c9c412010b037811cb2d45b2c3e494e01ea6f1be3619ac39290c22af5b1b76cc75a3ec0e0c3a9f6c3
6
+ metadata.gz: 651f8b53a0b70738f9dc084df5bdf471ce65ae4d7f0c2db8cc2eb557178fd541f317bee36ae062b8109aed72b452f69eb1c965db923d5d9875c86de9ab84f23e
7
+ data.tar.gz: f189ec83b4b663df4e3aca303f2f273fded6d5529e689d7f9421f379dd46203da95236a4f649414466b0f6050b0d9e7d952df003b4b63ed45722c1764fd1a094
data/CHANGELOG.md CHANGED
@@ -2,6 +2,27 @@
2
2
 
3
3
  ## Master (Unreleased)
4
4
 
5
+ ## 3.6.0 (2025-04-18)
6
+
7
+ - Fix false positive in `RSpec/Pending`, where it would mark the default block `it` as an offense. ([@bquorning])
8
+ - Fix issue when `Style/ContextWording` is configured with a Prefix being interpreted as a boolean, like `on`. ([@sakuro])
9
+ - Add new `RSpec/IncludeExamples` cop to enforce using `it_behaves_like` over `include_examples`. ([@dvandersluis])
10
+ - Change `RSpec/ScatteredSetup` to allow `around` hooks to be scattered. ([@ydah])
11
+ - Fix an error `RSpec/ChangeByZero` cop when without expect block. ([@lee266])
12
+ - Fix a false positive for `RSpec/DescribedClass` when `SkipBlocks` is true and numblocks are used. ([@earlopain])
13
+
14
+ ## 3.5.0 (2025-02-16)
15
+
16
+ - Don't let `RSpec/PredicateMatcher` replace `respond_to?` with two arguments with the RSpec `respond_to` matcher. ([@bquorning])
17
+ - Fix `RSpec/PredicateMatcher` support for `eql` and `equal` matchers. ([@bquorning])
18
+ - Pluginfy RuboCop RSpec. ([@koic])
19
+
20
+ ## 3.4.0 (2025-01-20)
21
+
22
+ - Fix `RSpec/SortMetadata` cop to limit sorting to trailing metadata arguments. ([@cbliard])
23
+ - Replace `RSpec/StringAsInstanceDoubleConstant` with `RSpec/VerifiedDoubleReference` configured to only support constant class references. ([@corsonknowles])
24
+ - Fix `RSpec/EmptyExampleGroup` cop false positive when a simple conditional is used inside an iterator. ([@lovro-bikic])
25
+
5
26
  ## 3.3.0 (2024-12-12)
6
27
 
7
28
  - Deprecate `top_level_group?` method from `TopLevelGroup` mixin as all of its callers were intentionally removed from `Rubocop/RSpec`. ([@corsonknowles])
@@ -93,7 +114,7 @@ Read more about how to upgrade in https://docs.rubocop.org/rubocop-rspec/upgrade
93
114
  - Add new `RSpec/IsExpectedSpecify` cop. ([@ydah])
94
115
  - Add new `RSpec/RepeatedSubjectCall` cop. ([@drcapulet])
95
116
  - Add support for `assert_true`, `assert_false`, `assert_not_equal`, `assert_not_nil`, `*_empty`, `*_predicate`, `*_kind_of`, `*_in_delta`, `*_match`, `*_instance_of` and `*_includes` assertions in `RSpec/Rails/MinitestAssertions`. ([@ydah], [@G-Rath])
96
- - Support asserts with messages in `Rspec/BeEmpty`. ([@G-Rath])
117
+ - Support asserts with messages in `RSpec/BeEmpty`. ([@G-Rath])
97
118
  - Fix a false positive for `RSpec/ExpectActual` when used with rspec-rails routing matchers. ([@naveg])
98
119
  - Add configuration option `ResponseMethods` to `RSpec/Rails/HaveHttpStatus`. ([@ydah])
99
120
  - Fix a false negative for `RSpec/DescribedClass` when class with constant. ([@ydah])
@@ -288,7 +309,7 @@ Read more about how to upgrade in https://docs.rubocop.org/rubocop-rspec/upgrade
288
309
  ## 2.13.0 (2022-09-12)
289
310
 
290
311
  - Fix `RSpec/FilePath` cop missing mismatched expanded namespace. ([@sl4vr])
291
- - Add new `AllowConsecutiveOneLiners` (default true) option for `Rspec/EmptyLineAfterHook` cop. ([@ngouy])
312
+ - Add new `AllowConsecutiveOneLiners` (default true) option for `RSpec/EmptyLineAfterHook` cop. ([@ngouy])
292
313
  - Add autocorrect support for `RSpec/EmptyExampleGroup`. ([@r7kamura])
293
314
  - Fix `RSpec/ChangeByZero` with compound expressions using `&` or `|` operators. ([@BrianHawley])
294
315
  - Add `RSpec/NoExpectationExample`. ([@r7kamura])
@@ -986,9 +1007,11 @@ Compatibility release so users can upgrade RuboCop to 0.51.0. No new features.
986
1007
  [@krororo]: https://github.com/krororo
987
1008
  [@kuahyeow]: https://github.com/kuahyeow
988
1009
  [@lazycoder9]: https://github.com/lazycoder9
1010
+ [@lee266]: https://github.com/lee266
989
1011
  [@leoarnold]: https://github.com/leoarnold
990
1012
  [@liberatys]: https://github.com/Liberatys
991
1013
  [@lokhi]: https://github.com/lokhi
1014
+ [@lovro-bikic]: https://github.com/lovro-bikic
992
1015
  [@luke-hill]: https://github.com/luke-hill
993
1016
  [@m-yamashita01]: https://github.com/M-Yamashita01
994
1017
  [@marocchino]: https://github.com/marocchino
@@ -1025,6 +1048,7 @@ Compatibility release so users can upgrade RuboCop to 0.51.0. No new features.
1025
1048
  [@rrosenblum]: https://github.com/rrosenblum
1026
1049
  [@rspeicher]: https://github.com/rspeicher
1027
1050
  [@rst-j]: https://github.com/RST-J
1051
+ [@sakuro]: https://github.com/sakuro
1028
1052
  [@samrjenkins]: https://github.com/samrjenkins
1029
1053
  [@schmijos]: https://github.com/schmijos
1030
1054
  [@seanpdoyle]: https://github.com/seanpdoyle
data/README.md CHANGED
@@ -48,13 +48,13 @@ ways to do this:
48
48
  Put this into your `.rubocop.yml`.
49
49
 
50
50
  ```yaml
51
- require: rubocop-rspec
51
+ plugins: rubocop-rspec
52
52
  ```
53
53
 
54
54
  Alternatively, use the following array notation when specifying multiple extensions.
55
55
 
56
56
  ```yaml
57
- require:
57
+ plugins:
58
58
  - rubocop-other-extension
59
59
  - rubocop-rspec
60
60
  ```
@@ -62,17 +62,20 @@ require:
62
62
  Now you can run `rubocop` and it will automatically load the RuboCop RSpec
63
63
  cops together with the standard cops.
64
64
 
65
+ > [!NOTE]
66
+ > The plugin system is supported in RuboCop 1.72+. In earlier versions, use `require` instead of `plugins`.
67
+
65
68
  ### Command line
66
69
 
67
70
  ```bash
68
- rubocop --require rubocop-rspec
71
+ rubocop --plugin rubocop-rspec
69
72
  ```
70
73
 
71
74
  ### Rake task
72
75
 
73
76
  ```ruby
74
77
  RuboCop::RakeTask.new do |task|
75
- task.requires << 'rubocop-rspec'
78
+ task.plugins << 'rubocop-rspec'
76
79
  end
77
80
  ```
78
81
 
data/config/default.yml CHANGED
@@ -532,6 +532,12 @@ RSpec/ImplicitSubject:
532
532
  VersionChanged: '2.13'
533
533
  Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ImplicitSubject
534
534
 
535
+ RSpec/IncludeExamples:
536
+ Description: Checks for usage of `include_examples`.
537
+ Enabled: pending
538
+ VersionAdded: '3.6'
539
+ Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/IncludeExamples
540
+
535
541
  RSpec/IndexedLet:
536
542
  Description: Do not set up test data using indexes (e.g., `item_1`, `item_2`).
537
543
  Enabled: true
@@ -930,13 +936,6 @@ RSpec/SpecFilePathSuffix:
930
936
  - "**/spec/**/*"
931
937
  Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/SpecFilePathSuffix
932
938
 
933
- RSpec/StringAsInstanceDoubleConstant:
934
- Description: Do not use a string as `instance_double` constant.
935
- Enabled: pending
936
- Safe: false
937
- VersionAdded: '3.1'
938
- Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/StringAsInstanceDoubleConstant
939
-
940
939
  RSpec/StubbedMock:
941
940
  Description: Checks that message expectations do not have a configured response.
942
941
  Enabled: true
@@ -995,12 +994,8 @@ RSpec/VerifiedDoubleReference:
995
994
  Description: Checks for consistent verified double reference style.
996
995
  Enabled: true
997
996
  SafeAutoCorrect: false
998
- EnforcedStyle: constant
999
- SupportedStyles:
1000
- - constant
1001
- - string
1002
997
  VersionAdded: 2.10.0
1003
- VersionChanged: '2.12'
998
+ VersionChanged: '3.4'
1004
999
  Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/VerifiedDoubleReference
1005
1000
 
1006
1001
  RSpec/VerifiedDoubles:
@@ -12,6 +12,9 @@ changed_parameters:
12
12
  parameters: IgnoredPatterns
13
13
  alternative: AllowedPatterns
14
14
  severity: warning
15
+ - cops: RSpec/VerifiedDoubleReference
16
+ parameters: EnforcedStyle
17
+ reason: String references are not verifying unless the class is loaded.
15
18
 
16
19
  split:
17
20
  RSpec/FilePath:
@@ -23,6 +26,8 @@ removed:
23
26
  RSpec/Capybara/FeatureMethods:
24
27
  reason: >
25
28
  this cop has migrated to `RSpec/Dialect`. Please use `RSpec/Dialect` instead
29
+ RSpec/StringAsInstanceDoubleConstant:
30
+ reason: Please use `RSpec/VerifiedDoubleReference` instead
26
31
 
27
32
  extracted:
28
33
  RSpec/Rails/*: rubocop-rspec_rails
@@ -31,7 +31,7 @@ module RuboCop
31
31
 
32
32
  # @!method eq_type_with_identity?(node)
33
33
  def_node_matcher :eq_type_with_identity?, <<~PATTERN
34
- (send nil? :eq {true false nil})
34
+ (send nil? :eq {boolean nil})
35
35
  PATTERN
36
36
 
37
37
  def on_send(node)
@@ -45,7 +45,7 @@ module RuboCop
45
45
 
46
46
  # @!method eql_type_with_identity(node)
47
47
  def_node_matcher :eql_type_with_identity, <<~PATTERN
48
- (send _ :to $(send nil? :eql {true false int float sym nil}))
48
+ (send _ :to $(send nil? :eql {boolean int float sym nil}))
49
49
  PATTERN
50
50
 
51
51
  def on_send(node)
@@ -48,6 +48,10 @@ module RuboCop
48
48
  check_be_style(node)
49
49
  when :be_nil
50
50
  check_be_nil_style(node)
51
+ else
52
+ # :nocov:
53
+ :noop
54
+ # :nocov:
51
55
  end
52
56
  end
53
57
 
@@ -101,8 +101,9 @@ module RuboCop
101
101
 
102
102
  private
103
103
 
104
- # rubocop:disable Metrics/MethodLength
105
104
  def register_offense(node, change_node)
105
+ return unless node.parent.send_type?
106
+
106
107
  if compound_expectations?(node)
107
108
  add_offense(node,
108
109
  message: message_compound(change_node)) do |corrector|
@@ -115,11 +116,9 @@ module RuboCop
115
116
  end
116
117
  end
117
118
  end
118
- # rubocop:enable Metrics/MethodLength
119
119
 
120
120
  def compound_expectations?(node)
121
- node.parent.send_type? &&
122
- %i[and or & |].include?(node.parent.method_name)
121
+ %i[and or & |].include?(node.parent.method_name)
123
122
  end
124
123
 
125
124
  def message(change_node)
@@ -6,6 +6,7 @@ module RuboCop
6
6
  # Checks where `contain_exactly` is used.
7
7
  #
8
8
  # This cop checks for the following:
9
+ #
9
10
  # - Prefer `match_array` when matching array values.
10
11
  # - Prefer `be_empty` when using `contain_exactly` with no arguments.
11
12
  #
@@ -115,7 +115,12 @@ module RuboCop
115
115
  end
116
116
 
117
117
  def prefixes
118
- Array(cop_config.fetch('Prefixes', []))
118
+ Array(cop_config.fetch('Prefixes', [])).tap do |prefixes|
119
+ non_strings = prefixes.reject { |pre| pre.is_a?(String) }
120
+ unless non_strings.empty?
121
+ raise "Non-string prefixes #{non_strings.inspect} detected."
122
+ end
123
+ end
119
124
  end
120
125
  end
121
126
  end
@@ -83,7 +83,7 @@ module RuboCop
83
83
 
84
84
  # @!method rspec_block?(node)
85
85
  def_node_matcher :rspec_block?,
86
- '({block numblock} (send #rspec? #ALL.all ...) ...)'
86
+ '(any_block (send #rspec? #ALL.all ...) ...)'
87
87
 
88
88
  # @!method scope_changing_syntax?(node)
89
89
  def_node_matcher :scope_changing_syntax?, '{def class module}'
@@ -153,7 +153,9 @@ module RuboCop
153
153
  end
154
154
 
155
155
  def skippable_block?(node)
156
- node.block_type? && !rspec_block?(node) && cop_config['SkipBlocks']
156
+ return false unless cop_config['SkipBlocks']
157
+
158
+ node.any_block_type? && !rspec_block?(node)
157
159
  end
158
160
 
159
161
  def only_static_constants?
@@ -24,7 +24,7 @@ module RuboCop
24
24
 
25
25
  # @!method include_rspec_blocks?(node)
26
26
  def_node_search :include_rspec_blocks?, <<~PATTERN
27
- ({block numblock} (send #explicit_rspec? #ExampleGroups.all ...) ...)
27
+ (any_block (send #explicit_rspec? #ExampleGroups.all ...) ...)
28
28
  PATTERN
29
29
 
30
30
  def on_module(node)
@@ -130,13 +130,14 @@ module RuboCop
130
130
  def_node_matcher :examples?, <<~PATTERN
131
131
  {
132
132
  #examples_directly_or_in_block?
133
+ #examples_in_branches?
133
134
  (begin <#examples_directly_or_in_block? ...>)
134
135
  (begin <#examples_in_branches? ...>)
135
136
  }
136
137
  PATTERN
137
138
 
138
139
  def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
139
- return if node.each_ancestor(:def, :defs).any?
140
+ return if node.each_ancestor(:any_def).any?
140
141
  return if node.each_ancestor(:block).any? { |block| example?(block) }
141
142
 
142
143
  example_group_body(node) do |body|
@@ -154,7 +155,7 @@ module RuboCop
154
155
  return true unless body
155
156
  return false if conditionals_with_examples?(body)
156
157
 
157
- if body.if_type? || body.case_type?
158
+ if body.type?(:if, :case)
158
159
  !examples_in_branches?(body)
159
160
  else
160
161
  !examples?(body)
@@ -162,7 +163,7 @@ module RuboCop
162
163
  end
163
164
 
164
165
  def conditionals_with_examples?(body)
165
- return false unless body.begin_type? || body.case_type?
166
+ return false unless body.type?(:begin, :case)
166
167
 
167
168
  body.each_descendant(:if, :case).any? do |condition_node|
168
169
  examples_in_branches?(condition_node)
@@ -170,7 +171,8 @@ module RuboCop
170
171
  end
171
172
 
172
173
  def examples_in_branches?(condition_node)
173
- return false if !condition_node.if_type? && !condition_node.case_type?
174
+ return false unless condition_node
175
+ return false unless condition_node.type?(:if, :case)
174
176
 
175
177
  condition_node.branches.any? { |branch| examples?(branch) }
176
178
  end
@@ -67,7 +67,6 @@ module RuboCop
67
67
  } ...) ...)
68
68
  PATTERN
69
69
 
70
- # rubocop:disable Metrics/MethodLength
71
70
  def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
72
71
  it_description(node) do |description_node, message|
73
72
  if message.match?(SHOULD_PREFIX)
@@ -82,7 +81,6 @@ module RuboCop
82
81
  end
83
82
  end
84
83
  end
85
- # rubocop:enable Metrics/MethodLength
86
84
 
87
85
  private
88
86
 
@@ -128,7 +126,7 @@ module RuboCop
128
126
  node.node_parts.map { |child_node| text(child_node) }.join
129
127
  when :str
130
128
  node.value
131
- when :begin
129
+ else
132
130
  node.source
133
131
  end
134
132
  end
@@ -100,7 +100,7 @@ module RuboCop
100
100
  node.node_parts.map { |child_node| text(child_node) }.join
101
101
  when :str, :sym
102
102
  node.value
103
- when :begin
103
+ else
104
104
  node.source
105
105
  end
106
106
  end
@@ -65,7 +65,7 @@ module RuboCop
65
65
  )
66
66
  PATTERN
67
67
 
68
- def on_send(node) # rubocop:disable Metrics/MethodLength
68
+ def on_send(node)
69
69
  expect_literal(node) do |actual, send_node, matcher, expected|
70
70
  next if SKIPPED_MATCHERS.include?(matcher)
71
71
 
@@ -5,11 +5,30 @@ module RuboCop
5
5
  module RSpec
6
6
  # Checks for consistent style of change matcher.
7
7
  #
8
- # Enforces either passing object and attribute as arguments to the matcher
9
- # or passing a block that reads the attribute value.
8
+ # Enforces either passing a receiver and message as method arguments,
9
+ # or a block.
10
10
  #
11
11
  # This cop can be configured using the `EnforcedStyle` option.
12
12
  #
13
+ # @safety
14
+ # Autocorrection is unsafe because `method_call` style calls the
15
+ # receiver *once* and sends the message to it before and after
16
+ # calling the `expect` block, whereas `block` style calls the
17
+ # expression *twice*, including the receiver.
18
+ #
19
+ # If your receiver is dynamic (e.g., the result of a method call) and
20
+ # you expect it to be called before and after the `expect` block,
21
+ # changing from `block` to `method_call` style may break your test.
22
+ #
23
+ # [source,ruby]
24
+ # ----
25
+ # expect { run }.to change { my_method.message }
26
+ # # `my_method` is called before and after `run`
27
+ #
28
+ # expect { run }.to change(my_method, :message)
29
+ # # `my_method` is called once, but `message` is called on it twice
30
+ # ----
31
+ #
13
32
  # @example `EnforcedStyle: method_call` (default)
14
33
  # # bad
15
34
  # expect { run }.to change { Foo.bar }
@@ -29,12 +29,6 @@ module RuboCop
29
29
  # describe 'test' do; end
30
30
  #
31
31
  # # bad
32
- # fdescribe 'test' do; end
33
- #
34
- # # good
35
- # describe 'test' do; end
36
- #
37
- # # bad
38
32
  # shared_examples 'test', focus: true do; end
39
33
  #
40
34
  # # good
@@ -79,25 +73,29 @@ module RuboCop
79
73
  PATTERN
80
74
 
81
75
  def on_send(node)
82
- return if node.chained? || node.each_ancestor(:def, :defs).any?
76
+ return if node.chained? || node.each_ancestor(:any_def).any?
83
77
 
84
- focus_metadata(node) do |focus|
85
- add_offense(focus) do |corrector|
86
- if focus.pair_type? || focus.str_type? || focus.sym_type?
87
- corrector.remove(with_surrounding(focus))
88
- elsif focus.send_type?
89
- correct_send(corrector, focus)
90
- end
78
+ if focused_block?(node)
79
+ on_focused_block(node)
80
+ else
81
+ metadata(node) do |focus|
82
+ on_metadata(focus)
91
83
  end
92
84
  end
93
85
  end
94
86
 
95
87
  private
96
88
 
97
- def focus_metadata(node, &block)
98
- yield(node) if focused_block?(node)
89
+ def on_focused_block(node)
90
+ add_offense(node) do |corrector|
91
+ correct_send(corrector, node)
92
+ end
93
+ end
99
94
 
100
- metadata(node, &block)
95
+ def on_metadata(node)
96
+ add_offense(node) do |corrector|
97
+ corrector.remove(with_surrounding(node))
98
+ end
101
99
  end
102
100
 
103
101
  def with_surrounding(focus)
@@ -67,12 +67,12 @@ module RuboCop
67
67
 
68
68
  # @!method scoped_hook(node)
69
69
  def_node_matcher :scoped_hook, <<~PATTERN
70
- ({block numblock} $(send _ #Hooks.all (sym ${:each :example})) ...)
70
+ (any_block $(send _ #Hooks.all (sym ${:each :example})) ...)
71
71
  PATTERN
72
72
 
73
73
  # @!method unscoped_hook(node)
74
74
  def_node_matcher :unscoped_hook, <<~PATTERN
75
- ({block numblock} $(send _ #Hooks.all) ...)
75
+ (any_block $(send _ #Hooks.all) ...)
76
76
  PATTERN
77
77
 
78
78
  def on_block(node)
@@ -30,7 +30,7 @@ module RuboCop
30
30
  # @!method example_or_group?(node)
31
31
  def_node_matcher :example_or_group?, <<~PATTERN
32
32
  {
33
- ({block numblock} {
33
+ (any_block {
34
34
  (send #rspec? #ExampleGroups.all ...)
35
35
  (send nil? #Examples.all ...)
36
36
  } ...)
@@ -46,7 +46,7 @@ module RuboCop
46
46
 
47
47
  ENFORCED_REPLACEMENTS = alternatives.merge(alternatives.invert).freeze
48
48
 
49
- def on_send(node) # rubocop:disable Metrics/MethodLength
49
+ def on_send(node)
50
50
  return unless (source_range = offending_expect(node))
51
51
 
52
52
  expectation_source = source_range.source
@@ -69,13 +69,13 @@ module RuboCop
69
69
  def offending_expect(node)
70
70
  case implicit_expect(node)
71
71
  when :is_expected
72
- is_expected_range(node.loc)
72
+ range_for_is_expected(node.loc)
73
73
  when :should, :should_not
74
74
  node.loc.selector
75
75
  end
76
76
  end
77
77
 
78
- def is_expected_range(source_map) # rubocop:disable Naming/PredicateName
78
+ def range_for_is_expected(source_map)
79
79
  Parser::Source::Range.new(
80
80
  source_map.expression.source_buffer,
81
81
  source_map.expression.begin_pos,
@@ -107,6 +107,10 @@ module RuboCop
107
107
  corrector.replace(node.location.selector, 'expect(subject).to')
108
108
  when :should_not
109
109
  corrector.replace(node.location.selector, 'expect(subject).not_to')
110
+ else
111
+ # :nocov:
112
+ :noop
113
+ # :nocov:
110
114
  end
111
115
  end
112
116
 
@@ -129,6 +133,10 @@ module RuboCop
129
133
  implicit_subject_in_non_its_and_non_single_line?(node)
130
134
  when :single_statement_only
131
135
  implicit_subject_in_non_its_and_non_single_statement?(node)
136
+ else
137
+ # :nocov:
138
+ :noop
139
+ # :nocov:
132
140
  end
133
141
  end
134
142
 
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module RSpec
6
+ # Checks for usage of `include_examples`.
7
+ #
8
+ # `include_examples`, unlike `it_behaves_like`, does not create its
9
+ # own context. As such, using `subject`, `let`, `before`/`after`, etc.
10
+ # within shared examples included with `include_examples` can have
11
+ # unexpected behavior and side effects.
12
+ #
13
+ # Prefer using `it_behaves_like` instead.
14
+ #
15
+ # @example
16
+ # # bad
17
+ # include_examples 'examples'
18
+ #
19
+ # # good
20
+ # it_behaves_like 'examples'
21
+ #
22
+ class IncludeExamples < Base
23
+ extend AutoCorrector
24
+
25
+ MSG = 'Prefer `it_behaves_like` over `include_examples`.'
26
+
27
+ RESTRICT_ON_SEND = %i[include_examples].freeze
28
+
29
+ def on_send(node)
30
+ selector = node.loc.selector
31
+
32
+ add_offense(selector) do |corrector|
33
+ corrector.replace(selector, 'it_behaves_like')
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -74,7 +74,9 @@ module RuboCop
74
74
  private
75
75
 
76
76
  SUFFIX_INDEX_REGEX = /_?\d+$/.freeze
77
+ private_constant :SUFFIX_INDEX_REGEX
77
78
  INDEX_REGEX = /\d+/.freeze
79
+ private_constant :INDEX_REGEX
78
80
 
79
81
  def filter_indexed_lets(candidates)
80
82
  candidates
@@ -6,6 +6,7 @@ module RuboCop
6
6
  # Checks where `match_array` is used.
7
7
  #
8
8
  # This cop checks for the following:
9
+ #
9
10
  # - Prefer `contain_exactly` when matching an array with values.
10
11
  # - Prefer `eq` when using `match_array` with an empty array literal.
11
12
  #
@@ -80,6 +80,10 @@ module RuboCop
80
80
  MSG_RECEIVE
81
81
  when :have_received
82
82
  format(MSG_HAVE_RECEIVED, source: receiver.source)
83
+ else
84
+ # :nocov:
85
+ :noop
86
+ # :nocov:
83
87
  end
84
88
  end
85
89
  end
@@ -47,15 +47,12 @@ module RuboCop
47
47
  private
48
48
 
49
49
  def on_metadata_arguments(metadata_arguments)
50
- *symbols, last = metadata_arguments
51
- hash = nil
52
- case last&.type
53
- when :hash
54
- hash = last
55
- when :sym
56
- symbols << last
50
+ if metadata_arguments.last&.hash_type?
51
+ *metadata_arguments, hash = metadata_arguments
52
+ on_metadata(metadata_arguments, hash)
53
+ else
54
+ on_metadata(metadata_arguments, nil)
57
55
  end
58
- on_metadata(symbols, hash)
59
56
  end
60
57
  end
61
58
  end
@@ -133,8 +133,8 @@ module RuboCop
133
133
 
134
134
  def count_up_nesting?(node, example_group)
135
135
  example_group &&
136
- (node.block_type? &&
137
- !allowed_groups.include?(node.method_name.to_s))
136
+ node.block_type? &&
137
+ !allowed_groups.include?(node.method_name.to_s)
138
138
  end
139
139
 
140
140
  def message(nesting)
@@ -65,7 +65,7 @@ module RuboCop
65
65
  # @param [RuboCop::AST::Node] node
66
66
  # @return [Boolean]
67
67
  def_node_matcher :regular_or_focused_example?, <<~PATTERN
68
- ({block numblock} (send nil? {#Examples.regular #Examples.focused} ...) ...)
68
+ (any_block (send nil? {#Examples.regular #Examples.focused} ...) ...)
69
69
  PATTERN
70
70
 
71
71
  # @!method includes_expectation?(node)