rubocop-rspec 1.38.1 → 1.43.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 +57 -0
- data/CODE_OF_CONDUCT.md +17 -0
- data/README.md +1 -61
- data/config/default.yml +159 -19
- data/lib/rubocop-rspec.rb +5 -2
- data/lib/rubocop/cop/rspec/align_left_let_brace.rb +12 -19
- data/lib/rubocop/cop/rspec/align_right_let_brace.rb +12 -19
- data/lib/rubocop/cop/rspec/any_instance.rb +1 -1
- data/lib/rubocop/cop/rspec/around_block.rb +1 -1
- data/lib/rubocop/cop/rspec/base.rb +74 -0
- data/lib/rubocop/cop/rspec/be.rb +2 -2
- data/lib/rubocop/cop/rspec/be_eql.rb +6 -6
- data/lib/rubocop/cop/rspec/before_after_all.rb +1 -1
- data/lib/rubocop/cop/rspec/capybara/current_path_expectation.rb +19 -17
- data/lib/rubocop/cop/rspec/capybara/feature_methods.rb +14 -12
- data/lib/rubocop/cop/rspec/capybara/visibility_matcher.rb +69 -0
- data/lib/rubocop/cop/rspec/context_method.rb +7 -9
- data/lib/rubocop/cop/rspec/context_wording.rb +3 -3
- data/lib/rubocop/cop/rspec/cop.rb +3 -87
- data/lib/rubocop/cop/rspec/describe_class.rb +29 -23
- data/lib/rubocop/cop/rspec/describe_method.rb +14 -7
- data/lib/rubocop/cop/rspec/describe_symbol.rb +2 -2
- data/lib/rubocop/cop/rspec/described_class.rb +12 -9
- data/lib/rubocop/cop/rspec/described_class_module_wrapping.rb +1 -1
- data/lib/rubocop/cop/rspec/dialect.rb +5 -12
- data/lib/rubocop/cop/rspec/empty_example_group.rb +91 -7
- data/lib/rubocop/cop/rspec/empty_hook.rb +46 -0
- data/lib/rubocop/cop/rspec/empty_line_after_example.rb +5 -7
- data/lib/rubocop/cop/rspec/empty_line_after_example_group.rb +5 -9
- data/lib/rubocop/cop/rspec/empty_line_after_final_let.rb +8 -8
- data/lib/rubocop/cop/rspec/empty_line_after_hook.rb +5 -9
- data/lib/rubocop/cop/rspec/empty_line_after_subject.rb +6 -6
- data/lib/rubocop/cop/rspec/example_length.rb +1 -1
- data/lib/rubocop/cop/rspec/example_without_description.rb +1 -1
- data/lib/rubocop/cop/rspec/example_wording.rb +10 -11
- data/lib/rubocop/cop/rspec/expect_actual.rb +8 -11
- data/lib/rubocop/cop/rspec/expect_change.rb +10 -35
- data/lib/rubocop/cop/rspec/expect_in_hook.rb +3 -3
- data/lib/rubocop/cop/rspec/expect_output.rb +2 -2
- data/lib/rubocop/cop/rspec/factory_bot/attribute_defined_statically.rb +24 -21
- data/lib/rubocop/cop/rspec/factory_bot/create_list.rb +20 -22
- data/lib/rubocop/cop/rspec/factory_bot/factory_class_name.rb +7 -8
- data/lib/rubocop/cop/rspec/file_path.rb +57 -21
- data/lib/rubocop/cop/rspec/focus.rb +7 -11
- data/lib/rubocop/cop/rspec/hook_argument.rb +16 -23
- data/lib/rubocop/cop/rspec/hooks_before_examples.rb +10 -29
- data/lib/rubocop/cop/rspec/implicit_block_expectation.rb +1 -1
- data/lib/rubocop/cop/rspec/implicit_expect.rb +7 -15
- data/lib/rubocop/cop/rspec/implicit_subject.rb +16 -11
- data/lib/rubocop/cop/rspec/instance_spy.rb +18 -12
- data/lib/rubocop/cop/rspec/instance_variable.rb +4 -8
- data/lib/rubocop/cop/rspec/invalid_predicate_matcher.rb +3 -6
- data/lib/rubocop/cop/rspec/it_behaves_like.rb +5 -6
- data/lib/rubocop/cop/rspec/iterated_expectation.rb +1 -1
- data/lib/rubocop/cop/rspec/leading_subject.rb +22 -26
- data/lib/rubocop/cop/rspec/leaky_constant_declaration.rb +2 -5
- data/lib/rubocop/cop/rspec/let_before_examples.rb +10 -26
- data/lib/rubocop/cop/rspec/let_setup.rb +21 -6
- data/lib/rubocop/cop/rspec/message_chain.rb +7 -6
- data/lib/rubocop/cop/rspec/message_expectation.rb +2 -2
- data/lib/rubocop/cop/rspec/message_spies.rb +2 -3
- data/lib/rubocop/cop/rspec/missing_example_group_argument.rb +1 -1
- data/lib/rubocop/cop/rspec/multiple_describes.rb +11 -8
- data/lib/rubocop/cop/rspec/multiple_expectations.rb +7 -11
- data/lib/rubocop/cop/rspec/multiple_memoized_helpers.rb +148 -0
- data/lib/rubocop/cop/rspec/multiple_subjects.rb +18 -19
- data/lib/rubocop/cop/rspec/named_subject.rb +8 -8
- data/lib/rubocop/cop/rspec/nested_groups.rb +12 -13
- data/lib/rubocop/cop/rspec/not_to_not.rb +5 -6
- data/lib/rubocop/cop/rspec/overwriting_setup.rb +1 -1
- data/lib/rubocop/cop/rspec/pending.rb +1 -1
- data/lib/rubocop/cop/rspec/predicate_matcher.rb +32 -69
- data/lib/rubocop/cop/rspec/rails/http_status.rb +7 -9
- data/lib/rubocop/cop/rspec/receive_counts.rb +15 -17
- data/lib/rubocop/cop/rspec/receive_never.rb +12 -12
- data/lib/rubocop/cop/rspec/repeated_description.rb +1 -1
- data/lib/rubocop/cop/rspec/repeated_example.rb +2 -2
- data/lib/rubocop/cop/rspec/repeated_example_group_body.rb +12 -2
- data/lib/rubocop/cop/rspec/repeated_example_group_description.rb +1 -1
- data/lib/rubocop/cop/rspec/return_from_stub.rb +12 -22
- data/lib/rubocop/cop/rspec/scattered_let.rb +12 -2
- data/lib/rubocop/cop/rspec/scattered_setup.rb +1 -1
- data/lib/rubocop/cop/rspec/shared_context.rb +8 -21
- data/lib/rubocop/cop/rspec/shared_examples.rb +7 -9
- data/lib/rubocop/cop/rspec/single_argument_message_chain.rb +15 -18
- data/lib/rubocop/cop/rspec/subject_stub.rb +25 -53
- data/lib/rubocop/cop/rspec/unspecified_exception.rb +1 -1
- data/lib/rubocop/cop/rspec/variable_definition.rb +56 -0
- data/lib/rubocop/cop/rspec/variable_name.rb +66 -0
- data/lib/rubocop/cop/rspec/verified_doubles.rb +1 -1
- data/lib/rubocop/cop/rspec/void_expect.rb +1 -1
- data/lib/rubocop/cop/rspec/yield.rb +14 -11
- data/lib/rubocop/cop/rspec_cops.rb +6 -1
- data/lib/rubocop/rspec/corrector/move_node.rb +54 -0
- data/lib/rubocop/rspec/description_extractor.rb +2 -6
- data/lib/rubocop/rspec/{blank_line_separation.rb → empty_line_separation.rb} +13 -10
- data/lib/rubocop/rspec/example_group.rb +21 -49
- data/lib/rubocop/rspec/factory_bot.rb +7 -1
- data/lib/rubocop/rspec/language.rb +13 -3
- data/lib/rubocop/rspec/language/node_pattern.rb +11 -2
- data/lib/rubocop/rspec/top_level_describe.rb +2 -2
- data/lib/rubocop/rspec/top_level_group.rb +55 -0
- data/lib/rubocop/rspec/variable.rb +16 -0
- data/lib/rubocop/rspec/version.rb +1 -1
- metadata +36 -13
- data/lib/rubocop/rspec/util.rb +0 -19
| @@ -24,7 +24,8 @@ module RuboCop | |
| 24 24 | 
             
                    #
         | 
