rubocop-rspec 3.5.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5852eb2103d4a2993b2174b7e4c97f5f7f09041c49407122ab6568d744d52c09
4
- data.tar.gz: 710d277b8be358c99cadf4ca500141d23fa73347ba3f29db0585a1e7026abd73
3
+ metadata.gz: 4e4727f136d1a399d3108fd010c76ac61f7fce57e3c89cb2d97ad121d558af44
4
+ data.tar.gz: dcc8c7f61c420d5938807dae3a610f53c6be8c657687e38542f701db2aec4ce2
5
5
  SHA512:
6
- metadata.gz: e27d20e6945c05f12af9fc24e17e42691186b332611d96eb9e7a5444476de44209517ccdb4829096cff659e7a7d1b98941ff632b3f7f5a547aa4dc82d3e18e38
7
- data.tar.gz: 93a9cb481828abc2e313129cec383d38de5261f382d7ae6fcabe42bd0146b5a134b90991df47cc0bade3c1e4266cbfcf733f35ea7bee8eafaa3e5e4236a0b3ca
6
+ metadata.gz: 651f8b53a0b70738f9dc084df5bdf471ce65ae4d7f0c2db8cc2eb557178fd541f317bee36ae062b8109aed72b452f69eb1c965db923d5d9875c86de9ab84f23e
7
+ data.tar.gz: f189ec83b4b663df4e3aca303f2f273fded6d5529e689d7f9421f379dd46203da95236a4f649414466b0f6050b0d9e7d952df003b4b63ed45722c1764fd1a094
data/CHANGELOG.md CHANGED
@@ -2,6 +2,15 @@
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
+
5
14
  ## 3.5.0 (2025-02-16)
6
15
 
7
16
  - Don't let `RSpec/PredicateMatcher` replace `respond_to?` with two arguments with the RSpec `respond_to` matcher. ([@bquorning])
@@ -998,6 +1007,7 @@ Compatibility release so users can upgrade RuboCop to 0.51.0. No new features.
998
1007
  [@krororo]: https://github.com/krororo
999
1008
  [@kuahyeow]: https://github.com/kuahyeow
1000
1009
  [@lazycoder9]: https://github.com/lazycoder9
1010
+ [@lee266]: https://github.com/lee266
1001
1011
  [@leoarnold]: https://github.com/leoarnold
1002
1012
  [@liberatys]: https://github.com/Liberatys
1003
1013
  [@lokhi]: https://github.com/lokhi
@@ -1038,6 +1048,7 @@ Compatibility release so users can upgrade RuboCop to 0.51.0. No new features.
1038
1048
  [@rrosenblum]: https://github.com/rrosenblum
1039
1049
  [@rspeicher]: https://github.com/rspeicher
1040
1050
  [@rst-j]: https://github.com/RST-J
1051
+ [@sakuro]: https://github.com/sakuro
1041
1052
  [@samrjenkins]: https://github.com/samrjenkins
1042
1053
  [@schmijos]: https://github.com/schmijos
1043
1054
  [@seanpdoyle]: https://github.com/seanpdoyle
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
@@ -102,6 +102,8 @@ module RuboCop
102
102
  private
103
103
 
104
104
  def register_offense(node, change_node)
105
+ return unless node.parent.send_type?
106
+
105
107
  if compound_expectations?(node)
106
108
  add_offense(node,
107
109
  message: message_compound(change_node)) do |corrector|
@@ -116,8 +118,7 @@ module RuboCop
116
118
  end
117
119
 
118
120
  def compound_expectations?(node)
119
- node.parent.send_type? &&
120
- %i[and or & |].include?(node.parent.method_name)
121
+ %i[and or & |].include?(node.parent.method_name)
121
122
  end
122
123
 
123
124
  def message(change_node)
@@ -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)
@@ -137,7 +137,7 @@ module RuboCop
137
137
  PATTERN
138
138
 
139
139
  def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
140
- return if node.each_ancestor(:def, :defs).any?
140
+ return if node.each_ancestor(:any_def).any?
141
141
  return if node.each_ancestor(:block).any? { |block| example?(block) }
142
142
 
143
143
  example_group_body(node) do |body|
@@ -155,7 +155,7 @@ module RuboCop
155
155
  return true unless body
156
156
  return false if conditionals_with_examples?(body)
157
157
 
158
- if body.if_type? || body.case_type?
158
+ if body.type?(:if, :case)
159
159
  !examples_in_branches?(body)
160
160
  else
161
161
  !examples?(body)
@@ -163,7 +163,7 @@ module RuboCop
163
163
  end
164
164
 
165
165
  def conditionals_with_examples?(body)
