rubocop-rspec 1.33.0 → 1.34.0

Sign up to get free protection for your applications and to get access to all the features.
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)