| 25 25 | 
             
                    #   # good
         | 
| 26 26 | 
             
                    #   3.times { create :user }
         | 
| 27 | 
            -
                    class CreateList <  | 
| 27 | 
            +
                    class CreateList < Base
         | 
| 28 | 
            +
                      extend AutoCorrector
         | 
| 28 29 | 
             
                      include ConfigurableEnforcedStyle
         | 
| 29 30 |  | 
| 30 31 | 
             
                      MSG_CREATE_LIST = 'Prefer create_list.'
         | 
| @@ -43,7 +44,7 @@ module RuboCop | |
| 43 44 | 
             
                      PATTERN
         | 
| 44 45 |  | 
| 45 46 | 
             
                      def_node_matcher :factory_list_call, <<-PATTERN
         | 
| 46 | 
            -
                        (send  | 
| 47 | 
            +
                        (send {(const nil? {:FactoryGirl :FactoryBot}) nil?} :create_list (sym _) (int $_) ...)
         | 
| 47 48 | 
             
                      PATTERN
         | 
| 48 49 |  | 
| 49 50 | 
             
                      def on_block(node)
         | 
| @@ -51,26 +52,19 @@ module RuboCop | |
| 51 52 | 
             
                        return unless n_times_block_without_arg?(node)
         | 
| 52 53 | 
             
                        return unless contains_only_factory?(node.body)
         | 
| 53 54 |  | 
| 54 | 
            -
                        add_offense(node.send_node, message: MSG_CREATE_LIST)
         | 
| 55 | 
            +
                        add_offense(node.send_node, message: MSG_CREATE_LIST) do |corrector|
         | 
| 56 | 
            +
                          CreateListCorrector.new(node.send_node).call(corrector)
         | 
| 57 | 
            +
                        end
         | 
| 55 58 | 
             
                      end
         | 
| 56 59 |  | 
| 57 60 | 
             
                      def on_send(node)
         | 
| 58 61 | 
             
                        return unless style == :n_times
         | 
| 59 62 |  | 
| 60 | 
            -
                        factory_list_call(node) do | | 
| 61 | 
            -
                           | 
| 62 | 
            -
             | 
| 63 | 
            -
                             | 
| 64 | 
            -
             | 
| 65 | 
            -
                          )
         | 