166
- return false unless body.begin_type? || body.case_type?
166
+ return false unless body.type?(:begin, :case)
167
167
 
168
168
  body.each_descendant(:if, :case).any? do |condition_node|
169
169
  examples_in_branches?(condition_node)
@@ -172,7 +172,7 @@ module RuboCop
172
172
 
173
173
  def examples_in_branches?(condition_node)
174
174
  return false unless condition_node
175
- return false if !condition_node.if_type? && !condition_node.case_type?
175
+ return false unless condition_node.type?(:if, :case)
176
176
 
177
177
  condition_node.branches.any? { |branch| examples?(branch) }
178
178
  end
@@ -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 }
@@ -73,7 +73,7 @@ module RuboCop
73
73
  PATTERN
74
74
 
75
75
  def on_send(node)
76
- return if node.chained? || node.each_ancestor(:def, :defs).any?
76
+ return if node.chained? || node.each_ancestor(:any_def).any?
77
77
 
78
78
  if focused_block?(node)
79
79
  on_focused_block(node)
@@ -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
  } ...)
@@ -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
@@ -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)
@@ -47,7 +47,7 @@ module RuboCop
47
47
 
48
48
  # @!method skippable_example?(node)
49
49
  def_node_matcher :skippable_example?, <<~PATTERN
