rubocop-rspec 2.25.0 → 2.27.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +35 -0
  3. data/config/default.yml +39 -4
  4. data/lib/rubocop/cop/rspec/around_block.rb +3 -3
  5. data/lib/rubocop/cop/rspec/be.rb +1 -1
  6. data/lib/rubocop/cop/rspec/be_empty.rb +1 -0
  7. data/lib/rubocop/cop/rspec/be_eq.rb +1 -1
  8. data/lib/rubocop/cop/rspec/be_eql.rb +1 -1
  9. data/lib/rubocop/cop/rspec/be_nil.rb +2 -2
  10. data/lib/rubocop/cop/rspec/before_after_all.rb +7 -13
  11. data/lib/rubocop/cop/rspec/capybara/feature_methods.rb +2 -2
  12. data/lib/rubocop/cop/rspec/change_by_zero.rb +30 -4
  13. data/lib/rubocop/cop/rspec/context_method.rb +2 -2
  14. data/lib/rubocop/cop/rspec/context_wording.rb +1 -1
  15. data/lib/rubocop/cop/rspec/describe_symbol.rb +1 -1
  16. data/lib/rubocop/cop/rspec/described_class.rb +33 -11
  17. data/lib/rubocop/cop/rspec/empty_example_group.rb +2 -2
  18. data/lib/rubocop/cop/rspec/empty_line_after_example.rb +2 -2
  19. data/lib/rubocop/cop/rspec/example_without_description.rb +11 -2
  20. data/lib/rubocop/cop/rspec/example_wording.rb +11 -2
  21. data/lib/rubocop/cop/rspec/excessive_docstring_spacing.rb +1 -1
  22. data/lib/rubocop/cop/rspec/expect_actual.rb +5 -2
  23. data/lib/rubocop/cop/rspec/expect_change.rb +2 -2
  24. data/lib/rubocop/cop/rspec/expect_output.rb +1 -4
  25. data/lib/rubocop/cop/rspec/focus.rb +2 -2
  26. data/lib/rubocop/cop/rspec/hook_argument.rb +2 -2
  27. data/lib/rubocop/cop/rspec/hooks_before_examples.rb +1 -1
  28. data/lib/rubocop/cop/rspec/implicit_block_expectation.rb +2 -2
  29. data/lib/rubocop/cop/rspec/implicit_expect.rb +1 -1
  30. data/lib/rubocop/cop/rspec/implicit_subject.rb +2 -2
  31. data/lib/rubocop/cop/rspec/instance_spy.rb +2 -2
  32. data/lib/rubocop/cop/rspec/instance_variable.rb +2 -2
  33. data/lib/rubocop/cop/rspec/is_expected_specify.rb +45 -0
  34. data/lib/rubocop/cop/rspec/iterated_expectation.rb +3 -3
  35. data/lib/rubocop/cop/rspec/let_before_examples.rb +1 -1
  36. data/lib/rubocop/cop/rspec/let_setup.rb +1 -1
  37. data/lib/rubocop/cop/rspec/message_expectation.rb +1 -2
  38. data/lib/rubocop/cop/rspec/message_spies.rb +0 -2
  39. data/lib/rubocop/cop/rspec/mixin/skip_or_pending.rb +2 -2
  40. data/lib/rubocop/cop/rspec/multiple_expectations.rb +12 -7
  41. data/lib/rubocop/cop/rspec/pending.rb +1 -1
  42. data/lib/rubocop/cop/rspec/pending_without_reason.rb +1 -1
  43. data/lib/rubocop/cop/rspec/predicate_matcher.rb +6 -6
  44. data/lib/rubocop/cop/rspec/rails/avoid_setup_hook.rb +1 -1
  45. data/lib/rubocop/cop/rspec/rails/have_http_status.rb +34 -10
  46. data/lib/rubocop/cop/rspec/rails/http_status.rb +1 -1
  47. data/lib/rubocop/cop/rspec/rails/minitest_assertions.rb +314 -22
  48. data/lib/rubocop/cop/rspec/receive_counts.rb +1 -1
  49. data/lib/rubocop/cop/rspec/receive_messages.rb +1 -1
  50. data/lib/rubocop/cop/rspec/redundant_predicate_matcher.rb +67 -0
  51. data/lib/rubocop/cop/rspec/remove_const.rb +40 -0
  52. data/lib/rubocop/cop/rspec/repeated_example_group_body.rb +1 -1
  53. data/lib/rubocop/cop/rspec/repeated_example_group_description.rb +2 -2
  54. data/lib/rubocop/cop/rspec/repeated_include_example.rb +1 -1
  55. data/lib/rubocop/cop/rspec/repeated_subject_call.rb +124 -0
  56. data/lib/rubocop/cop/rspec/return_from_stub.rb +1 -1
  57. data/lib/rubocop/cop/rspec/shared_context.rb +1 -1
  58. data/lib/rubocop/cop/rspec/shared_examples.rb +66 -20
  59. data/lib/rubocop/cop/rspec/single_argument_message_chain.rb +2 -3
  60. data/lib/rubocop/cop/rspec/stubbed_mock.rb +1 -1
  61. data/lib/rubocop/cop/rspec/subject_stub.rb +4 -4
  62. data/lib/rubocop/cop/rspec/unspecified_exception.rb +2 -2
  63. data/lib/rubocop/cop/rspec/variable_definition.rb +2 -2
  64. data/lib/rubocop/cop/rspec/verified_doubles.rb +1 -1
  65. data/lib/rubocop/cop/rspec/void_expect.rb +2 -2
  66. data/lib/rubocop/cop/rspec_cops.rb +4 -0
  67. data/lib/rubocop/rspec/language.rb +8 -8
  68. data/lib/rubocop/rspec/version.rb +1 -1
  69. data/lib/rubocop/rspec/wording.rb +8 -0
  70. metadata +10 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: afb5cf0c88af50530fc023549eb7e9083db3ca2314553f1fca912ea2a3c47bdb
