rubocop-rspec 1.33.0 → 1.34.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 (64) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +16 -2
  3. data/README.md +10 -2
  4. data/config/default.yml +6 -1
  5. data/lib/rubocop/cop/rspec/any_instance.rb +0 -1
  6. data/lib/rubocop/cop/rspec/around_block.rb +1 -2
  7. data/lib/rubocop/cop/rspec/before_after_all.rb +0 -1
  8. data/lib/rubocop/cop/rspec/context_wording.rb +18 -17
  9. data/lib/rubocop/cop/rspec/describe_class.rb +1 -1
  10. data/lib/rubocop/cop/rspec/describe_method.rb +1 -1
  11. data/lib/rubocop/cop/rspec/describe_symbol.rb +1 -1
  12. data/lib/rubocop/cop/rspec/described_class.rb +79 -13
  13. data/lib/rubocop/cop/rspec/empty_example_group.rb +1 -1
  14. data/lib/rubocop/cop/rspec/empty_line_after_subject.rb +1 -1
  15. data/lib/rubocop/cop/rspec/example_length.rb +1 -1
  16. data/lib/rubocop/cop/rspec/example_wording.rb +6 -4
  17. data/lib/rubocop/cop/rspec/expect_actual.rb +1 -1
  18. data/lib/rubocop/cop/rspec/expect_output.rb +2 -0
  19. data/lib/rubocop/cop/rspec/factory_bot/attribute_defined_statically.rb +1 -1
  20. data/lib/rubocop/cop/rspec/factory_bot/create_list.rb +1 -2
  21. data/lib/rubocop/cop/rspec/file_path.rb +0 -1
  22. data/lib/rubocop/cop/rspec/focus.rb +1 -1
  23. data/lib/rubocop/cop/rspec/hook_argument.rb +0 -1
  24. data/lib/rubocop/cop/rspec/instance_spy.rb +1 -1
  25. data/lib/rubocop/cop/rspec/instance_variable.rb +1 -1
  26. data/lib/rubocop/cop/rspec/invalid_predicate_matcher.rb +1 -1
  27. data/lib/rubocop/cop/rspec/it_behaves_like.rb +1 -1
  28. data/lib/rubocop/cop/rspec/iterated_expectation.rb +1 -1
  29. data/lib/rubocop/cop/rspec/leading_subject.rb +0 -1
  30. data/lib/rubocop/cop/rspec/leaky_constant_declaration.rb +128 -0
  31. data/lib/rubocop/cop/rspec/let_before_examples.rb +1 -1
  32. data/lib/rubocop/cop/rspec/let_setup.rb +2 -4
  33. data/lib/rubocop/cop/rspec/missing_example_group_argument.rb +1 -2
  34. data/lib/rubocop/cop/rspec/multiple_describes.rb +1 -1
  35. data/lib/rubocop/cop/rspec/multiple_expectations.rb +32 -16
  36. data/lib/rubocop/cop/rspec/multiple_subjects.rb +1 -1
  37. data/lib/rubocop/cop/rspec/nested_groups.rb +0 -1
  38. data/lib/rubocop/cop/rspec/overwriting_setup.rb +0 -1
  39. data/lib/rubocop/cop/rspec/pending.rb +1 -1
  40. data/lib/rubocop/cop/rspec/predicate_matcher.rb +0 -3
  41. data/lib/rubocop/cop/rspec/repeated_description.rb +1 -1
  42. data/lib/rubocop/cop/rspec/repeated_example.rb +1 -1
  43. data/lib/rubocop/cop/rspec/scattered_let.rb +1 -1
  44. data/lib/rubocop/cop/rspec/scattered_setup.rb +1 -1
  45. data/lib/rubocop/cop/rspec/shared_context.rb +0 -1
  46. data/lib/rubocop/cop/rspec/single_argument_message_chain.rb +1 -1
  47. data/lib/rubocop/cop/rspec/subject_stub.rb +17 -20
  48. data/lib/rubocop/cop/rspec/unspecified_exception.rb +1 -4
  49. data/lib/rubocop/cop/rspec/verified_doubles.rb +1 -1
  50. data/lib/rubocop/cop/rspec/void_expect.rb +1 -1
  51. data/lib/rubocop/cop/rspec_cops.rb +1 -0
  52. data/lib/rubocop/rspec/language.rb +1 -1
  53. data/lib/rubocop/rspec/top_level_describe.rb +0 -4
  54. data/lib/rubocop/rspec/version.rb +1 -1
  55. data/spec/rubocop/cop/rspec/cop_spec.rb +3 -3
  56. data/spec/rubocop/cop/rspec/describe_class_spec.rb +7 -0
  57. data/spec/rubocop/cop/rspec/described_class_spec.rb +113 -80
  58. data/spec/rubocop/cop/rspec/example_wording_spec.rb +33 -0
  59. data/spec/rubocop/cop/rspec/leaky_constant_declaration_spec.rb +91 -0
  60. data/spec/rubocop/cop/rspec/let_setup_spec.rb +2 -2
  61. data/spec/rubocop/cop/rspec/multiple_expectations_spec.rb +64 -37
  62. data/spec/rubocop/cop/rspec/subject_stub_spec.rb +113 -14
  63. data/spec/rubocop/rspec/language/selector_set_spec.rb +2 -2
  64. metadata +5 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 53e671fa54f485f07186b567e9e44f7522db1e9508f5f723549c1f50f467ef68
