rubocop-rspec 2.12.1 → 2.13.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 +4 -4
- data/CHANGELOG.md +110 -86
- data/config/default.yml +44 -6
- data/lib/rubocop/cop/rspec/align_left_let_brace.rb +8 -9
- data/lib/rubocop/cop/rspec/align_right_let_brace.rb +8 -9
- data/lib/rubocop/cop/rspec/any_instance.rb +1 -0
- data/lib/rubocop/cop/rspec/around_block.rb +26 -3
- data/lib/rubocop/cop/rspec/be.rb +0 -1
- data/lib/rubocop/cop/rspec/be_eq.rb +0 -1
- data/lib/rubocop/cop/rspec/be_eql.rb +0 -1
- data/lib/rubocop/cop/rspec/before_after_all.rb +1 -0
- data/lib/rubocop/cop/rspec/capybara/current_path_expectation.rb +9 -3
- data/lib/rubocop/cop/rspec/capybara/feature_methods.rb +2 -1
- data/lib/rubocop/cop/rspec/capybara/specific_finders.rb +86 -0
- data/lib/rubocop/cop/rspec/capybara/specific_matcher.rb +91 -10
- data/lib/rubocop/cop/rspec/capybara/visibility_matcher.rb +0 -1
- data/lib/rubocop/cop/rspec/change_by_zero.rb +60 -5
- data/lib/rubocop/cop/rspec/class_check.rb +101 -0
- data/lib/rubocop/cop/rspec/context_method.rb +2 -1
- data/lib/rubocop/cop/rspec/context_wording.rb +49 -18
- data/lib/rubocop/cop/rspec/describe_class.rb +1 -1
- data/lib/rubocop/cop/rspec/describe_method.rb +1 -0
- data/lib/rubocop/cop/rspec/described_class.rb +4 -14
- data/lib/rubocop/cop/rspec/dialect.rb +1 -0
- data/lib/rubocop/cop/rspec/empty_example_group.rb +19 -4
- data/lib/rubocop/cop/rspec/empty_hook.rb +2 -1
- data/lib/rubocop/cop/rspec/empty_line_after_example.rb +4 -9
- data/lib/rubocop/cop/rspec/empty_line_after_example_group.rb +1 -1
- data/lib/rubocop/cop/rspec/empty_line_after_final_let.rb +2 -1
- data/lib/rubocop/cop/rspec/empty_line_after_hook.rb +32 -2
- data/lib/rubocop/cop/rspec/empty_line_after_subject.rb +2 -1
- data/lib/rubocop/cop/rspec/example_length.rb +2 -1
- data/lib/rubocop/cop/rspec/example_without_description.rb +2 -1
- data/lib/rubocop/cop/rspec/example_wording.rb +2 -1
- data/lib/rubocop/cop/rspec/excessive_docstring_spacing.rb +1 -0
- data/lib/rubocop/cop/rspec/expect_actual.rb +3 -0
- data/lib/rubocop/cop/rspec/expect_change.rb +1 -1
- data/lib/rubocop/cop/rspec/expect_in_hook.rb +4 -1
- data/lib/rubocop/cop/rspec/expect_output.rb +1 -0
- data/lib/rubocop/cop/rspec/factory_bot/attribute_defined_statically.rb +2 -1
- data/lib/rubocop/cop/rspec/factory_bot/create_list.rb +26 -12
- data/lib/rubocop/cop/rspec/factory_bot/factory_class_name.rb +1 -0
- data/lib/rubocop/cop/rspec/file_path.rb +6 -3
- data/lib/rubocop/cop/rspec/focus.rb +18 -0
- data/lib/rubocop/cop/rspec/hook_argument.rb +7 -2
- data/lib/rubocop/cop/rspec/hooks_before_examples.rb +10 -9
- data/lib/rubocop/cop/rspec/identical_equality_assertion.rb +0 -1
- data/lib/rubocop/cop/rspec/implicit_block_expectation.rb +1 -0
- data/lib/rubocop/cop/rspec/implicit_expect.rb +0 -2
- data/lib/rubocop/cop/rspec/instance_spy.rb +1 -1
- data/lib/rubocop/cop/rspec/instance_variable.rb +0 -1
- data/lib/rubocop/cop/rspec/it_behaves_like.rb +1 -0
- data/lib/rubocop/cop/rspec/iterated_expectation.rb +16 -0
- data/lib/rubocop/cop/rspec/leading_subject.rb +15 -15
- data/lib/rubocop/cop/rspec/let_before_examples.rb +7 -8
- data/lib/rubocop/cop/rspec/let_setup.rb +4 -4
- data/lib/rubocop/cop/rspec/message_chain.rb +1 -1
- data/lib/rubocop/cop/rspec/missing_example_group_argument.rb +2 -1
- data/lib/rubocop/cop/rspec/mixin/css_selector.rb +99 -0
- data/lib/rubocop/cop/rspec/mixin/namespace.rb +23 -0
- data/lib/rubocop/cop/rspec/multiple_describes.rb +1 -0
- data/lib/rubocop/cop/rspec/multiple_expectations.rb +1 -5
- data/lib/rubocop/cop/rspec/multiple_memoized_helpers.rb +1 -3
- data/lib/rubocop/cop/rspec/multiple_subjects.rb +17 -2
- data/lib/rubocop/cop/rspec/named_subject.rb +2 -1
- data/lib/rubocop/cop/rspec/nested_groups.rb +45 -25
- data/lib/rubocop/cop/rspec/no_expectation_example.rb +64 -0
- data/lib/rubocop/cop/rspec/not_to_not.rb +1 -2
- data/lib/rubocop/cop/rspec/overwriting_setup.rb +2 -1
- data/lib/rubocop/cop/rspec/pending.rb +1 -0
- data/lib/rubocop/cop/rspec/predicate_matcher.rb +2 -1
- data/lib/rubocop/cop/rspec/rails/avoid_setup_hook.rb +1 -2
- data/lib/rubocop/cop/rspec/receive_counts.rb +14 -15
- data/lib/rubocop/cop/rspec/receive_never.rb +4 -5
- data/lib/rubocop/cop/rspec/repeated_description.rb +25 -26
- data/lib/rubocop/cop/rspec/repeated_example.rb +1 -1
- data/lib/rubocop/cop/rspec/repeated_example_group_body.rb +28 -29
- data/lib/rubocop/cop/rspec/repeated_example_group_description.rb +28 -29
- data/lib/rubocop/cop/rspec/repeated_include_example.rb +32 -33
- data/lib/rubocop/cop/rspec/return_from_stub.rb +1 -1
- data/lib/rubocop/cop/rspec/scattered_let.rb +1 -5
- data/lib/rubocop/cop/rspec/scattered_setup.rb +1 -1
- data/lib/rubocop/cop/rspec/shared_context.rb +1 -1
- data/lib/rubocop/cop/rspec/stubbed_mock.rb +0 -1
- data/lib/rubocop/cop/rspec/subject_declaration.rb +0 -1
- data/lib/rubocop/cop/rspec/subject_stub.rb +2 -2
- data/lib/rubocop/cop/rspec/unspecified_exception.rb +15 -15
- data/lib/rubocop/cop/rspec/variable_definition.rb +1 -0
- data/lib/rubocop/cop/rspec/variable_name.rb +6 -7
- data/lib/rubocop/cop/rspec/verified_doubles.rb +1 -0
- data/lib/rubocop/cop/rspec/void_expect.rb +2 -1
- data/lib/rubocop/cop/rspec/yield.rb +2 -1
- data/lib/rubocop/cop/rspec_cops.rb +3 -0
- data/lib/rubocop/rspec/config_formatter.rb +14 -3
- data/lib/rubocop/rspec/inject.rb +1 -3
- data/lib/rubocop/rspec/language/node_pattern.rb +4 -0
- data/lib/rubocop/rspec/language.rb +6 -1
- data/lib/rubocop/rspec/version.rb +1 -1
- data/lib/rubocop/rspec/wording.rb +2 -2
- data/lib/rubocop/rspec.rb +14 -0
- data/lib/rubocop-rspec.rb +3 -0
- metadata +10 -88
| @@ -16,13 +16,14 @@ module RuboCop | |
| 16 16 | 
             
                  #   let(:something) { other }
         | 