| 66 | 
            -
                        end
         | 
| 67 | 
            -
                      end
         | 
| 68 | 
            -
             | 
| 69 | 
            -
                      def autocorrect(node)
         | 
| 70 | 
            -
                        if style == :create_list
         | 
| 71 | 
            -
                          CreateListCorrector.new(node)
         | 
| 72 | 
            -
                        else
         | 
| 73 | 
            -
                          TimesCorrector.new(node)
         | 
| 63 | 
            +
                        factory_list_call(node) do |count|
         | 
| 64 | 
            +
                          message = format(MSG_N_TIMES, number: count)
         | 
| 65 | 
            +
                          add_offense(node.loc.selector, message: message) do |corrector|
         | 
| 66 | 
            +
                            TimesCorrector.new(node).call(corrector)
         | 
| 67 | 
            +
                          end
         | 
| 74 68 | 
             
                        end
         | 
| 75 69 | 
             
                      end
         | 
| 76 70 |  | 
| @@ -85,7 +79,7 @@ module RuboCop | |
| 85 79 | 
             
                      end
         | 
| 86 80 |  | 
| 87 81 | 
             
                      # :nodoc
         | 
| 88 | 
            -
                       | 
| 82 | 
            +
                      module Corrector
         | 
| 89 83 | 
             
                        private
         | 
| 90 84 |  | 
| 91 85 | 
             
                        def build_options_string(options)
         | 
| @@ -108,14 +102,16 @@ module RuboCop | |
| 108 102 | 
             
                      end
         | 
| 109 103 |  | 
| 110 104 | 
             
                      # :nodoc
         | 
| 111 | 
            -
                      class TimesCorrector | 
| 105 | 
            +
                      class TimesCorrector
         | 
| 106 | 
            +
                        include Corrector
         | 
| 107 | 
            +
             | 
| 112 108 | 
             
                        def initialize(node)
         | 
| 113 109 | 
             
                          @node = node
         | 
| 114 110 | 
             
                        end
         | 
| 115 111 |  | 
| 116 112 | 
             
                        def call(corrector)
         | 
| 117 113 | 
             
                          replacement = generate_n_times_block(node)
         | 