4
- data.tar.gz: 5f842a528fb62843a686e9674d4b94f5a44008afbc602c9babfb91ddf90ef4df
3
+ metadata.gz: b93f9fd4cff11c9b4a47a1bffca8e578bcf0e354320b461d63cdab7d01fad49b
4
+ data.tar.gz: 31244d48dd90be566b9f3b18dbe3f7c40112de41ef9fe9dbcbc282e20da2c66e
5
5
  SHA512:
6
- metadata.gz: 1e03a650246098cb4498448db4e91846bb25643ea3673ec54db68678dbe80acefecbc69f20ca484addbea5f8a97a7dd84e3d21205b14da21cc74de45d8048501
7
- data.tar.gz: 1d3cfdc4b32495be01056e6435bebaf1c1575bb37bda80973c31095ec4ce2f3556ce90ad9360e81102522869fa57c1f0eb6d005d670820b75df00c70e689131e
6
+ metadata.gz: ca99737cdb9ebea08757e8412974d678c846623798efab61a3a8e3e35ece75ccde9c3bcb41a2e800eeefa465ea955ee2683e843b62c0eda3698a0fa9f562fa05
7
+ data.tar.gz: ff707c6bd4b46f289beb68127b4b49a214c490914098aaadacf436c0efbf41511ef942cbeb52f50428310788d05fdeaf43be69a6bfe43bf5383fd50d7fe075d9
@@ -2,6 +2,18 @@
2
2
 
3
3
  ## Master (Unreleased)
4
4
 
5
+ ## 1.34.0 (2019-07-23)
6
+
7
+ * Remove `AggregateFailuresByDefault` config option of `RSpec/MultipleExpectations`. ([@pirj][])
8
+ * Add `RSpec/LeakyConstantDeclaration` cop. ([@jonatas][], [@pirj][])
9
+ * Improve `aggregate_failures` metadata detection of `RSpec/MultipleExpectations`. ([@pirj][])
10
+ * Improve `RSpec/SubjectStub` detection and message. ([@pirj][])
11
+ * Change message of `RSpec/LetSetup` cop to be more descriptive. ([@foton][])
12
+ * Improve `RSpec/ExampleWording` to handle interpolated example messages. ([@nc-holodakg][])
13
+ * Improve detection by allowing the use of `RSpec` as a top-level constant. ([@pirj][])
14
+ * Fix `RSpec/DescribedClass`'s incorrect detection. ([@pirj][])
15
+ * Improve `RSpec/DescribedClass`'s ability to detect inside modules and classes. ([@pirj][])
16
+
5
17
  ## 1.33.0 (2019-05-13)
6
18
 