| 17 17 | 
             
                  #
         | 
| 18 18 | 
             
                  #   it { does_something }
         | 
| 19 | 
            +
                  #
         | 
| 19 20 | 
             
                  class EmptyLineAfterFinalLet < Base
         | 
| 20 21 | 
             
                    extend AutoCorrector
         | 
| 21 22 | 
             
                    include EmptyLineSeparation
         | 
| 22 23 |  | 
| 23 24 | 
             
                    MSG = 'Add an empty line after the last `%<let>s`.'
         | 
| 24 25 |  | 
| 25 | 
            -
                    def on_block(node)
         | 
| 26 | 
            +
                    def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
         | 
| 26 27 | 
             
                      return unless example_group_with_body?(node)
         | 
| 27 28 |  | 
| 28 29 | 
             
                      final_let = node.body.child_nodes.reverse.find { |child| let?(child) }
         | 
| @@ -5,6 +5,9 @@ module RuboCop | |
| 5 5 | 
             
                module RSpec
         | 
| 6 6 | 
             
                  # Checks if there is an empty line after hook blocks.
         | 
| 7 7 | 
             
                  #
         | 
| 8 | 
            +
                  # `AllowConsecutiveOneLiners` configures whether adjacent
         | 
| 9 | 
            +
                  # one-line definitions are considered an offense.
         | 
| 10 | 
            +
                  #
         | 
| 8 11 | 
             
                  # @example
         | 
| 9 12 | 
             
                  #   # bad
         | 
| 10 13 | 
             
                  #   before { do_something }
         | 
| @@ -19,11 +22,23 @@ module RuboCop | |
| 19 22 | 
             
                  #   it { does_something }
         | 
| 20 23 | 
             
                  #
         | 
| 21 24 | 
             
                  #   # good
         | 
| 22 | 
            -
                  #    | 
| 25 | 
            +
                  #   after { do_something }
         | 
| 23 26 | 
             
                  #
         | 
| 24 27 | 
             
                  #   it { does_something }
         | 
| 25 28 | 
             
                  #
         | 
| 26 | 
            -
                  #   #  | 
| 29 | 
            +
                  #   # fair - it's ok to have non-separated one-liners hooks
         | 
| 30 | 
            +
                  #   around { |test| test.run }
         | 
| 31 | 
            +
                  #   after { do_something }
         | 