| 118 | 
            -
                          corrector.replace(node | 
| 114 | 
            +
                          corrector.replace(node, replacement)
         | 
| 119 115 | 
             
                        end
         | 
| 120 116 |  | 
| 121 117 | 
             
                        private
         | 
| @@ -136,7 +132,9 @@ module RuboCop | |
| 136 132 | 
             
                      end
         | 
| 137 133 |  | 
| 138 134 | 
             
                      # :nodoc:
         | 
| 139 | 
            -
                      class CreateListCorrector | 
| 135 | 
            +
                      class CreateListCorrector
         | 
| 136 | 
            +
                        include Corrector
         | 
| 137 | 
            +
             | 
| 140 138 | 
             
                        def initialize(node)
         | 
| 141 139 | 
             
                          @node = node.parent
         | 
| 142 140 | 
             
                        end
         | 
| @@ -148,7 +146,7 @@ module RuboCop | |
| 148 146 | 
             
                                          call_replacement(node)
         | 
| 149 147 | 
             
                                        end
         | 
| 150 148 |  | 
| 151 | 
            -
                          corrector.replace(node | 
| 149 | 
            +
                          corrector.replace(node, replacement)
         | 
| 152 150 | 
             
                        end
         | 
| 153 151 |  | 
| 154 152 | 
             
                        private
         | 
| @@ -19,7 +19,9 @@ module RuboCop | |
| 19 19 | 
             
                    #   # good
         | 
| 20 20 | 
             
                    #   factory :foo, class: 'Foo' do
         | 
| 21 21 | 
             
                    #   end
         | 
| 22 | 
            -
                    class FactoryClassName <  | 
| 22 | 
            +
                    class FactoryClassName < Base
         | 
| 23 | 
            +
                      extend AutoCorrector
         | 
| 24 | 
            +
             | 
| 23 25 | 
             
                      MSG = "Pass '%<class_name>s' string instead of `%<class_name>s` " \
         | 
| 24 26 | 
             
                            'constant.'
         | 
| 25 27 | 
             
                      ALLOWED_CONSTANTS = %w[Hash OpenStruct].freeze
         | 
| @@ -32,13 +34,10 @@ module RuboCop | |
| 32 34 | 
             
                        class_name(node) do |cn|
         | 
| 33 35 | 
             
                          next if allowed?(cn.const_name)
         | 
| 34 36 |  | 
| 35 | 
            -
                           | 
| 36 | 
            -
             | 
| 37 | 
            -
             | 
| 38 | 
            -
             | 
| 39 | 
            -
                      def autocorrect(node)
         | 
| 40 | 
            -
                        lambda do |corrector|
         | 
| 41 | 
            -
                          corrector.replace(node.loc.expression, "'#{node.source}'")
         | 
| 37 | 
            +
                          msg = format(MSG, class_name: cn.const_name)
         | 
| 38 | 
            +
                          add_offense(cn, message: msg) do |corrector|
         | 
| 39 | 
            +
                            corrector.replace(cn, "'#{cn.source}'")
         | 
| 40 | 
            +
                          end
         | 
| 42 41 | 
             
                        end
         | 
| 43 42 | 
             
                      end
         | 
| 44 43 |  | 
| @@ -3,10 +3,11 @@ | |
| 3 3 | 
             
            module RuboCop
         | 
| 4 4 | 
             
              module Cop
         | 
| 5 5 | 
             
                module RSpec
         | 
| 6 | 
            -
                  # Checks that spec file paths are consistent  | 
| 6 | 
            +
                  # Checks that spec file paths are consistent and well-formed.
         | 
| 7 7 | 
             
                  #
         | 
| 8 | 
            -
                  #  | 
| 9 | 
            -
                  #  | 
| 8 | 
            +
                  # By default, this checks that spec file paths are consistent with the
         | 
| 9 | 
            +
                  # test subject and and enforces that it reflects the described
         | 
| 10 | 
            +
                  # class/module and its optionally called out method.
         | 
| 10 11 | 
             
                  #
         | 
| 11 12 | 
             
                  # With the configuration option `IgnoreMethods` the called out method will
         | 
| 12 13 | 
             
                  # be ignored when determining the enforced path.
         | 
| @@ -15,6 +16,10 @@ module RuboCop | |
| 15 16 | 
             
                  # be specified that should not as usual be transformed from CamelCase to
         | 
| 16 17 | 
             
                  # snake_case (e.g. 'RuboCop' => 'rubocop' ).
         | 
| 17 18 | 
             
                  #
         | 
| 19 | 
            +
                  # With the configuration option `SpecSuffixOnly` test files will only
         | 
| 20 | 
            +
                  # be checked to ensure they end in '_spec.rb'. This option disables
         | 
| 21 | 
            +
                  # checking for consistency in the test subject or test methods.
         | 
| 22 | 
            +
                  #
         | 
| 18 23 | 
             
                  # @example
         | 
| 19 24 | 
             
                  #   # bad
         | 
| 20 25 | 
             
                  #   whatever_spec.rb         # describe MyClass
         | 
| @@ -41,42 +46,66 @@ module RuboCop | |
| 41 46 | 
             
                  #   # good
         | 
| 42 47 | 
             
                  #   my_class_spec.rb         # describe MyClass, '#method'
         | 
| 43 48 | 
             
                  #
         | 
| 44 | 
            -
                   | 
| 45 | 
            -
             | 
| 49 | 
            +
                  # @example when configuration is `SpecSuffixOnly: true`
         | 
| 50 | 
            +
                  #   # good
         | 
| 51 | 
            +
                  #   whatever_spec.rb         # describe MyClass
         | 
| 52 | 
            +
                  #
         | 
| 53 | 
            +
                  #   # good
         | 
| 54 | 
            +
                  #   my_class_spec.rb         # describe MyClass
         | 
| 55 | 
            +
                  #
         | 
| 56 | 
            +
                  #   # good
         | 
| 57 | 
            +
                  #   my_class_spec.rb         # describe MyClass, '#method'
         | 
| 58 | 
            +
                  #
         | 
| 59 | 
            +
                  class FilePath < Base
         | 
| 60 | 
            +
                    include RuboCop::RSpec::TopLevelGroup
         | 
| 46 61 |  | 
| 47 62 | 
             
                    MSG = 'Spec path should end with `%<suffix>s`.'
         | 
| 48 63 |  | 
| 49 | 
            -
                     | 
| 50 | 
            -
             | 
| 64 | 
            +
                    def_node_matcher :const_described, <<~PATTERN
         | 
| 65 | 
            +
                      (block
         | 
| 66 | 
            +
                        $(send #rspec? _example_group $(const ...) $...) ...
         | 
| 67 | 
            +
                      )
         | 
| 68 | 
            +
                    PATTERN
         | 
| 51 69 |  | 
| 52 | 
            -
                     | 
| 53 | 
            -
                      return unless const_described?(node) && single_top_level_describe?
         | 
| 54 | 
            -
                      return if routing_spec?(args)
         | 
| 70 | 
            +
                    def_node_search :routing_metadata?, '(pair (sym :type) (sym :routing))'
         | 
| 55 71 |  | 
| 56 | 
            -
             | 
| 72 | 
            +
                    def on_top_level_group(node)
         | 
| 73 | 
            +
                      return unless top_level_groups.one?
         | 
| 57 74 |  | 
| 58 | 
            -
                       | 
| 75 | 
            +
                      const_described(node) do |send_node, described_class, arguments|
         | 
| 76 | 
            +
                        next if routing_spec?(arguments)
         | 
| 59 77 |  | 
| 60 | 
            -
             | 
| 61 | 
            -
             | 
| 62 | 
            -
                        message: format(MSG, suffix: glob)
         | 
| 63 | 
            -
                      )
         | 
| 78 | 
            +
                        ensure_correct_file_path(send_node, described_class, arguments)
         | 
| 79 | 
            +
                      end
         | 
| 64 80 | 
             
                    end
         | 
| 65 81 |  | 
| 66 82 | 
             
                    private
         | 
| 67 83 |  | 
| 84 | 
            +
                    def ensure_correct_file_path(send_node, described_class, arguments)
         | 
| 85 | 
            +
                      glob = glob_for(described_class, arguments.first)
         | 
| 86 | 
            +
                      return if filename_ends_with?(glob)
         | 
| 87 | 
            +
             | 
| 88 | 
            +
                      add_offense(send_node, message: format(MSG, suffix: glob))
         | 
| 89 | 
            +
                    end
         | 
| 90 | 
            +
             | 
| 68 91 | 
             
                    def routing_spec?(args)
         | 
| 69 92 | 
             
                      args.any?(&method(:routing_metadata?))
         | 
| 70 93 | 
             
                    end
         | 
| 71 94 |  | 
| 72 | 
            -
                    def glob_for( | 
| 95 | 
            +
                    def glob_for(described_class, method_name)
         | 
| 96 | 
            +
                      return glob_for_spec_suffix_only? if spec_suffix_only?
         | 
| 97 | 
            +
             | 
| 73 98 | 
             
                      "#{expected_path(described_class)}#{name_glob(method_name)}*_spec.rb"
         | 
| 74 99 | 
             
                    end
         | 
| 75 100 |  | 
| 76 | 
            -
                    def  | 
| 77 | 
            -
                       | 
| 101 | 
            +
                    def glob_for_spec_suffix_only?
         | 
| 102 | 
            +
                      '*_spec.rb'
         | 
| 103 | 
            +
                    end
         | 
| 104 | 
            +
             | 
| 105 | 
            +
                    def name_glob(method_name)
         | 
| 106 | 
            +
                      return unless method_name&.str_type?
         | 
| 78 107 |  | 
| 79 | 
            -
                      "*#{ | 
| 108 | 
            +
                      "*#{method_name.str_content.gsub(/\W/, '')}" unless ignore_methods?
         | 
| 80 109 | 
             
                    end
         | 
| 81 110 |  | 
| 82 111 | 
             
                    def expected_path(constant)
         | 
| @@ -103,12 +132,19 @@ module RuboCop | |
| 103 132 | 
             
                    end
         | 
| 104 133 |  | 
| 105 134 | 
             
                    def filename_ends_with?(glob)
         | 
| 106 | 
            -
                       | 
| 135 | 
            +
                      filename =
         | 
| 136 | 
            +
                        RuboCop::PathUtil.relative_path(processed_source.buffer.name)
         | 
| 137 | 
            +
                          .gsub('../', '')
         | 
| 138 | 
            +
                      File.fnmatch?("*#{glob}", filename)
         | 
| 107 139 | 
             
                    end
         | 
| 108 140 |  | 
| 109 141 | 
             
                    def relevant_rubocop_rspec_file?(_file)
         | 
| 110 142 | 
             
                      true
         | 
| 111 143 | 
             
                    end
         | 
| 144 | 
            +
             | 
| 145 | 
            +
                    def spec_suffix_only?
         | 
| 146 | 
            +
                      cop_config['SpecSuffixOnly']
         | 
| 147 | 
            +
                    end
         | 
| 112 148 | 
             
                  end
         | 
| 113 149 | 
             
                end
         | 
| 114 150 | 
             
              end
         | 
| @@ -19,23 +19,19 @@ module RuboCop | |
| 19 19 | 
             
                  #   # good
         | 
| 20 20 | 
             
                  #   describe MyClass do
         | 
| 21 21 | 
             
                  #   end
         | 
| 22 | 
            -
                  class Focus <  | 
| 22 | 
            +
                  class Focus < Base
         | 
| 23 23 | 
             
                    MSG = 'Focused spec found.'
         | 
| 24 24 |  | 
| 25 | 
            -
                    focusable =
         | 
| 26 | 
            -
                      ExampleGroups::GROUPS  +
         | 
| 27 | 
            -
                      ExampleGroups::SKIPPED +
         | 
| 28 | 
            -
                      Examples::EXAMPLES     +
         | 
| 29 | 
            -
                      Examples::SKIPPED      +
         | 
| 30 | 
            -
                      Examples::PENDING
         | 
| 31 | 
            -
             | 
| 32 25 | 
             
                    focused = ExampleGroups::FOCUSED + Examples::FOCUSED
         | 
| 33 26 |  | 
| 34 | 
            -
                     | 
| 27 | 
            +
                    def_node_matcher :focusable_selector?,
         | 
| 28 | 
            +
                                     (ExampleGroups::GROUPS + ExampleGroups::SKIPPED +
         | 
| 29 | 
            +
                                      Examples::EXAMPLES + Examples::SKIPPED +
         | 
| 30 | 
            +
                                      Examples::PENDING).node_pattern_union
         | 
| 35 31 |  | 
| 36 32 | 
             
                    def_node_matcher :metadata, <<-PATTERN
         | 
| 37 | 
            -
                      {(send # | 
| 38 | 
            -
                       (send # | 
| 33 | 
            +
                      {(send #rspec? #focusable_selector? <$(sym :focus) ...>)
         | 
| 34 | 
            +
                       (send #rspec? #focusable_selector? ... (hash <$(pair (sym :focus) true) ...>))}
         | 
| 39 35 | 
             
                    PATTERN
         | 
| 40 36 |  | 
| 41 37 | 
             
                    def_node_matcher :focused_block?, focused.send_pattern
         | 
| @@ -57,20 +57,20 @@ module RuboCop | |
| 57 57 | 
             
                  #   before(:example) do
         | 
| 58 58 | 
             
                  #     # ...
         | 
| 59 59 | 
             
                  #   end
         | 
| 60 | 
            -
                  class HookArgument <  | 
| 60 | 
            +
                  class HookArgument < Base
         | 
| 61 | 
            +
                    extend AutoCorrector
         | 
| 61 62 | 
             
                    include ConfigurableEnforcedStyle
         | 
| 62 63 |  | 
| 63 | 
            -
                    IMPLICIT_MSG = 'Omit the default `%<scope>p` ' | 
| 64 | 
            -
                                   'argument for RSpec hooks.'
         | 
| 64 | 
            +
                    IMPLICIT_MSG = 'Omit the default `%<scope>p` argument for RSpec hooks.'
         | 
| 65 65 | 
             
                    EXPLICIT_MSG = 'Use `%<scope>p` for RSpec hooks.'
         | 
| 66 66 |  | 
| 67 | 
            -
                     | 
| 67 | 
            +
                    def_node_matcher :hook?, Hooks::ALL.node_pattern_union
         | 
| 68 68 |  | 
| 69 69 | 
             
                    def_node_matcher :scoped_hook, <<-PATTERN
         | 
| 70 | 
            -
                      (block $(send _ # | 
| 70 | 
            +
                      (block $(send _ #hook? (sym ${:each :example})) ...)
         | 
| 71 71 | 
             
                    PATTERN
         | 
| 72 72 |  | 
| 73 | 
            -
                    def_node_matcher :unscoped_hook,  | 
| 73 | 
            +
                    def_node_matcher :unscoped_hook, '(block $(send _ #hook?) ...)'
         | 
| 74 74 |  | 
| 75 75 | 
             
                    def on_block(node)
         | 
| 76 76 | 
             
                      hook(node) do |method_send, scope_name|
         | 
| @@ -78,18 +78,11 @@ module RuboCop | |
| 78 78 | 
             
                        return check_implicit(method_send) unless scope_name
         | 
| 79 79 |  | 
| 80 80 | 
             
                        style_detected(scope_name)
         | 
| 81 | 
            -
                         | 
| 82 | 
            -
             | 
| 83 | 
            -
                           | 
| 84 | 
            -
             | 
| 85 | 
            -
             | 
| 86 | 
            -
                    end
         | 
| 87 | 
            -
             | 
| 88 | 
            -
                    def autocorrect(node)
         | 
| 89 | 
            -
                      scope = implicit_style? ? '' : "(#{style.inspect})"
         | 
| 90 | 
            -
             | 
| 91 | 
            -
                      lambda do |corrector|
         | 
| 92 | 
            -
                        corrector.replace(argument_range(node), scope)
         | 
| 81 | 
            +
                        msg = explicit_message(scope_name)
         | 
| 82 | 
            +
                        add_offense(method_send, message: msg) do |corrector|
         | 
| 83 | 
            +
                          scope = implicit_style? ? '' : "(#{style.inspect})"
         | 
| 84 | 
            +
                          corrector.replace(argument_range(method_send), scope)
         | 
| 85 | 
            +
                        end
         | 
| 93 86 | 
             
                      end
         | 
| 94 87 | 
             
                    end
         | 
| 95 88 |  | 
| @@ -99,11 +92,11 @@ module RuboCop | |
| 99 92 | 
             
                      style_detected(:implicit)
         | 
| 100 93 | 
             
                      return if implicit_style?
         | 
| 101 94 |  | 
| 102 | 
            -
                       | 
| 103 | 
            -
             | 
| 104 | 
            -
                         | 
| 105 | 
            -
                         | 
| 106 | 
            -
                       | 
| 95 | 
            +
                      msg = explicit_message(nil)
         | 
| 96 | 
            +
                      add_offense(method_send.loc.selector, message: msg) do |corrector|
         | 
| 97 | 
            +
                        scope = "(#{style.inspect})"
         | 
| 98 | 
            +
                        corrector.replace(argument_range(method_send), scope)
         | 
| 99 | 
            +
                      end
         | 
| 107 100 | 
             
                    end
         | 
| 108 101 |  | 
| 109 102 | 
             
                    def explicit_message(scope)
         | 
| @@ -23,9 +23,8 @@ module RuboCop | |
| 23 23 | 
             
                  #     expect(foo).to be
         | 
| 24 24 | 
             
                  #   end
         | 
| 25 25 | 
             
                  #
         | 
| 26 | 
            -
                  class HooksBeforeExamples <  | 
| 27 | 
            -
                     | 
| 28 | 
            -
                    include RuboCop::RSpec::FinalEndLocation
         | 
| 26 | 
            +
                  class HooksBeforeExamples < Base
         | 
| 27 | 
            +
                    extend AutoCorrector
         | 
| 29 28 |  | 
| 30 29 | 
             
                    MSG = 'Move `%<hook>s` above the examples in the group.'
         | 
| 31 30 |  | 
| @@ -42,17 +41,6 @@ module RuboCop | |
| 42 41 | 
             
                      check_hooks(node.body) if multiline_block?(node.body)
         | 
| 43 42 | 
             
                    end
         | 
| 44 43 |  | 
| 45 | 
            -
                    def autocorrect(node)
         | 
| 46 | 
            -
                      lambda do |corrector|
         | 
| 47 | 
            -
                        first_example = find_first_example(node.parent)
         | 
| 48 | 
            -
                        first_example_pos = first_example.loc.expression
         | 
| 49 | 
            -
                        indent = "\n" + ' ' * first_example.loc.column
         | 
| 50 | 
            -
             | 
| 51 | 
            -
                        corrector.insert_before(first_example_pos, source(node) + indent)
         | 
| 52 | 
            -
                        corrector.remove(node_range_with_surrounding_space(node))
         | 
| 53 | 
            -
                      end
         | 
| 54 | 
            -
                    end
         | 
| 55 | 
            -
             | 
| 56 44 | 
             
                    private
         | 
| 57 45 |  | 
| 58 46 | 
             
                    def multiline_block?(block)
         | 
| @@ -67,10 +55,10 @@ module RuboCop | |
| 67 55 | 
             
                        next if child.sibling_index < first_example.sibling_index
         | 
| 68 56 | 
             
                        next unless hook?(child)
         | 
| 69 57 |  | 
| 70 | 
            -
                         | 
| 71 | 
            -
             | 
| 72 | 
            -
                           | 
| 73 | 
            -
                         | 
| 58 | 
            +
                        msg = format(MSG, hook: child.method_name)
         | 
| 59 | 
            +
                        add_offense(child, message: msg) do |corrector|
         | 
| 60 | 
            +
                          autocorrect(corrector, child, first_example)
         | 
| 61 | 
            +
                        end
         | 
| 74 62 | 
             
                      end
         | 
| 75 63 | 
             
                    end
         | 
| 76 64 |  | 
| @@ -78,17 +66,10 @@ module RuboCop | |
| 78 66 | 
             
                      node.children.find { |sibling| example_or_group?(sibling) }
         | 
| 79 67 | 
             
                    end
         | 
| 80 68 |  | 
| 81 | 
            -
                    def  | 
| 82 | 
            -
                       | 
| 83 | 
            -
             | 
| 84 | 
            -
             | 
| 85 | 
            -
             | 
| 86 | 
            -
                    def source(node)
         | 
| 87 | 
            -
                      node_range(node).source
         | 
| 88 | 
            -
                    end
         | 
| 89 | 
            -
             | 
| 90 | 
            -
                    def node_range(node)
         | 
| 91 | 
            -
                      node.loc.expression.with(end_pos: final_end_location(node).end_pos)
         | 
| 69 | 
            +
                    def autocorrect(corrector, node, first_example)
         | 
| 70 | 
            +
                      RuboCop::RSpec::Corrector::MoveNode.new(
         | 
| 71 | 
            +
                        node, corrector, processed_source
         | 
| 72 | 
            +
                      ).move_before(first_example)
         | 
| 92 73 | 
             
                    end
         | 
| 93 74 | 
             
                  end
         | 
| 94 75 | 
             
                end
         | 
| @@ -16,7 +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 | 
            -
                  class ImplicitBlockExpectation <  | 
| 19 | 
            +
                  class ImplicitBlockExpectation < Base
         | 
| 20 20 | 
             
                    MSG = 'Avoid implicit block expectations.'
         | 
| 21 21 |  | 
| 22 22 | 
             
                    def_node_matcher :lambda?, <<-PATTERN
         | 
| @@ -24,7 +24,8 @@ module RuboCop | |
| 24 24 | 
             
                  #   # good
         | 
| 25 25 | 
             
                  #   it { should be_truthy }
         | 
| 26 26 | 
             
                  #
         | 
| 27 | 
            -
                  class ImplicitExpect <  | 
| 27 | 
            +
                  class ImplicitExpect < Base
         | 
| 28 | 
            +
                    extend AutoCorrector
         | 
| 28 29 | 
             
                    include ConfigurableEnforcedStyle
         | 
| 29 30 |  | 
| 30 31 | 
             
                    MSG = 'Prefer `%<good>s` over `%<bad>s`.'
         | 
| @@ -54,20 +55,11 @@ module RuboCop | |
| 54 55 | 
             
                      else
         | 
| 55 56 | 
             
                        opposite_style_detected
         | 
| 56 57 |  | 
| 57 | 
            -
                         | 
| 58 | 
            -
             | 
| 59 | 
            -
                           | 
| 60 | 
            -
                           | 
| 61 | 
            -
                         | 
| 62 | 
            -
                      end
         | 
| 63 | 
            -
                    end
         | 
| 64 | 
            -
             | 
| 65 | 
            -
                    def autocorrect(node)
         | 
| 66 | 
            -
                      lambda do |corrector|
         | 
| 67 | 
            -
                        offense     = offending_expect(node)
         | 
| 68 | 
            -
                        replacement = replacement_source(offense.source)
         | 
| 69 | 
            -
             | 
| 70 | 
            -
                        corrector.replace(offense, replacement)
         | 
| 58 | 
            +
                        msg = offense_message(expectation_source)
         | 
| 59 | 
            +
                        add_offense(source_range, message: msg) do |corrector|
         | 
| 60 | 
            +
                          replacement = replacement_source(expectation_source)
         | 
| 61 | 
            +
                          corrector.replace(source_range, replacement)
         | 
| 62 | 
            +
                        end
         | 
| 71 63 | 
             
                      end
         | 
| 72 64 | 
             
                    end
         | 
| 73 65 |  |