4
- data.tar.gz: ba30f926d9cd3056e786f724140ac4358af527496b2e783fcc5c8e541adc9d13
3
+ metadata.gz: 629669f9a1d9d41dae7bc62c630f3a6cdae80623d3213c8e79ac8eb207f79e59
4
+ data.tar.gz: 5005161c3684fcd8b794284bcaeedc50253a545d649be9e0e0a82958fdd125b0
5
5
  SHA512:
6
- metadata.gz: cd7955549b3b95b481eb5dea24b98f72e1b802546f8e090695a782a20b0ee8d1d0bcca9a6089f3a46718c5a14967de6c8473709ecea72d8aa5eae85e2cb5bd6f
7
- data.tar.gz: 2beb193cf65884c363c2ece1a3a7ba5db39eecc3a579724bd39f29696ab29276def06261363b6a6290d378743e0b79d414e056b65f0a8a9e2e4215a417d9b978
6
+ metadata.gz: 8af331d4b31697228397a1122cbe331223d3f040f44d2260e5148d73177df5ba08ae2aea1d481b27f698b5d59c9522d1c5f4c5e08e14b473a548de75ccf218c6
7
+ data.tar.gz: 0f86ea257bcd14e73c57b2e431f618e0959cf9dbeca6e22c4b75bd8d4945f670d8fdb65212ff12969b351b62c35f845ca28041d4b1b30627e7d64dda5932b365
data/CHANGELOG.md CHANGED
@@ -2,6 +2,35 @@
2
2
 
3
3
  ## Master (Unreleased)
4
4
 
5
+ ## 2.27.1 (2024-03-03)
6
+
7
+ - Fix a false positive for `RSpec/RepeatedSubjectCall` when `subject.method_call`. ([@ydah])
8
+ - Add configuration option `OnlyStaticConstants` to `RSpec/DescribedClass`. ([@ydah])
9
+
10
+ ## 2.27.0 (2024-03-01)
11
+
12
+ - Add new `RSpec/IsExpectedSpecify` cop. ([@ydah])
13
+ - Add new `RSpec/RepeatedSubjectCall` cop. ([@drcapulet])
14
+ - 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])
15
+ - Support asserts with messages in `Rspec/BeEmpty`. ([@G-Rath])
16
+ - Fix a false positive for `RSpec/ExpectActual` when used with rspec-rails routing matchers. ([@naveg])
17
+ - Add configuration option `ResponseMethods` to `RSpec/Rails/HaveHttpStatus`. ([@ydah])
18
+ - Fix a false negative for `RSpec/DescribedClass` when class with constant. ([@ydah])
19
+ - Fix a false positive for `RSpec/ExampleWithoutDescription` when `specify` with multi-line block and missing description. ([@ydah])
20
+ - Fix an incorrect autocorrect for `RSpec/ChangeByZero` when compound expectations with line break before `.by(0)`. ([@ydah])
21
+
22
+ ## 2.26.1 (2024-01-05)
23
+
24
+ - Fix an error for `RSpec/SharedExamples` when using examples without argument. ([@ydah])
25
+
26
+ ## 2.26.0 (2024-01-04)
27
+
28
+ - Add new `RSpec/RedundantPredicateMatcher` cop. ([@ydah])
29
+ - Add new `RSpec/RemoveConst` cop. ([@swelther])
30
+ - Add support for correcting "it will" (future tense) for `RSpec/ExampleWording`. ([@jdufresne])
31
+ - Add support for `symbol` style for `RSpec/SharedExamples`. ([@jessieay])
32
+ - Ensure `PendingWithoutReason` can detect violations inside shared groups. ([@robinaugh])
33
+
5
34
  ## 2.25.0 (2023-10-27)