| 32 | 
            +
                  #
         | 
| 33 | 
            +
                  #   it { does_something }
         | 
| 34 | 
            +
                  #
         | 
| 35 | 
            +
                  # @example with AllowConsecutiveOneLiners configuration
         | 
| 36 | 
            +
                  #   # rubocop.yml
         | 
| 37 | 
            +
                  #   # RSpec/EmptyLineAfterHook:
         | 
| 38 | 
            +
                  #   #   AllowConsecutiveOneLiners: false
         | 
| 39 | 
            +
                  #
         | 
| 40 | 
            +
                  #   # bad
         | 
| 41 | 
            +
                  #   around { |test| test.run }
         | 
| 27 42 | 
             
                  #   after { do_something }
         | 
| 28 43 | 
             
                  #
         | 
| 29 44 | 
             
                  #   it { does_something }
         | 
| @@ -31,21 +46,36 @@ module RuboCop | |
| 31 46 | 
             
                  #   # good
         | 
| 32 47 | 
             
                  #   around { |test| test.run }
         | 
| 33 48 | 
             
                  #
         | 
| 49 | 
            +
                  #   after { do_something }
         | 
| 50 | 
            +
                  #
         | 
| 34 51 | 
             
                  #   it { does_something }
         | 
| 35 52 | 
             
                  #
         | 
| 36 53 | 
             
                  class EmptyLineAfterHook < Base
         | 
| 37 54 | 
             
                    extend AutoCorrector
         | 
| 55 | 
            +
                    include ConfigurableEnforcedStyle
         | 
| 38 56 | 
             
                    include EmptyLineSeparation
         | 
| 39 57 |  | 
| 40 58 | 
             
                    MSG = 'Add an empty line after `%<hook>s`.'
         | 
| 41 59 |  | 
| 42 60 | 
             
                    def on_block(node)
         | 
| 43 61 | 
             
                      return unless hook?(node)
         | 
| 62 | 
            +
                      return if cop_config['AllowConsecutiveOneLiners'] &&
         | 
| 63 | 
            +
                        chained_single_line_hooks?(node)
         | 
| 44 64 |  | 
| 45 65 | 
             
                      missing_separating_line_offense(node) do |method|
         | 
| 46 66 | 
             
                        format(MSG, hook: method)
         | 
| 47 67 | 
             
                      end
         | 
| 48 68 | 
             
                    end
         | 
| 69 | 
            +
             | 
| 70 | 
            +
                    alias on_numblock on_block
         | 
| 71 | 
            +
             | 
| 72 | 
            +
                    private
         | 
| 73 | 
            +
             | 
| 74 | 
            +
                    def chained_single_line_hooks?(node)
         | 
| 75 | 
            +
                      next_node = node.right_sibling
         | 
| 76 | 
            +
             | 
| 77 | 
            +
                      hook?(next_node) && node.single_line? && next_node.single_line?
         | 
| 78 | 
            +
                    end
         | 
| 49 79 | 
             
                  end
         | 
| 50 80 | 
             
                end
         | 
| 51 81 | 
             
              end
         | 
| @@ -14,6 +14,7 @@ module RuboCop | |
| 14 14 | 
             
                  #   subject(:obj) { described_class }
         | 
| 15 15 | 
             
                  #
         | 
| 16 16 | 
             
                  #   let(:foo) { bar }
         | 
| 17 | 
            +
                  #
         | 
| 17 18 | 
             
                  class EmptyLineAfterSubject < Base
         | 
| 18 19 | 
             
                    extend AutoCorrector
         | 
| 19 20 | 
             
                    include EmptyLineSeparation
         | 
| @@ -21,7 +22,7 @@ module RuboCop | |
| 21 22 |  | 
| 22 23 | 
             
                    MSG = 'Add an empty line after `%<subject>s`.'
         | 
| 23 24 |  | 
| 24 | 
            -
                    def on_block(node)
         | 
| 25 | 
            +
                    def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
         | 
| 25 26 | 
             
                      return unless subject?(node)
         | 
| 26 27 | 
             
                      return unless inside_example_group?(node)
         | 
| 27 28 |  | 
| @@ -47,12 +47,13 @@ module RuboCop | |
| 47 47 | 
             
                  #       content.
         | 
| 48 48 | 
             
                  #     HEREDOC
         | 
| 49 49 | 
             
                  #   end                 # 5 points
         | 
| 50 | 
            +
                  #
         | 
| 50 51 | 
             
                  class ExampleLength < Base
         | 
| 51 52 | 
             
                    include CodeLength
         | 
| 52 53 |  | 
| 53 54 | 
             
                    LABEL = 'Example'
         | 
| 54 55 |  | 
| 55 | 
            -
                    def on_block(node)
         | 
| 56 | 
            +
                    def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
         | 
| 56 57 | 
             
                      return unless example?(node)
         | 
| 57 58 |  | 
| 58 59 | 
             
                      check_code_length(node)
         | 
| @@ -47,6 +47,7 @@ module RuboCop | |
| 47 47 | 
             
                  #     result = service.call
         | 
| 48 48 | 
             
                  #     expect(result).to be(true)
         | 
| 49 49 | 
             
                  #   end
         | 
| 50 | 
            +
                  #
         | 
| 50 51 | 
             
                  class ExampleWithoutDescription < Base
         | 