7
19
  * Let `RSpec/DescribedClass` pass `Struct` instantiation closures. ([@schmijos][])
@@ -202,7 +214,7 @@ Compatibility release so users can upgrade RuboCop to 0.51.0. No new features.
202
214
  * Add [observed_nesting/max_nesting] info to `RSpec/NestedGroups` messages. ([@dgollahon][])
203
215
  * Add `RSpec/ItBehavesLike` cop. ([@dgollahon][])
204
216
  * Add `RSpec/SharedContext` cop. ([@Darhazer][])
205
- * `Rspec/MultipleExpectations`: Count aggregate_failures block as single expectation. ([@Darhazer][])
217
+ * `RSpec/MultipleExpectations`: Count aggregate_failures block as single expectation. ([@Darhazer][])
206
218
  * Fix `ExpectActual` cop flagging `rspec-rails` routing specs. ([@backus][])
207
219
  * Fix `FilePath` cop not registering offenses for files like `spec/blog/user.rb` when it should be `spec/blog/user_spec.rb`. ([@backus][])
208
220
 
@@ -310,7 +322,7 @@ Compatibility release so users can upgrade RuboCop to 0.51.0. No new features.
310
322
  * Update to rubocop 0.37.2. ([@nijikon][])
311
323
  * Update ruby versions we test against. ([@nijikon][])
312
324
  * Add `RSpec::NotToNot` cop. ([@miguelfteixeira][])
313
- * Add `Rspec/AnyInstance` cop. ([@mlarraz][])
325
+ * Add `RSpec/AnyInstance` cop. ([@mlarraz][])
314
326
 
315
327
  ## 1.3.1
316
328
 
@@ -418,3 +430,5 @@ Compatibility release so users can upgrade RuboCop to 0.51.0. No new features.
418
430
  [@mkenyon]: https://github.com/mkenyon
419
431
  [@gsamokovarov]: https://github.com/gsamokovarov
420
432
  [@schmijos]: https://github.com/schmijos
433
+ [@foton]: https://github.com/foton
434
+ [@nc-holodakg]: https://github.com/nc-holodakg
data/README.md CHANGED
@@ -32,10 +32,18 @@ ways to do this:
32
32
 
33
33
  Put this into your `.rubocop.yml`.
34
34
 
35
- ```
35
+ ```yaml
36
36
  require: rubocop-rspec
37
37
  ```
38
38
 
39
+ Alternatively, use the following array notation when specifying multiple extensions.
40
+
41
+ ```yaml
42
+ require:
43
+ - rubocop-other-extension
44
+ - rubocop-rspec
45
+ ```
46
+
39
47
  Now you can run `rubocop` and it will automatically load the RuboCop RSpec
40
48
  cops together with the standard cops.
41
49
 
@@ -119,7 +127,7 @@ is a feature of RSpec itself – you can read about it in the [RSpec Documentati
119
127
  Enforcing
120
128
 
121
129
  ```ruby
122
- Rspec.describe MyClass do
130
+ RSpec.describe MyClass do
123
131
  ...
124
132
  end