6
35
 
7
36
  - Add support single quoted string and percent string and heredoc for `RSpec/Rails/HttpStatus`. ([@ydah])
@@ -833,6 +862,7 @@ Compatibility release so users can upgrade RuboCop to 0.51.0. No new features.
833
862
  [@deivid-rodriguez]: https://github.com/deivid-rodriguez
834
863
  [@dgollahon]: https://github.com/dgollahon
835
864
  [@dmitrytsepelev]: https://github.com/dmitrytsepelev
865
+ [@drcapulet]: https://github.com/drcapulet
836
866
  [@drowze]: https://github.com/Drowze
837
867
  [@dswij]: https://github.com/dswij
838
868
  [@dvandersluis]: https://github.com/dvandersluis
@@ -855,7 +885,9 @@ Compatibility release so users can upgrade RuboCop to 0.51.0. No new features.
855
885
  [@ignaciovillaverde]: https://github.com/ignaciovillaverde
856
886
  [@jaredbeck]: https://github.com/jaredbeck
857
887
  [@jaredmoody]: https://github.com/jaredmoody
888
+ [@jdufresne]: https://github.com/jdufresne
858
889
  [@jeffreyc]: https://github.com/jeffreyc
890
+ [@jessieay]: https://github.com/jessieay
859
891
  [@jfragoulis]: https://github.com/jfragoulis
860
892
  [@johnny-miyake]: https://github.com/johnny-miyake
861
893
  [@jojos003]: https://github.com/jojos003
@@ -878,6 +910,7 @@ Compatibility release so users can upgrade RuboCop to 0.51.0. No new features.
878
910
  [@mockdeep]: https://github.com/mockdeep
879
911
  [@mothonmars]: https://github.com/MothOnMars
880
912
  [@mvz]: https://github.com/mvz
913
+ [@naveg]: https://github.com/naveg
881
914
  [@nc-holodakg]: https://github.com/nc-holodakg
882
915
  [@nevir]: https://github.com/nevir
883
916
  [@ngouy]: https://github.com/ngouy
@@ -897,6 +930,7 @@ Compatibility release so users can upgrade RuboCop to 0.51.0. No new features.
897
930
  [@rafix02]: https://github.com/Rafix02
898
931
  [@redross]: https://github.com/redross
899
932
  [@renanborgescampos]: https://github.com/renanborgescampos
933
+ [@robinaugh]: https://github.com/robinaugh
900
934
  [@robotdana]: https://github.com/robotdana
901
935
  [@rolfschmidt]: https://github.com/rolfschmidt
902
936
  [@rrosenblum]: https://github.com/rrosenblum
@@ -909,6 +943,7 @@ Compatibility release so users can upgrade RuboCop to 0.51.0. No new features.
909
943
  [@smcgivern]: https://github.com/smcgivern
910
944
  [@splattael]: https://github.com/splattael
911
945
  [@stephannv]: https://github.com/stephannv
946
+ [@swelther]: https://github.com/swelther
912
947
  [@t3h2mas]: https://github.com/t3h2mas
913
948
  [@tdeo]: https://github.com/tdeo
914
949
  [@tejasbubane]: https://github.com/tejasbubane
data/config/default.yml CHANGED
@@ -178,7 +178,7 @@ RSpec/BeNil:
178
178
  Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/BeNil
179
179
 
180
180
  RSpec/BeforeAfterAll:
181
- Description: Check that before/after(:all) isn't being used.
181
+ Description: Check that before/after(:all/:context) isn't being used.
182
182
  Enabled: true
183
183
  Exclude:
184
184
  - "**/spec/spec_helper.rb"
@@ -283,9 +283,10 @@ RSpec/DescribedClass:
283
283
  SupportedStyles:
284
284
  - described_class
285
285
  - explicit
286
+ OnlyStaticConstants: true
286
287
  SafeAutoCorrect: false
287
288
  VersionAdded: '1.0'
288
- VersionChanged: '1.11'
289
+ VersionChanged: '2.27'
289
290
  Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/DescribedClass
290
291
 
291
292
  RSpec/DescribedClassModuleWrapping:
@@ -548,6 +549,13 @@ RSpec/InstanceVariable:
548
549
  StyleGuide: https://rspec.rubystyle.guide/#instance-variables
549
550
  Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/InstanceVariable
550
551
 
552
+ RSpec/IsExpectedSpecify:
553
+ Description: Check for `specify` with `is_expected` and one-liner expectations.
554
+ Enabled: pending
555
+ VersionAdded: '2.27'
556
+ StyleGuide: https://rspec.rubystyle.guide/#it-and-specify
557
+ Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/IsExpectedSpecify
558
+
551
559
  RSpec/ItBehavesLike:
552
560
  Description: Checks that only one `it_behaves_like` style is used.
553
561
  Enabled: true
@@ -771,6 +779,18 @@ RSpec/RedundantAround:
771
779
  VersionAdded: '2.19'
772
780
  Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/RedundantAround
773
781
 
782
+ RSpec/RedundantPredicateMatcher:
783
+ Description: Checks for redundant predicate matcher.
784
+ Enabled: pending
785
+ VersionAdded: '2.26'
786
+ Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/RedundantPredicateMatcher
787
+
788
+ RSpec/RemoveConst:
789
+ Description: Checks that `remove_const` is not used in specs.
790
+ Enabled: pending
791
+ VersionAdded: '2.26'
792
+ Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/RemoveConst
793
+
774
794
  RSpec/RepeatedDescription:
775
795
  Description: Check for repeated description strings in example groups.
776
796
  Enabled: true
@@ -801,6 +821,12 @@ RSpec/RepeatedIncludeExample:
801
821
  VersionAdded: '1.44'
802
822
  Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/RepeatedIncludeExample
803
823
 
824
+ RSpec/RepeatedSubjectCall:
825
+ Description: Checks for repeated calls to subject missing that it is memoized.
826
+ Enabled: pending
827
+ VersionAdded: '2.27'
828
+ Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/RepeatedSubjectCall
829
+
804
830
  RSpec/ReturnFromStub:
805
831
  Description: Checks for consistent style of stub's return setting.
806
832
  Enabled: true
@@ -832,9 +858,14 @@ RSpec/SharedContext:
832
858
  Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/SharedContext
833
859
 
834
860
  RSpec/SharedExamples:
835
- Description: Enforces use of string to titleize shared examples.
861
+ Description: Checks for consistent style for shared example names.
836
862
  Enabled: true
863
+ EnforcedStyle: string
864
+ SupportedStyles:
865
+ - string
866
+ - symbol
837
867
  VersionAdded: '1.25'
868
+ VersionChanged: '2.26'
838
869
  Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/SharedExamples
839
870
 
840
871
  RSpec/SingleArgumentMessageChain:
@@ -1109,8 +1140,12 @@ RSpec/Rails/AvoidSetupHook:
1109
1140
  RSpec/Rails/HaveHttpStatus:
1110
1141
  Description: Checks that tests use `have_http_status` instead of equality matchers.
1111
1142
  Enabled: pending
1143
+ ResponseMethods:
1144
+ - response
1145
+ - last_response
1112
1146
  SafeAutoCorrect: false
1113
1147
  VersionAdded: '2.12'
1148
+ VersionChanged: '2.27'
1114
1149
  Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Rails/HaveHttpStatus
1115
1150
 
1116
1151
  RSpec/Rails/HttpStatus:
@@ -1149,7 +1184,7 @@ RSpec/Rails/InferredSpecType:
1149
1184
  views: view
1150
1185
 
1151
1186
  RSpec/Rails/MinitestAssertions:
1152
- Description: Check if using Minitest matchers.
1187
+ Description: Check if using Minitest-like matchers.
1153
1188
  Enabled: pending
1154
1189
  VersionAdded: '2.17'
1155
1190
  Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Rails/MinitestAssertions
@@ -32,17 +32,17 @@ module RuboCop
32
32
  'or `%<arg>s.run`.'
33
33
 
34
34
  # @!method hook_block(node)