| 51 52 | 
             
                    include ConfigurableEnforcedStyle
         | 
| 52 53 |  | 
| @@ -57,7 +58,7 @@ module RuboCop | |
| 57 58 | 
             
                    # @!method example_description(node)
         | 
| 58 59 | 
             
                    def_node_matcher :example_description, '(send nil? _ $(str $_))'
         | 
| 59 60 |  | 
| 60 | 
            -
                    def on_block(node)
         | 
| 61 | 
            +
                    def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
         | 
| 61 62 | 
             
                      return unless example?(node)
         | 
| 62 63 |  | 
| 63 64 | 
             
                      check_example_without_description(node.send_node)
         | 
| @@ -29,6 +29,7 @@ module RuboCop | |
| 29 29 | 
             
                  #   # good
         | 
| 30 30 | 
             
                  #   it 'does things' do
         | 
| 31 31 | 
             
                  #   end
         | 
| 32 | 
            +
                  #
         | 
| 32 33 | 
             
                  class ExampleWording < Base
         | 
| 33 34 | 
             
                    extend AutoCorrector
         | 
| 34 35 |  | 
| @@ -46,7 +47,7 @@ module RuboCop | |
| 46 47 | 
             
                      } ...) ...)
         | 
| 47 48 | 
             
                    PATTERN
         | 
| 48 49 |  | 
| 49 | 
            -
                    def on_block(node)
         | 
| 50 | 
            +
                    def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
         | 
| 50 51 | 
             
                      it_description(node) do |description_node, message|
         | 
| 51 52 | 
             
                        if message.match?(SHOULD_PREFIX)
         | 
| 52 53 | 
             
                          add_wording_offense(description_node, MSG_SHOULD)
         | 
| @@ -20,13 +20,14 @@ module RuboCop | |
| 20 20 | 
             
                  #   it do
         | 
| 21 21 | 
             
                  #     expect(something).to eq 'foo'
         | 
| 22 22 | 
             
                  #   end
         | 
| 23 | 
            +
                  #
         | 
| 23 24 | 
             
                  class ExpectInHook < Base
         | 
| 24 25 | 
             
                    MSG = 'Do not use `%<expect>s` in `%<hook>s` hook'
         | 
| 25 26 |  | 
| 26 27 | 
             
                    # @!method expectation(node)
         | 
| 27 28 | 
             
                    def_node_search :expectation, send_pattern('#Expectations.all')
         | 
| 28 29 |  | 
| 29 | 
            -
                    def on_block(node)
         | 
| 30 | 
            +
                    def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
         | 
| 30 31 | 
             
                      return unless hook?(node)
         | 
| 31 32 | 
             
                      return if node.body.nil?
         | 
| 32 33 |  | 
| @@ -36,6 +37,8 @@ module RuboCop | |
| 36 37 | 
             
                      end
         | 
| 37 38 | 
             
                    end
         | 
| 38 39 |  | 
| 40 | 
            +
                    alias on_numblock on_block
         | 
| 41 | 
            +
             | 
| 39 42 | 
             
                    private
         | 
| 40 43 |  | 
| 41 44 | 
             
                    def message(expect, hook)
         | 
| @@ -24,6 +24,7 @@ module RuboCop | |
| 24 24 | 
             
                    #
         | 
| 25 25 | 
             
                    #   # good
         | 
| 26 26 | 
             
                    #   count { 1 }
         | 
| 27 | 
            +
                    #
         | 
| 27 28 | 
             
                    class AttributeDefinedStatically < Base
         | 
| 28 29 | 
             
                      extend AutoCorrector
         | 