50
- (send nil? #Examples.regular ...)
50
+ (send nil? #Examples.regular _ ...)
51
51
  PATTERN
52
52
 
53
53
  # @!method pending_block?(node)
@@ -63,8 +63,7 @@ module RuboCop
63
63
  def_node_matcher :skipped_in_example?, <<~PATTERN
64
64
  {
65
65
  (send nil? ${#Examples.skipped #Examples.pending})
66
- (block (send nil? ${#Examples.skipped}) ...)
67
- (numblock (send nil? ${#Examples.skipped}) ...)
66
+ (any_block (send nil? ${#Examples.skipped}) ...)
68
67
  }
69
68
  PATTERN
70
69
 
@@ -75,7 +74,7 @@ module RuboCop
75
74
 
76
75
  # @!method skipped_by_example_method_with_block?(node)
77
76
  def_node_matcher :skipped_by_example_method_with_block?, <<~PATTERN
78
- ({block numblock} (send nil? ${#Examples.skipped #Examples.pending} ...) ...)
77
+ (any_block (send nil? ${#Examples.skipped #Examples.pending} ...) ...)
79
78
  PATTERN
80
79
 
81
80
  # @!method metadata_without_reason?(node)
@@ -182,7 +182,7 @@ module RuboCop
182
182
 
183
183
  def heredoc_argument?(matcher)
184
184
  matcher.arguments.select do |arg|
185
- arg.str_type? || arg.dstr_type? || arg.xstr_type?
185
+ arg.type?(:str, :dstr, :xstr)
186
186
  end.any?(&:heredoc?)
187
187
  end
188
188
 
@@ -148,8 +148,7 @@ module RuboCop
148
148
  end
149
149
 
150
150
  def heredoc_or_splat?(node)
151
- ((node.str_type? || node.dstr_type?) && node.heredoc?) ||
152
- node.splat_type?
151
+ (node.type?(:str, :dstr) && node.heredoc?) || node.splat_type?
153
152
  end
154
153
 
155
154
  def requires_quotes?(value)
@@ -41,7 +41,7 @@ module RuboCop
41
41
 
42
42
  # @!method match_redundant_around_hook_block?(node)
43
43
  def_node_matcher :match_redundant_around_hook_block?, <<~PATTERN
44
- ({block numblock} (send _ :around ...) ... (send _ :run))
44
+ (any_block (send _ :around ...) ... (send _ :run))
45
45
  PATTERN
46
46
 
47
47
  # @!method match_redundant_around_hook_send?(node)
@@ -5,7 +5,9 @@ module RuboCop
5
5
  module RSpec
6
6
  # Checks for setup scattered across multiple hooks in an example group.
7
7
  #
8
- # Unify `before`, `after`, and `around` hooks when possible.
8
+ # Unify `before` and `after` hooks when possible.
9
+ # However, `around` hooks are allowed to be defined multiple times,
10
+ # as unifying them would typically make the code harder to read.
9
11
  #
10
12
  # @example
11
13
  # # bad
@@ -22,6 +24,12 @@ module RuboCop
22
24
  # end
23
25
  # end
24
26
  #
27
+ # # good
28
+ # describe Foo do
29
+ # around { |example| before1; example.call; after1 }
30
+ # around { |example| before2; example.call; after2 }
31
+ # end
32
+ #
25
33
  class ScatteredSetup < Base
26
34
  include FinalEndLocation
27
35
  include RangeHelp
@@ -48,7 +56,7 @@ module RuboCop
48
56
  def repeated_hooks(node)
49
57
  hooks = RuboCop::RSpec::ExampleGroup.new(node)
50
58
  .hooks
51
- .select(&:knowable_scope?)
59
+ .select { |hook| hook.knowable_scope? && hook.name != :around }
52
60
  .group_by { |hook| [hook.name, hook.scope, hook.metadata] }
53
61
  .values
54
62
  .reject(&:one?)
@@ -69,7 +69,7 @@ module RuboCop
69
69
  end
70
70
 
71
71
  def symbol?(node)
72
- node.sym_type? || node.dsym_type?
72
+ node.type?(:sym, :dsym)
73
73
  end
74
74
  end
75
75
  end
@@ -50,7 +50,7 @@ module RuboCop
50
50
  return unless inside_example_group?(node)
51
51
 
52
52
  variable_definition?(node) do |variable|
53
- return if variable.dstr_type? || variable.dsym_type?
53
+ return if variable.type?(:dstr, :dsym)
54
54
  return if matches_allowed_pattern?(variable.value)
55
55
 
56
56
  check_name(node, variable.value, variable.source_range)
@@ -48,6 +48,7 @@ require_relative 'rspec/identical_equality_assertion'
48
48
  require_relative 'rspec/implicit_block_expectation'
49
49
  require_relative 'rspec/implicit_expect'
50
50
  require_relative 'rspec/implicit_subject'
51
+ require_relative 'rspec/include_examples'
51
52
  require_relative 'rspec/indexed_let'
52
53
  require_relative 'rspec/instance_spy'
53
54
  require_relative 'rspec/instance_variable'
@@ -64,7 +64,9 @@ module RuboCop
64
64
  end
65
65
 
66
66
  def transform_true(node)
67
- node.true_type? ? true : node
67
+ return true if node.true_type?
68
+
69
+ node
68
70
  end
69
71
 
70
72
  def scope_name
@@ -26,7 +26,7 @@ module RuboCop
26
26
 
27
27
  # @!method example_group?(node)
28
28
  def_node_matcher :example_group?, <<~PATTERN
29
- ({block numblock} (send #rspec? #ExampleGroups.all ...) ...)
29
+ (any_block (send #rspec? #ExampleGroups.all ...) ...)
30
30
  PATTERN
31
31
 
32
32
  # @!method shared_group?(node)
@@ -35,7 +35,7 @@ module RuboCop
35
35
 
36
36
  # @!method spec_group?(node)
37
37
  def_node_matcher :spec_group?, <<~PATTERN
38
- ({block numblock} (send #rspec?
38
+ (any_block (send #rspec?
39
39
  {#SharedGroups.all #ExampleGroups.all}
40
40
  ...) ...)
41
41
  PATTERN
@@ -50,10 +50,7 @@ module RuboCop
50
50
 
51
51
  # @!method hook?(node)
52
52
  def_node_matcher :hook?, <<~PATTERN
53
- {
54
- (numblock (send nil? #Hooks.all ...) ...)
55
- (block (send nil? #Hooks.all ...) ...)
56
- }
53
+ (any_block (send nil? #Hooks.all ...) ...)
57
54
  PATTERN
58
55
 
59
56
  # @!method let?(node)
@@ -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.5.0'
7
+ STRING = '3.6.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.5.0
4
+ version: 3.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Backus
@@ -9,7 +9,7 @@ authors:
9
9
  - Nils Gemeinhardt
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2025-02-16 00:00:00.000000000 Z
12
+ date: 1980-01-02 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: lint_roller
@@ -114,6 +114,7 @@ files:
114
114
  - lib/rubocop/cop/rspec/implicit_block_expectation.rb
115
115
  - lib/rubocop/cop/rspec/implicit_expect.rb
116
116
  - lib/rubocop/cop/rspec/implicit_subject.rb
117
+ - lib/rubocop/cop/rspec/include_examples.rb
117
118
  - lib/rubocop/cop/rspec/indexed_let.rb
118
119
  - lib/rubocop/cop/rspec/instance_spy.rb
119
120
  - lib/rubocop/cop/rspec/instance_variable.rb
@@ -226,7 +227,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
226
227
  - !ruby/object:Gem::Version
227
228
  version: '0'
228
229
  requirements: []
229
- rubygems_version: 3.6.2
230
+ rubygems_version: 3.6.7
230
231
  specification_version: 4
231
232
  summary: Code style checking for RSpec files
232
233
  test_files: []