35
- def_node_matcher :hook_block, <<-PATTERN
35
+ def_node_matcher :hook_block, <<~PATTERN
36
36
  (block (send nil? :around sym ?) (args $...) ...)
37
37
  PATTERN
38
38
 
39
39
  # @!method hook_numblock(node)
40
- def_node_matcher :hook_numblock, <<-PATTERN
40
+ def_node_matcher :hook_numblock, <<~PATTERN
41
41
  (numblock (send nil? :around sym ?) ...)
42
42
  PATTERN
43
43
 
44
44
  # @!method find_arg_usage(node)
45
- def_node_search :find_arg_usage, <<-PATTERN
45
+ def_node_search :find_arg_usage, <<~PATTERN
46
46
  {(send $... {:call :run}) (send _ _ $...) (yield $...) (block-pass $...)}
47
47
  PATTERN
48
48
 
@@ -24,7 +24,7 @@ module RuboCop
24
24
  RESTRICT_ON_SEND = Runners.all
25
25
 
26
26
  # @!method be_without_args(node)
27
- def_node_matcher :be_without_args, <<-PATTERN
27
+ def_node_matcher :be_without_args, <<~PATTERN
28
28
  (send _ #Runners.all $(send nil? :be))
29
29
  PATTERN
30
30
 
@@ -28,6 +28,7 @@ module RuboCop
28
28
  (send nil? :match_array (array))
29
29
  (send nil? :contain_exactly)
30
30
  }
31
+ _?
31
32
  )
32
33
  PATTERN
33
34
 
@@ -30,7 +30,7 @@ module RuboCop
30
30
  RESTRICT_ON_SEND = %i[eq].freeze
31
31
 
32
32
  # @!method eq_type_with_identity?(node)
33
- def_node_matcher :eq_type_with_identity?, <<-PATTERN
33
+ def_node_matcher :eq_type_with_identity?, <<~PATTERN
34
34
  (send nil? :eq {true false nil})
35
35
  PATTERN
36
36
 
@@ -44,7 +44,7 @@ module RuboCop
44
44
  RESTRICT_ON_SEND = %i[to].freeze
45
45
 
46
46
  # @!method eql_type_with_identity(node)
47
- def_node_matcher :eql_type_with_identity, <<-PATTERN
47
+ def_node_matcher :eql_type_with_identity, <<~PATTERN
48
48
  (send _ :to $(send nil? :eql {true false int float sym nil}))
49
49
  PATTERN
50
50
 
@@ -33,12 +33,12 @@ module RuboCop
33
33
  RESTRICT_ON_SEND = %i[be be_nil].freeze
34
34
 
35
35
  # @!method be_nil_matcher?(node)
36
- def_node_matcher :be_nil_matcher?, <<-PATTERN
36
+ def_node_matcher :be_nil_matcher?, <<~PATTERN
37
37
  (send nil? :be_nil)
38
38
  PATTERN
39
39
 
40
40
  # @!method nil_value_expectation?(node)
41
- def_node_matcher :nil_value_expectation?, <<-PATTERN
41
+ def_node_matcher :nil_value_expectation?, <<~PATTERN
42
42
  (send nil? :be nil)
43
43
  PATTERN
44
44
 
@@ -3,22 +3,16 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module RSpec
6
- # Check that before/after(:all) isn't being used.
6
+ # Check that before/after(:all/:context) isn't being used.
7
7
  #
8
8
  # @example
9
- # # bad
10
- # #
11
- # # Faster but risk of state leaking between examples
12
- # #
9
+ # # bad - Faster but risk of state leaking between examples
13
10
  # describe MyClass do
14
11
  # before(:all) { Widget.create }
15
- # after(:all) { Widget.delete_all }
12
+ # after(:context) { Widget.delete_all }
16
13
  # end
17
14
  #
18
- # # good
19
- # #
20
- # # Slower but examples are properly isolated
21
- # #
15
+ # # good - Slower but examples are properly isolated
22
16
  # describe MyClass do
23
17
  # before(:each) { Widget.create }
24
18
  # after(:each) { Widget.delete_all }
@@ -30,11 +24,11 @@ module RuboCop
30
24
  '`use_transactional_fixtures` is enabled, then records created ' \
31
25
  'in `%<hook>s` are not automatically rolled back.'
32
26
 
33
- RESTRICT_ON_SEND = %i[before after].freeze
27
+ RESTRICT_ON_SEND = Set[:before, :after].freeze
34
28
 
35
29
  # @!method before_or_after_all(node)