| 29 30 |  | 
| @@ -39,7 +40,7 @@ module RuboCop | |
| 39 40 | 
             
                        (block (send _ #attribute_defining_method? ...) _ { (begin $...) $(send ...) } )
         | 
| 40 41 | 
             
                      PATTERN
         | 
| 41 42 |  | 
| 42 | 
            -
                      def on_block(node)
         | 
| 43 | 
            +
                      def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
         | 
| 43 44 | 
             
                        attributes = factory_attributes(node) || []
         | 
| 44 45 | 
             
                        attributes = [attributes] unless attributes.is_a?(Array) # rubocop:disable Style/ArrayCoercion, Lint/RedundantCopDisableDirective
         | 
| 45 46 |  | 
| @@ -30,6 +30,7 @@ module RuboCop | |
| 30 30 | 
             
                    #
         | 
| 31 31 | 
             
                    #   # good
         | 
| 32 32 | 
             
                    #   3.times { create :user }
         | 
| 33 | 
            +
                    #
         | 
| 33 34 | 
             
                    class CreateList < Base
         | 
| 34 35 | 
             
                      extend AutoCorrector
         | 
| 35 36 | 
             
                      include ConfigurableEnforcedStyle
         | 
| @@ -39,20 +40,23 @@ module RuboCop | |
| 39 40 | 
             
                      MSG_N_TIMES = 'Prefer %<number>s.times.'
         | 
| 40 41 | 
             
                      RESTRICT_ON_SEND = %i[create_list].freeze
         | 
| 41 42 |  | 
| 42 | 
            -
                      # @!method  | 
| 43 | 
            -
                      def_node_matcher : | 
| 43 | 
            +
                      # @!method array_new_or_n_times_block?(node)
         | 
| 44 | 
            +
                      def_node_matcher :array_new_or_n_times_block?, <<-PATTERN
         | 
| 44 45 | 
             
                        (block
         | 
| 45 | 
            -
                           | 
| 46 | 
            +
                          {
         | 
| 47 | 
            +
                            (send (const {nil? | cbase} :Array) :new (int _)) |
         | 
| 48 | 
            +
                            (send (int _) :times)
         | 
| 49 | 
            +
                          }
         | 
| 46 50 | 
             
                          ...
         | 
| 47 51 | 
             
                        )
         | 
| 48 52 | 
             
                      PATTERN
         | 
| 49 53 |  | 
| 50 | 
            -
                      # @!method  | 
| 51 | 
            -
                      def_node_matcher : | 
| 54 | 
            +
                      # @!method block_with_arg_and_used?(node)
         | 
| 55 | 
            +
                      def_node_matcher :block_with_arg_and_used?, <<-PATTERN
         | 
| 52 56 | 
             
                        (block
         | 
| 53 | 
            -
                           | 
| 57 | 
            +
                          _
         | 
| 54 58 | 
             
                          (args (arg _value))
         | 
| 55 | 
            -
             | 
| 59 | 
            +
                          `_value
         | 
| 56 60 | 
             
                        )
         | 
| 57 61 | 
             
                      PATTERN
         | 
| 58 62 |  | 
| @@ -71,11 +75,11 @@ module RuboCop | |
| 71 75 | 
             
                        (send {nil? #factory_bot?} :create_list (sym _) (int $_) ...)
         | 
| 72 76 | 
             
                      PATTERN
         | 
| 73 77 |  | 
| 74 | 
            -
                      def on_block(node)
         | 
| 78 | 
            +
                      def on_block(node) # rubocop:todo InternalAffairs/NumblockHandler
         | 
| 75 79 | 
             
                        return unless style == :create_list
         | 
| 76 80 |  | 
| 77 | 
            -
                        return unless  | 
| 78 | 
            -
                        return if  | 
| 81 | 
            +
                        return unless array_new_or_n_times_block?(node)
         | 
| 82 | 
            +
                        return if block_with_arg_and_used?(node)
         | 
| 79 83 | 
             
                        return unless node.body
         | 
| 80 84 | 
             
                        return if arguments_include_method_call?(node.body)
         | 
| 81 85 | 
             
                        return unless contains_only_factory?(node.body)
         | 
| @@ -183,7 +187,7 @@ module RuboCop | |
| 183 187 |  | 
| 184 188 | 
             
                        def call_with_block_replacement(node)
         | 
| 185 189 | 
             
                          block = node.body
         | 
| 186 | 
            -
                          arguments = build_arguments(block, node | 
| 190 | 
            +
                          arguments = build_arguments(block, count_from(node))
         | 
| 187 191 | 
             
                          replacement = format_receiver(block.receiver)
         | 
| 188 192 | 
             
                          replacement += format_method_call(block, 'create_list', arguments)
         | 
| 189 193 | 
             
                          replacement += format_block(block)
         | 
| @@ -203,7 +207,7 @@ module RuboCop | |
| 203 207 | 
             
                          block = node.body
         | 
| 204 208 | 
             
                          factory, *options = *block.arguments
         | 
| 205 209 |  | 
| 206 | 
            -
                          arguments = "#{factory.source}, #{node | 
| 210 | 
            +
                          arguments = "#{factory.source}, #{count_from(node)}"
         | 
| 207 211 | 
             
                          options = build_options_string(options)
         | 
| 208 212 | 
             
                          arguments += ", #{options}" unless options.empty?
         | 
| 209 213 |  | 
| @@ -212,6 +216,16 @@ module RuboCop | |
| 212 216 | 
             
                          replacement
         | 
| 213 217 | 
             
                        end
         | 
| 214 218 |  | 
| 219 | 
            +
                        def count_from(node)
         | 
| 220 | 
            +
                          count_node =
         | 
| 221 | 
            +
                            if node.receiver.int_type?
         | 
| 222 | 
            +
                              node.receiver
         | 
| 223 | 
            +
                            else
         | 
| 224 | 
            +
                              node.send_node.first_argument
         | 
| 225 | 
            +
                            end
         | 
| 226 | 
            +
                          count_node.source
         | 
| 227 | 
            +
                        end
         | 
| 228 | 
            +
             | 
| 215 229 | 
             
                        def format_block(node)
         | 
| 216 230 | 
             
                          if node.body.begin_type?
         | 
| 217 231 | 
             
                            format_multiline_block(node)
         | 
| @@ -58,6 +58,7 @@ module RuboCop | |
| 58 58 | 
             
                  #
         | 
| 59 59 | 
             
                  class FilePath < Base
         | 
| 60 60 | 
             
                    include TopLevelGroup
         | 
| 61 | 
            +
                    include Namespace
         | 
| 61 62 |  | 
| 62 63 | 
             
                    MSG = 'Spec path should end with `%<suffix>s`.'
         | 
| 63 64 |  | 
| @@ -101,7 +102,7 @@ module RuboCop | |
| 101 102 |  | 
| 102 103 | 
             
                    def pattern_for(example_group, method_name)
         | 
| 103 104 | 
             
                      if spec_suffix_only? || !example_group.const_type?
         | 
| 104 | 
            -
                        return pattern_for_spec_suffix_only | 
| 105 | 
            +
                        return pattern_for_spec_suffix_only
         | 
| 105 106 | 
             
                      end
         | 
| 106 107 |  | 
| 107 108 | 
             
                      [
         | 
| @@ -111,7 +112,7 @@ module RuboCop | |
| 111 112 | 
             
                      ].join
         | 
| 112 113 | 
             
                    end
         | 
| 113 114 |  | 
| 114 | 
            -
                    def pattern_for_spec_suffix_only | 
| 115 | 
            +
                    def pattern_for_spec_suffix_only
         | 
| 115 116 | 
             
                      '.*_spec\.rb'
         | 
| 116 117 | 
             
                    end
         | 
| 117 118 |  | 
| @@ -123,8 +124,10 @@ module RuboCop | |
| 123 124 | 
             
                    end
         | 
| 124 125 |  | 
| 125 126 | 
             
                    def expected_path(constant)
         | 
| 127 | 
            +
                      constants = namespace(constant) + constant.const_name.split('::')
         | 
| 128 | 
            +
             | 
| 126 129 | 
             
                      File.join(
         | 
| 127 | 
            -
                         | 
| 130 | 
            +
                        constants.map do |name|
         | 
| 128 131 | 
             
                          custom_transform.fetch(name) { camel_to_snake_case(name) }
         | 
| 129 132 | 
             
                        end
         | 
| 130 133 | 
             
                      )
         | 
| @@ -5,6 +5,8 @@ module RuboCop | |
| 5 5 | 
             
                module RSpec
         | 
| 6 6 | 
             
                  # Checks if examples are focused.
         | 
| 7 7 | 
             
                  #
         | 
| 8 | 
            +
                  # This cop does not support autocorrection in some cases.
         | 
| 9 | 
            +
                  #
         | 
| 8 10 | 
             
                  # @example
         | 
| 9 11 | 
             
                  #   # bad
         | 
| 10 12 | 
             
                  #   describe MyClass, focus: true do
         | 
| @@ -19,6 +21,22 @@ module RuboCop | |
| 19 21 | 
             
                  #   # good
         | 
| 20 22 | 
             
                  #   describe MyClass do
         | 
| 21 23 | 
             
                  #   end
         | 
| 24 | 
            +
                  #
         | 
| 25 | 
            +
                  #   # bad
         | 
| 26 | 
            +
                  #   fdescribe 'test' do; end
         | 
| 27 | 
            +
                  #
         | 
| 28 | 
            +
                  #   # good
         | 
| 29 | 
            +
                  #   describe 'test' do; end
         | 
| 30 | 
            +
                  #
         | 
| 31 | 
            +
                  #   # bad
         | 
| 32 | 
            +
                  #   fdescribe 'test' do; end
         | 
| 33 | 
            +
                  #
         | 
| 34 | 
            +
                  #   # good
         | 
| 35 | 
            +
                  #   describe 'test' do; end
         | 
| 36 | 
            +
                  #
         | 
| 37 | 
            +
                  #   # bad (does not support autocorrection)
         | 
| 38 | 
            +
                  #   focus 'test' do; end
         | 
| 39 | 
            +
                  #
         | 
| 22 40 | 
             
                  class Focus < Base
         | 
| 23 41 | 
             
                    extend AutoCorrector
         | 
| 24 42 | 
             
                    include RangeHelp
         | 
| @@ -57,6 +57,7 @@ module RuboCop | |
| 57 57 | 
             
                  #   before(:example) do
         | 
| 58 58 | 
             
                  #     # ...
         | 
| 59 59 | 
             
                  #   end
         | 
| 60 | 
            +
                  #
         | 
| 60 61 | 
             
                  class HookArgument < Base
         | 
| 61 62 | 
             
                    extend AutoCorrector
         | 
| 62 63 | 
             
                    include ConfigurableEnforcedStyle
         | 
| @@ -66,11 +67,13 @@ module RuboCop | |
| 66 67 |  | 
| 67 68 | 
             
                    # @!method scoped_hook(node)
         | 
| 68 69 | 
             
                    def_node_matcher :scoped_hook, <<-PATTERN
         | 
| 69 | 
            -
                      (block $(send _ #Hooks.all (sym ${:each :example})) ...)
         | 
| 70 | 
            +
                      ({block numblock} $(send _ #Hooks.all (sym ${:each :example})) ...)
         | 
| 70 71 | 
             
                    PATTERN
         | 
| 71 72 |  | 
| 72 73 | 
             
                    # @!method unscoped_hook(node)
         | 
| 73 | 
            -
                    def_node_matcher :unscoped_hook,  | 
| 74 | 
            +
                    def_node_matcher :unscoped_hook, <<-PATTERN
         | 
| 75 | 
            +
                      ({block numblock} $(send _ #Hooks.all) ...)
         | 
| 76 | 
            +
                    PATTERN
         | 
| 74 77 |  | 
| 75 78 | 
             
                    def on_block(node)
         | 
| 76 79 | 
             
                      hook(node) do |method_send, scope_name|
         | 
| @@ -86,6 +89,8 @@ module RuboCop | |
| 86 89 | 
             
                      end
         | 
| 87 90 | 
             
                    end
         | 
| 88 91 |  | 
| 92 | 
            +
                    alias on_numblock on_block
         | 
| 93 | 
            +
             | 
| 89 94 | 
             
                    private
         | 
| 90 95 |  | 
| 91 96 | 
             
                    def check_implicit(method_send)
         | 
| @@ -6,8 +6,7 @@ module RuboCop | |
| 6 6 | 
             
                  # Checks for before/around/after hooks that come after an example.
         | 
| 7 7 | 
             
                  #
         | 
| 8 8 | 
             
                  # @example
         | 
| 9 | 
            -
                  #   #  | 
| 10 | 
            -
                  #
         | 
| 9 | 
            +
                  #   # bad
         | 
| 11 10 | 
             
                  #   it 'checks what foo does' do
         | 
| 12 11 | 
             
                  #     expect(foo).to be
         | 
| 13 12 | 
             
                  #   end
         | 
| @@ -15,7 +14,7 @@ module RuboCop | |
| 15 14 | 
             
                  #   before { prepare }
         | 
| 16 15 | 
             
                  #   after { clean_up }
         | 
| 17 16 | 
             
                  #
         | 
| 18 | 
            -
                  #   #  | 
| 17 | 
            +
                  #   # good
         | 
| 19 18 | 
             
                  #   before { prepare }
         | 
| 20 19 | 
             
                  #   after { clean_up }
         | 
| 21 20 | 
             
                  #
         | 
| @@ -32,6 +31,7 @@ module RuboCop | |
| 32 31 | 
             
                    def_node_matcher :example_or_group?, <<-PATTERN
         | 
| 33 32 | 
             
                      {
         | 
| 34 33 | 
             
                        #{block_pattern('{#ExampleGroups.all #Examples.all}')}
         | 
| 34 | 
            +
                        #{numblock_pattern('{#ExampleGroups.all #Examples.all}')}
         | 
| 35 35 | 
             
                        #{send_pattern('#Includes.examples')}
         | 
| 36 36 | 
             
                      }
         | 
| 37 37 | 
             
                    PATTERN
         | 
| @@ -42,6 +42,8 @@ module RuboCop | |
| 42 42 | 
             
                      check_hooks(node.body) if multiline_block?(node.body)
         | 
| 43 43 | 
             
                    end
         | 
| 44 44 |  | 
| 45 | 
            +
                    alias on_numblock on_block
         | 
| 46 | 
            +
             | 
| 45 47 | 
             
                    private
         | 
| 46 48 |  | 
| 47 49 | 
             
                    def multiline_block?(block)
         | 
| @@ -52,13 +54,12 @@ module RuboCop | |
| 52 54 | 
             
                      first_example = find_first_example(node)
         | 
| 53 55 | 
             
                      return unless first_example
         | 
| 54 56 |  | 
| 55 | 
            -
                       | 
| 56 | 
            -
                        next  | 
| 57 | 
            -
                        next unless hook?(child)
         | 
| 57 | 
            +
                      first_example.right_siblings.each do |sibling|
         | 
| 58 | 
            +
                        next unless hook?(sibling)
         | 
| 58 59 |  | 
| 59 | 
            -
                        msg = format(MSG, hook:  | 
| 60 | 
            -
                        add_offense( | 
| 61 | 
            -
                          autocorrect(corrector,  | 
| 60 | 
            +
                        msg = format(MSG, hook: sibling.method_name)
         | 
| 61 | 
            +
                        add_offense(sibling, message: msg) do |corrector|
         | 
| 62 | 
            +
                          autocorrect(corrector, sibling, first_example)
         | 
| 62 63 | 
             
                        end
         | 
| 63 64 | 
             
                      end
         | 
| 64 65 | 
             
                    end
         | 
| @@ -16,6 +16,7 @@ module RuboCop | |
| 16 16 | 
             
                  #   it 'changes something to a new value' do
         | 
| 17 17 | 
             
                  #     expect { do_something }.to change(something).to(new_value)
         | 
| 18 18 | 
             
                  #   end
         | 
| 19 | 
            +
                  #
         | 
| 19 20 | 
             
                  class ImplicitBlockExpectation < Base
         | 
| 20 21 | 
             
                    MSG = 'Avoid implicit block expectations.'
         | 
| 21 22 | 
             
                    RESTRICT_ON_SEND = %i[is_expected should should_not].freeze
         | 
| @@ -9,7 +9,6 @@ module RuboCop | |
| 9 9 | 
             
                  # and supports the `--auto-gen-config` flag.
         | 
| 10 10 | 
             
                  #
         | 
| 11 11 | 
             
                  # @example `EnforcedStyle: is_expected` (default)
         | 
| 12 | 
            -
                  #
         | 
| 13 12 | 
             
                  #   # bad
         | 
| 14 13 | 
             
                  #   it { should be_truthy }
         | 
| 15 14 | 
             
                  #
         | 
| @@ -17,7 +16,6 @@ module RuboCop | |
| 17 16 | 
             
                  #   it { is_expected.to be_truthy }
         | 
| 18 17 | 
             
                  #
         | 
| 19 18 | 
             
                  # @example `EnforcedStyle: should`
         | 
| 20 | 
            -
                  #
         | 
| 21 19 | 
             
                  #   # bad
         | 
| 22 20 | 
             
                  #   it { is_expected.to be_truthy }
         | 
| 23 21 | 
             
                  #
         | 
| @@ -15,6 +15,7 @@ module RuboCop | |
| 15 15 | 
             
                  #   it 'validates users' do
         | 
| 16 16 | 
             
                  #     expect([user1, user2, user3]).to all(be_valid)
         | 
| 17 17 | 
             
                  #   end
         | 
| 18 | 
            +
                  #
         | 
| 18 19 | 
             
                  class IteratedExpectation < Base
         | 
| 19 20 | 
             
                    MSG = 'Prefer using the `all` matcher instead ' \
         | 
| 20 21 | 
             
                          'of iterating over an array.'
         | 
| @@ -28,6 +29,13 @@ module RuboCop | |
| 28 29 | 
             
                      )
         | 
| 29 30 | 
             
                    PATTERN
         | 
| 30 31 |  | 
| 32 | 
            +
                    # @!method each_numblock?(node)
         | 
| 33 | 
            +
                    def_node_matcher :each_numblock?, <<-PATTERN
         | 
| 34 | 
            +
                      (numblock
         | 
| 35 | 
            +
                        (send ... :each) _ $(...)
         | 
| 36 | 
            +
                      )
         | 
| 37 | 
            +
                    PATTERN
         | 
| 38 | 
            +
             | 
| 31 39 | 
             
                    # @!method expectation?(node)
         | 
| 32 40 | 
             
                    def_node_matcher :expectation?, <<-PATTERN
         | 
| 33 41 | 
             
                      (send (send nil? :expect (lvar %)) :to ...)
         | 
| @@ -41,6 +49,14 @@ module RuboCop | |
| 41 49 | 
             
                      end
         | 
| 42 50 | 
             
                    end
         | 
| 43 51 |  | 
| 52 | 
            +
                    def on_numblock(node)
         | 
| 53 | 
            +
                      each_numblock?(node) do |body|
         | 
| 54 | 
            +
                        if single_expectation?(body, :_1) || only_expectations?(body, :_1)
         | 
| 55 | 
            +
                          add_offense(node.send_node)
         | 
| 56 | 
            +
                        end
         | 
| 57 | 
            +
                      end
         | 
| 58 | 
            +
                    end
         | 
| 59 | 
            +
             | 
| 44 60 | 
             
                    private
         | 
| 45 61 |  | 
| 46 62 | 
             
                    def single_expectation?(body, arg)
         | 
| @@ -7,29 +7,29 @@ module RuboCop | |
| 7 7 | 
             
                  #
         | 
| 8 8 | 
             
                  # @example
         | 
| 9 9 | 
             
                  #   # bad
         | 
| 10 | 
            -
                  # | 
| 11 | 
            -
                  # | 
| 10 | 
            +
                  #   let(:params) { blah }
         | 
| 11 | 
            +
                  #   subject { described_class.new(params) }
         | 
| 12 12 | 
             
                  #
         | 
| 13 | 
            -
                  # | 
| 14 | 
            -
                  # | 
| 13 | 
            +
                  #   before { do_something }
         | 
| 14 | 
            +
                  #   subject { described_class.new(params) }
         | 
| 15 15 | 
             
                  #
         | 
| 16 | 
            -
                  # | 
| 17 | 
            -
                  # | 
| 18 | 
            -
                  # | 
| 16 | 
            +
                  #   it { expect_something }
         | 
| 17 | 
            +
                  #   subject { described_class.new(params) }
         | 
| 18 | 
            +
                  #   it { expect_something_else }
         | 
| 19 19 | 
             
                  #
         | 
| 20 20 | 
             
                  #
         | 
| 21 21 | 
             
                  #   # good
         | 
| 22 | 
            -
                  # | 
| 23 | 
            -
                  # | 
| 22 | 
            +
                  #   subject { described_class.new(params) }
         | 
| 23 | 
            +
                  #   let(:params) { blah }
         | 
| 24 24 | 
             
                  #
         | 
| 25 25 | 
             
                  #   # good
         | 
| 26 | 
            -
                  # | 
| 27 | 
            -
                  # | 
| 26 | 
            +
                  #   subject { described_class.new(params) }
         | 
| 27 | 
            +
                  #   before { do_something }
         | 
| 28 28 | 
             
                  #
         | 
| 29 29 | 
             
                  #   # good
         | 
| 30 | 
            -
                  # | 
| 31 | 
            -
                  # | 
| 32 | 
            -
                  # | 
| 30 | 
            +
                  #   subject { described_class.new(params) }
         | 
| 31 | 
            +
                  #   it { expect_something }
         | 
| 32 | 
            +
                  #   it { expect_something_else }
         | 
| 33 33 | 
             
                  #
         | 
| 34 34 | 
             
                  class LeadingSubject < Base
         | 
| 35 35 | 
             
                    extend AutoCorrector
         | 
| @@ -37,7 +37,7 @@ module RuboCop | |
| 37 37 |  | 
| 38 38 | 
             
                    MSG = 'Declare `subject` above any other `%<offending>s` declarations.'
         | 
| 39 39 |  | 
| 40 | 
            -
                    def on_block(node)
         | 
| 40 | 
            +
                    def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
         | 
| 41 41 | 
             
                      return unless subject?(node)
         | 
| 42 42 | 
             
                      return unless inside_example_group?(node)
         | 
| 43 43 |  |