125
133
  ```
@@ -50,7 +50,7 @@ RSpec/BeforeAfterAll:
50
50
  StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/BeforeAfterAll
51
51
 
52
52
  RSpec/ContextWording:
53
- Description: "`context` block descriptions should start with 'when', or 'with'."
53
+ Description: Checks that `context` docstring starts with an allowed prefix.
54
54
  Enabled: true
55
55
  Prefixes:
56
56
  - when
@@ -251,6 +251,11 @@ RSpec/LeadingSubject:
251
251
  Enabled: true
252
252
  StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/LeadingSubject
253
253
 
254
+ RSpec/LeakyConstantDeclaration:
255
+ Description: Checks that no class, module, or constant is declared.
256
+ Enabled: true
257
+ StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/LeakyConstantDeclaration
258
+
254
259
  RSpec/LetBeforeExamples:
255
260
  Description: Checks for `let` definitions that come after an example.
256
261
  Enabled: true
@@ -33,7 +33,6 @@ module RuboCop
33
33
  disallowed_stub(node) do |method|
34
34
  add_offense(
35
35
  node,
36
- location: :expression,
37
36
  message: format(MSG, method: method)
38
37
  )
39
38
  end
@@ -51,7 +51,7 @@ module RuboCop
51
51
  private
52
52
 
53
53
  def add_no_arg_offense(node)
54
- add_offense(node, location: :expression, message: MSG_NO_ARG)
54
+ add_offense(node, message: MSG_NO_ARG)
55
55
  end
56
56
 
57
57
  def check_for_unused_proxy(block, proxy)
@@ -63,7 +63,6 @@ module RuboCop
63
63
 
64
64
  add_offense(
65
65
  proxy,
66
- location: :expression,
67
66
  message: format(MSG_UNUSED_ARG, arg: name)
68
67
  )
69
68
  end
@@ -37,7 +37,6 @@ module RuboCop
37
37
  before_or_after_all(node) do |hook|
38
38
  add_offense(
39
39
  node,
40
- location: :expression,
41
40
  message: format(MSG, hook: hook.source)
42
41
  )
43
42
  end
@@ -3,18 +3,22 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module RSpec
6
- # `context` block descriptions should start with 'when', or 'with'.
6
+ # Checks that `context` docstring starts with an allowed prefix.
7
7
  #
8
8
  # @see https://github.com/reachlocal/rspec-style-guide#context-descriptions
9
9
  # @see http://www.betterspecs.org/#contexts
10
10
  #
11
- # @example `Prefixes` configuration option, defaults: 'when', 'with', and
12
- # 'without'
13
- # Prefixes:
14
- # - when
15
- # - with
16
- # - without
17
- # - if
11
+ # @example `Prefixes` configuration
12
+ #
13
+ # # .rubocop.yml
14
+ # # RSpec/ContextWording:
15
+ # # Prefixes:
16
+ # # - when
17
+ # # - with
18
+ # # - without
19
+ # # - if
20
+ # # - unless
21
+ # # - for
18
22
  #
19
23
  # @example
20
24
  # # bad
@@ -35,7 +39,8 @@ module RuboCop
35
39
 
36
40
  def on_block(node)
37
41
  context_wording(node) do |context|
38
- add_offense(context, message: message)
42
+ add_offense(context,
43
+ message: format(MSG, prefixes: joined_prefixes))
39
44
  end
40
45
  end
41
46
 
@@ -45,14 +50,6 @@ module RuboCop
45
50
  !prefixes.include?(description.split.first)
46
51
  end
47
52
 
48
- def prefixes
49
- cop_config['Prefixes'] || []
50
- end
51
-
52
- def message
53
- format(MSG, prefixes: joined_prefixes)
54
- end
55
-
56
53
  def joined_prefixes
57
54
  quoted = prefixes.map { |prefix| "'#{prefix}'" }
58
55
  return quoted.first if quoted.size == 1
@@ -60,6 +57,10 @@ module RuboCop
60
57
  quoted << "or #{quoted.pop}"
61
58
  quoted.join(', ')
62
59
  end
60
+
61
+ def prefixes
62
+ cop_config['Prefixes'] || []
63
+ end
63
64
  end
64
65
  end
65
66
  end
@@ -52,7 +52,7 @@ module RuboCop
52
52
  return if pairs.any?(&method(:rails_metadata?))
53
53
  end
54
54
 
55
- add_offense(args.first, location: :expression)
55
+ add_offense(args.first)
56
56
  end
57
57
  end
58
58
  end
@@ -27,7 +27,7 @@ module RuboCop
27
27
  return unless second_arg&.str_type?
28
28
  return if second_arg.str_content.start_with?('#', '.')
29
29
 
30
- add_offense(second_arg, location: :expression)
30
+ add_offense(second_arg)
31
31
  end
32
32
  end
33
33
  end
@@ -26,7 +26,7 @@ module RuboCop
26
26
 
27
27
  def on_send(node)
28
28
  describe_symbol?(node) do |match|
29
- add_offense(match, location: :expression)
29
+ add_offense(match)
30
30
  end
31
31
  end
32
32
  end
@@ -33,7 +33,6 @@ module RuboCop
33
33
  # end
34
34
  #
35
35
  class DescribedClass < Cop
36
- include RuboCop::RSpec::TopLevelDescribe
37
36
  include ConfigurableEnforcedStyle
38
37
 
39
38
  DESCRIBED_CLASS = 'described_class'
@@ -48,20 +47,19 @@ module RuboCop
48
47
 
49
48
  def_node_matcher :scope_changing_syntax?, '{def class module}'
50
49
 
50
+ def_node_matcher :described_constant, <<-PATTERN
51
+ (block (send _ :describe $(const ...) ...) (args) $_)
52
+ PATTERN
53
+
51
54
  def on_block(node)
52
- # In case the explicit style is used, we needs to remember what's
53
- # being described. Thus, we use an ivar for @described_class.
54
- describe, @described_class, body = described_constant(node)
55
+ # In case the explicit style is used, we need to remember what's
56
+ # being described.
57
+ @described_class, body = described_constant(node)
55
58
 
56
- return if body.nil?
57
- return unless top_level_describe?(describe)
59
+ return unless body
58
60
 
59
61
  find_usage(body) do |match|
60
- add_offense(
61
- match,
62
- location: :expression,
63
- message: message(match.const_name)
64
- )
62
+ add_offense(match, message: message(match.const_name))
65
63
  end
66
64
  end
67
65
 
@@ -108,16 +106,84 @@ module RuboCop
108
106
  end
109
107
 
110
108
  def skip_blocks?
111
- cop_config['SkipBlocks'].equal?(true)
109
+ cop_config['SkipBlocks']
112
110
  end
113
111
 
114
112
  def offensive?(node)
115
113
  if style == :described_class
116
- node.eql?(@described_class)
114
+ offensive_described_class?(node)
117
115
  else
118
116
  node.send_type? && node.method_name == :described_class
119
117
  end
120
118
  end
119
+
120
+ def offensive_described_class?(node)
121
+ return unless node.const_type?
122
+
123
+ nearest_described_class, = node.each_ancestor(:block)
124
+ .map { |ancestor| described_constant(ancestor) }.find(&:itself)
125
+
126
+ return if nearest_described_class.equal?(node)
127
+
128
+ full_const_name(nearest_described_class) == full_const_name(node)
129
+ end
130
+
131
+ def full_const_name(node)
132
+ collapse_namespace(namespace(node), const_name(node))
133
+ end
134
+
135
+ # @param namespace [Array<Symbol>]
136
+ # @param const [Array<Symbol>]
137
+ # @return [Array<Symbol>]
138
+ # @example
139
+ # # nil represents base constant
140
+ # collapse_namespace([], :C) # => [:C]
141
+ # collapse_namespace([:A, :B], [:C) # => [:A, :B, :C]
142
+ # collapse_namespace([:A, :B], [:B, :C) # => [:A, :B, :C]
143
+ # collapse_namespace([:A, :B], [nil, :C) # => [nil, :C]
144
+ # collapse_namespace([:A, :B], [nil, :B, :C) # => [nil, :B, :C]
145
+ def collapse_namespace(namespace, const)
146
+ return const if namespace.empty?
147
+ return const if const.first.nil?
148
+
149
+ start = [0, (namespace.length - const.length)].max
150
+ max = namespace.length
151
+ intersection = (start..max).find do |shift|
152
+ namespace[shift, max - shift] == const[0, max - shift]
153
+ end
154
+ [*namespace[0, intersection], *const]
155
+ end
156
+
157
+ # @param node [RuboCop::AST::Node]
158
+ # @return [Array<Symbol>]
159
+ # @example
160
+ # const_name(s(:const, nil, :C)) # => [:C]
161
+ # const_name(s(:const, s(:const, nil, :M), :C)) # => [:M, :C]
162
+ # const_name(s(:const, s(:cbase), :C)) # => [nil, :C]
163
+ def const_name(node)
164
+ # rubocop:disable InternalAffairs/NodeDestructuring
165
+ namespace, name = *node
166
+ # rubocop:enable InternalAffairs/NodeDestructuring
167
+ if !namespace
168
+ [name]
169
+ elsif namespace.cbase_type?
170
+ [nil, name]
171
+ else
172
+ [*const_name(namespace), name]
173
+ end
174
+ end
175
+
176
+ # @param node [RuboCop::AST::Node]
177
+ # @return [Array<Symbol>]
178
+ # @example
179
+ # namespace(node) # => [:A, :B, :C]
180
+ def namespace(node)
181
+ node
182
+ .each_ancestor(:class, :module)
183
+ .reverse_each
184
+ .flat_map { |ancestor| ancestor.defined_module_name.split('::') }
185
+ .map(&:to_sym)
186
+ end
121
187
  end
122
188
  end
123
189
  end
@@ -70,7 +70,7 @@ module RuboCop
70
70
  def on_block(node)
71
71
  return unless example_group?(node) && !contains_example?(node)
72
72
 
73
- add_offense(node.send_node, location: :expression)
73
+ add_offense(node.send_node)
74
74
  end
75
75
 
76
76
  private
@@ -24,7 +24,7 @@ module RuboCop
24
24
  return if last_child?(node)
25
25
 
26
26
  missing_separating_line(node) do |location|
27
- add_offense(node, location: location, message: MSG)
27
+ add_offense(node, location: location)
28
28
  end
29
29
  end
30
30
 
@@ -37,7 +37,7 @@ module RuboCop
37
37
 
38
38
  return unless length > max_length
39
39
 
40
- add_offense(node, location: :expression, message: message(length))
40
+ add_offense(node, message: message(length))
41
41
  end
42
42
 
43
43
  private
@@ -36,10 +36,12 @@ module RuboCop
36
36
  SHOULD_PREFIX = /\Ashould(?:n't)?\b/i.freeze
37
37
  IT_PREFIX = /\Ait /i.freeze
38
38
 
39
- def_node_matcher(
40
- :it_description,
41
- '(block (send _ :it $(str $_) ...) ...)'
42
- )
39
+ def_node_matcher :it_description, <<-PATTERN
40
+ (block (send _ :it ${
41
+ (str $_)
42
+ (dstr (str $_ ) ...)
43
+ } ...) ...)
44
+ PATTERN
43
45
 
44
46
  def on_block(node)
45
47
  it_description(node) do |description_node, message|
@@ -45,7 +45,7 @@ module RuboCop
45
45
 
46
46
  def on_send(node)
47
47
  expect_literal(node) do |argument|
48
- add_offense(argument, location: :expression)
48
+ add_offense(argument)
49
49
  end
50
50
  end
51
51
 
@@ -21,7 +21,9 @@ module RuboCop
21
21
  def on_gvasgn(node)
22
22
  return unless inside_example_scope?(node)
23
23
 
24
+ # rubocop:disable InternalAffairs/NodeDestructuring
24
25
  variable_name, _rhs = *node
26
+ # rubocop:enable InternalAffairs/NodeDestructuring
25
27
  name = variable_name[1..-1]
26
28
  return unless name.eql?('stdout') || name.eql?('stderr')
27
29
 
@@ -40,7 +40,7 @@ module RuboCop
40
40
  next unless offensive_receiver?(attribute.receiver, node)
41
41
  next if proc?(attribute) || association?(attribute)
42
42
 
43
- add_offense(attribute, location: :expression)
43
+ add_offense(attribute)
44
44
  end
45
45
  end
46
46
 
@@ -51,8 +51,7 @@ module RuboCop
51
51
  return unless n_times_block_without_arg?(node)
52
52
  return unless contains_only_factory?(node.body)
53
53
 
54
- add_offense(node.send_node,
55
- location: :expression, message: MSG_CREATE_LIST)
54
+ add_offense(node.send_node, message: MSG_CREATE_LIST)
56
55
  end
57
56
 
58
57
  def on_send(node)