36
- def_node_matcher :before_or_after_all, <<-PATTERN
37
- $(send _ {:before :after} (sym {:all :context}))
30
+ def_node_matcher :before_or_after_all, <<~PATTERN
31
+ $(send _ RESTRICT_ON_SEND (sym {:all :context}))
38
32
  PATTERN
39
33
 
40
34
  def on_send(node)
@@ -58,12 +58,12 @@ module RuboCop
58
58
  }.freeze
59
59
 
60
60
  # @!method capybara_speak(node)
61
- def_node_matcher :capybara_speak, <<-PATTERN
61
+ def_node_matcher :capybara_speak, <<~PATTERN
62
62
  {#{MAP.keys.map(&:inspect).join(' ')}}
63
63
  PATTERN
64
64
 
65
65
  # @!method feature_method(node)
66
- def_node_matcher :feature_method, <<-PATTERN
66
+ def_node_matcher :feature_method, <<~PATTERN
67
67
  (block
68
68
  $(send #rspec? $#capybara_speak ...)
69
69
  ...)
@@ -59,6 +59,8 @@ module RuboCop
59
59
  #
60
60
  class ChangeByZero < Base
61
61
  extend AutoCorrector
62
+ include RangeHelp
63
+
62
64
  MSG = 'Prefer `not_to change` over `to %<method>s.by(0)`.'
63
65
  MSG_COMPOUND = 'Prefer %<preferred>s with compound expectations ' \
64
66
  'over `%<method>s.by(0)`.'
@@ -66,14 +68,14 @@ module RuboCop
66
68
  RESTRICT_ON_SEND = CHANGE_METHODS.freeze
67
69
 
68
70
  # @!method expect_change_with_arguments(node)
69
- def_node_matcher :expect_change_with_arguments, <<-PATTERN
71
+ def_node_matcher :expect_change_with_arguments, <<~PATTERN
70
72
  (send
71
73
  $(send nil? CHANGE_METHODS ...) :by
72
74
  (int 0))
73
75
  PATTERN
74
76
 
75
77
  # @!method expect_change_with_block(node)
76
- def_node_matcher :expect_change_with_block, <<-PATTERN
78
+ def_node_matcher :expect_change_with_block, <<~PATTERN
77
79
  (send
78
80
  (block
79
81
  $(send nil? CHANGE_METHODS)
@@ -83,7 +85,7 @@ module RuboCop
83
85
  PATTERN
84
86
 
85
87
  # @!method change_nodes(node)
86
- def_node_search :change_nodes, <<-PATTERN
88
+ def_node_search :change_nodes, <<~PATTERN
87
89
  $(send nil? CHANGE_METHODS ...)
88
90
  PATTERN
89
91
 
@@ -140,8 +142,32 @@ module RuboCop
140
142
 
141
143
  change_nodes(node) do |change_node|
142
144
  corrector.replace(change_node.loc.selector, negated_matcher)
143
- range = node.loc.dot.with(end_pos: node.source_range.end_pos)
145
+ insert_operator(corrector, node, change_node)
146
+ remove_by_zero(corrector, node, change_node)
147
+ end
148
+ end
149
+
150
+ def insert_operator(corrector, node, change_node)
151
+ operator = node.right_siblings.first
152
+ return unless %i[& |].include?(operator)
153
+
154
+ corrector.insert_after(
155
+ replace_node(node, change_node), " #{operator}"
156
+ )
157
+ end
158
+
159
+ def replace_node(node, change_node)
160
+ expect_change_with_arguments(node) ? change_node : change_node.parent
161
+ end
162
+
163
+ def remove_by_zero(corrector, node, change_node)
164
+ range = node.loc.dot.with(end_pos: node.source_range.end_pos)
165
+ if change_node.loc.line == range.line
144
166
  corrector.remove(range)
167
+ else
168
+ corrector.remove(
169
+ range_by_whole_lines(range, include_final_newline: true)
170
+ )
145
171
  end
146
172
  end
147
173
 
@@ -30,7 +30,7 @@ module RuboCop
30
30
  MSG = 'Use `describe` for testing methods.'
31
31
 
32
32
  # @!method context_method(node)
33
- def_node_matcher :context_method, <<-PATTERN
33
+ def_node_matcher :context_method, <<~PATTERN
34
34
  (block
35
35
  (send #rspec? :context
36
36
  ${(str #method_name?) (dstr (str #method_name?) ...)}
@@ -38,7 +38,7 @@ module RuboCop
38
38
  ...)
39
39
  PATTERN
40
40
 
41
- def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
41
+ def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
42
42
  context_method(node) do |context|
43
43
  add_offense(context) do |corrector|
44
44
  corrector.replace(node.send_node.loc.selector, 'describe')
@@ -61,7 +61,7 @@ module RuboCop
61
61
  MSG = 'Context description should match %<patterns>s.'
62
62
 
63
63
  # @!method context_wording(node)
64
- def_node_matcher :context_wording, <<-PATTERN
64
+ def_node_matcher :context_wording, <<~PATTERN
65
65
  (block (send #rspec? { :context :shared_context } $({str dstr xstr} ...) ...) ...)
66
66
  PATTERN
67
67
 
@@ -22,7 +22,7 @@ module RuboCop
22
22
  RESTRICT_ON_SEND = %i[describe].freeze
23
23
 
24
24
  # @!method describe_symbol?(node)
25
- def_node_matcher :describe_symbol?, <<-PATTERN
25
+ def_node_matcher :describe_symbol?, <<~PATTERN
26
26
  (send #rspec? :describe $sym ...)
27
27
  PATTERN
28
28
 
@@ -8,8 +8,10 @@ module RuboCop
8
8
  # If the first argument of describe is a class, the class is exposed to
9
9
  # each example via described_class.
10
10
  #
11
- # This cop can be configured using the `EnforcedStyle` and `SkipBlocks`
12
- # options.
11
+ # This cop can be configured using the `EnforcedStyle`, `SkipBlocks`
12
+ # and `OnlyStaticConstants` options.
13
+ # `OnlyStaticConstants` is only relevant when `EnforcedStyle` is
14
+ # `described_class`.
13
15
  #
14
16
  # @example `EnforcedStyle: described_class` (default)
15
17
  # # bad
@@ -22,6 +24,18 @@ module RuboCop
22
24
  # subject { described_class.do_something }
23
25
  # end
24
26
  #
27
+ # @example `OnlyStaticConstants: true` (default)
28
+ # # good
29
+ # describe MyClass do
30
+ # subject { MyClass::CONSTANT }
31
+ # end
32
+ #
33
+ # @example `OnlyStaticConstants: false`
34
+ # # bad
35
+ # describe MyClass do
36
+ # subject { MyClass::CONSTANT }
37
+ # end
38
+ #
25
39
  # @example `EnforcedStyle: explicit`
26
40
  # # bad
27
41
  # describe MyClass do
@@ -54,7 +68,7 @@ module RuboCop
54
68
  # end
55
69
  # end
56
70
  #
57
- class DescribedClass < Base
71
+ class DescribedClass < Base # rubocop:disable Metrics/ClassLength
58
72
  extend AutoCorrector
59
73
  include ConfigurableEnforcedStyle
60
74
  include Namespace
@@ -63,7 +77,7 @@ module RuboCop
63
77
  MSG = 'Use `%<replacement>s` instead of `%<src>s`.'
64
78
 
65
79
  # @!method common_instance_exec_closure?(node)
66
- def_node_matcher :common_instance_exec_closure?, <<-PATTERN
80
+ def_node_matcher :common_instance_exec_closure?, <<~PATTERN
67
81
  (block (send (const nil? {:Class :Module :Struct}) :new ...) ...)
68
82
  PATTERN
69
83
 
@@ -75,7 +89,7 @@ module RuboCop
75
89
  def_node_matcher :scope_changing_syntax?, '{def class module}'
76
90
 
77
91
  # @!method described_constant(node)
78
- def_node_matcher :described_constant, <<-PATTERN
92
+ def_node_matcher :described_constant, <<~PATTERN
79
93
  (block (send _ :describe $(const ...) ...) (args) $_)
80
94
  PATTERN
81
95
 
@@ -112,14 +126,17 @@ module RuboCop
112
126
 
113
127
  def find_usage(node, &block)
114
128
  yield(node) if offensive?(node)
115
-
116
- return if scope_change?(node) || node.const_type?
129
+ return if scope_change?(node) || allowed?(node)
117
130
 
118
131
  node.each_child_node do |child|
119
132
  find_usage(child, &block)
120
133
  end
121
134
  end
122
135
 
136
+ def allowed?(node)
137
+ node.const_type? && only_static_constants?
138
+ end
139
+
123
140
  def message(offense)
124
141
  if style == :described_class
125
142
  format(MSG, replacement: DESCRIBED_CLASS, src: offense)
@@ -139,6 +156,10 @@ module RuboCop
139
156
  node.block_type? && !rspec_block?(node) && cop_config['SkipBlocks']
140
157
  end
141
158
 
159
+ def only_static_constants?
160
+ cop_config.fetch('OnlyStaticConstants', true)
161
+ end
162
+
142
163
  def offensive?(node)
143
164
  if style == :described_class
144
165
  offensive_described_class?(node)
@@ -148,15 +169,15 @@ module RuboCop
148
169
  end
149
170
 
150
171
  def offensive_described_class?(node)
151
- return unless node.const_type?
172
+ return false unless node.const_type?
152
173
 
153
174
  # E.g. `described_class::CONSTANT`
154
- return if contains_described_class?(node)
175
+ return false if contains_described_class?(node)
155
176
 
156
177
  nearest_described_class, = node.each_ancestor(:block)
157
178
  .map { |ancestor| described_constant(ancestor) }.find(&:itself)
158
179
 
159
- return if nearest_described_class.equal?(node)
180
+ return false if nearest_described_class.equal?(node)
160
181
 
161
182
  full_const_name(nearest_described_class) == full_const_name(node)
162
183
  end
@@ -194,7 +215,8 @@ module RuboCop
194
215
  # const_name(s(:const, s(:const, nil, :M), :C)) # => [:M, :C]
195
216
  # const_name(s(:const, s(:cbase), :C)) # => [nil, :C]
196
217
  def const_name(node)
197
- namespace, name = *node # rubocop:disable InternalAffairs/NodeDestructuring
218
+ namespace = node.namespace
219
+ name = node.short_name
198
220
  if !namespace
199
221
  [name]
200
222
  elsif namespace.const_type?
@@ -162,7 +162,7 @@ module RuboCop
162
162
  end
163
163
 
164
164
  def conditionals_with_examples?(body)
165
- return unless body.begin_type? || body.case_type?
165
+ return false unless body.begin_type? || body.case_type?
166
166
 
167
167
  body.each_descendant(:if, :case).any? do |condition_node|
168
168
  examples_in_branches?(condition_node)
@@ -170,7 +170,7 @@ module RuboCop
170
170
  end
171
171
 
172
172
  def examples_in_branches?(condition_node)
173
- return if !condition_node.if_type? && !condition_node.case_type?
173
+ return false if !condition_node.if_type? && !condition_node.case_type?
174
174
 
175
175
  condition_node.branches.any? { |branch| examples?(branch) }
176
176
  end
@@ -71,8 +71,8 @@ module RuboCop
71
71
 
72
72
  def next_one_line_example?(node)
73
73
  next_sibling = node.right_sibling
74
- return unless next_sibling
75
- return unless example?(next_sibling)
74
+ return false unless next_sibling
75
+ return false unless example?(next_sibling)
76
76
 
77
77
  next_sibling.single_line?
78
78
  end
@@ -7,6 +7,7 @@ module RuboCop
7
7
  #
8
8
  # RSpec allows for auto-generated example descriptions when there is no
9
9
  # description provided or the description is an empty one.
10
+ # It is acceptable to use `specify` without a description
10
11
  #
11
12
  # This cop removes empty descriptions.
12
13
  # It also defines whether auto-generated description is allowed, based
@@ -14,17 +15,24 @@ module RuboCop
14
15
  #
15
16
  # This cop can be configured using the `EnforcedStyle` option
16
17
  #
18
+ # @example
19
+ # # always good
20
+ # specify do
21
+ # result = service.call
22
+ # expect(result).to be(true)
23
+ # end
24
+ #
17
25
  # @example `EnforcedStyle: always_allow` (default)
18
26
  # # bad
19
27
  # it('') { is_expected.to be_good }
20
- # it '' do
28
+ # specify '' do
21
29
  # result = service.call
22
30
  # expect(result).to be(true)
23
31
  # end
24
32
  #
25
33
  # # good
26
34
  # it { is_expected.to be_good }
27
- # it do
35
+ # specify do
28
36
  # result = service.call
29
37
  # expect(result).to be(true)
30
38
  # end
@@ -75,6 +83,7 @@ module RuboCop
75
83
  def check_example_without_description(node)
76
84
  return if node.arguments?
77
85
  return unless disallow_empty_description?(node)
86
+ return if node.method?(:specify) && node.parent.multiline?
78
87
 
79
88
  add_offense(node, message: MSG_ADD_DESCRIPTION)
80
89
  end