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
| @@ -22,7 +22,7 @@ module RuboCop | |
| 22 22 | 
             
                  #   let(:foo) do
         | 
| 23 23 | 
             
                  #     instance_double("ClassName", method_name: 'returned value')
         | 
| 24 24 | 
             
                  #   end
         | 
| 25 | 
            -
                  class VerifiedDoubles <  | 
| 25 | 
            +
                  class VerifiedDoubles < Base
         | 
| 26 26 | 
             
                    MSG = 'Prefer using verifying doubles over normal doubles.'
         | 
| 27 27 |  | 
| 28 28 | 
             
                    def_node_matcher :unverified_double, <<-PATTERN
         | 
| @@ -11,7 +11,8 @@ module RuboCop | |
| 11 11 | 
             
                  #
         | 
| 12 12 | 
             
                  #   # good
         | 
| 13 13 | 
             
                  #   expect(foo).to be(:bar).and_yield(1)
         | 
| 14 | 
            -
                  class Yield <  | 
| 14 | 
            +
                  class Yield < Base
         | 
| 15 | 
            +
                    extend AutoCorrector
         | 
| 15 16 | 
             
                    include RangeHelp
         | 
| 16 17 |  | 
| 17 18 | 
             
                    MSG = 'Use `.and_yield`.'
         | 
| @@ -27,22 +28,24 @@ module RuboCop | |
| 27 28 |  | 
| 28 29 | 
             
                      block_arg(node.arguments) do |block|
         | 
| 29 30 | 
             
                        if calling_block?(node.body, block)
         | 
| 30 | 
            -
                           | 
| 31 | 
            -
                        end
         | 
| 32 | 
            -
                      end
         | 
| 33 | 
            -
                    end
         | 
| 31 | 
            +
                          range = block_range(node)
         | 
| 34 32 |  | 
| 35 | 
            -
             | 
| 36 | 
            -
             | 
| 37 | 
            -
             | 
| 38 | 
            -
             | 
| 39 | 
            -
                        )
         | 
| 40 | 
            -
                        corrector.replace(node_range, generate_replacement(node.body))
         | 
| 33 | 
            +
                          add_offense(range) do |corrector|
         | 
| 34 | 
            +
                            autocorrect(corrector, node, range)
         | 
| 35 | 
            +
                          end
         | 
| 36 | 
            +
                        end
         | 
| 41 37 | 
             
                      end
         | 
| 42 38 | 
             
                    end
         | 
| 43 39 |  | 
| 44 40 | 
             
                    private
         | 
| 45 41 |  | 
| 42 | 
            +
                    def autocorrect(corrector, node, range)
         | 
| 43 | 
            +
                      corrector.replace(
         | 
| 44 | 
            +
                        range_with_surrounding_space(range: range, side: :left),
         | 
| 45 | 
            +
                        generate_replacement(node.body)
         | 
| 46 | 
            +
                      )
         | 
| 47 | 
            +
                    end
         | 
| 48 | 
            +
             | 
| 46 49 | 
             
                    def calling_block?(node, block)
         | 
| 47 50 | 
             
                      if node.begin_type?
         | 
| 48 51 | 
             
                        node.each_child_node.all? { |child| block_call?(child, block) }
         | 
| @@ -2,6 +2,7 @@ | |
| 2 2 |  | 
| 3 3 | 
             
            require_relative 'rspec/capybara/current_path_expectation'
         | 
| 4 4 | 
             
            require_relative 'rspec/capybara/feature_methods'
         | 
| 5 | 
            +
            require_relative 'rspec/capybara/visibility_matcher'
         | 
| 5 6 |  | 
| 6 7 | 
             
            require_relative 'rspec/factory_bot/attribute_defined_statically'
         | 
| 7 8 | 
             
            require_relative 'rspec/factory_bot/create_list'
         | 
| @@ -9,7 +10,7 @@ require_relative 'rspec/factory_bot/factory_class_name' | |
| 9 10 |  | 
| 10 11 | 
             
            begin
         | 
| 11 12 | 
             
              require_relative 'rspec/rails/http_status'
         | 
| 12 | 
            -
            rescue LoadError | 
| 13 | 
            +
            rescue LoadError
         | 
| 13 14 | 
             
              # Rails/HttpStatus cannot be loaded if rack/utils is unavailable.
         | 
| 14 15 | 
             
            end
         | 
| 15 16 |  | 
| @@ -29,6 +30,7 @@ require_relative 'rspec/described_class' | |
| 29 30 | 
             
            require_relative 'rspec/described_class_module_wrapping'
         | 
| 30 31 | 
             
            require_relative 'rspec/dialect'
         | 
| 31 32 | 
             
            require_relative 'rspec/empty_example_group'
         | 
| 33 | 
            +
            require_relative 'rspec/empty_hook'
         | 
| 32 34 | 
             
            require_relative 'rspec/empty_line_after_example'
         | 
| 33 35 | 
             
            require_relative 'rspec/empty_line_after_example_group'
         | 
| 34 36 | 
             
            require_relative 'rspec/empty_line_after_final_let'
         | 
| @@ -63,6 +65,7 @@ require_relative 'rspec/message_spies' | |
| 63 65 | 
             
            require_relative 'rspec/missing_example_group_argument'
         | 
| 64 66 | 
             
            require_relative 'rspec/multiple_describes'
         | 
| 65 67 | 
             
            require_relative 'rspec/multiple_expectations'
         | 
| 68 | 
            +
            require_relative 'rspec/multiple_memoized_helpers'
         | 
| 66 69 | 
             
            require_relative 'rspec/multiple_subjects'
         | 
| 67 70 | 
             
            require_relative 'rspec/named_subject'
         | 
| 68 71 | 
             
            require_relative 'rspec/nested_groups'
         | 
| @@ -84,6 +87,8 @@ require_relative 'rspec/shared_examples' | |
| 84 87 | 
             
            require_relative 'rspec/single_argument_message_chain'
         | 
| 85 88 | 
             
            require_relative 'rspec/subject_stub'
         | 
| 86 89 | 
             
            require_relative 'rspec/unspecified_exception'
         | 
| 90 | 
            +
            require_relative 'rspec/variable_definition'
         | 
| 91 | 
            +
            require_relative 'rspec/variable_name'
         | 
| 87 92 | 
             
            require_relative 'rspec/verified_doubles'
         | 
| 88 93 | 
             
            require_relative 'rspec/void_expect'
         | 
| 89 94 | 
             
            require_relative 'rspec/yield'
         | 
| @@ -0,0 +1,54 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module RuboCop
         | 
| 4 | 
            +
              module RSpec
         | 
| 5 | 
            +
                module Corrector
         | 
| 6 | 
            +
                  # Helper methods to move a node
         | 
| 7 | 
            +
                  class MoveNode
         | 
| 8 | 
            +
                    include RuboCop::Cop::RangeHelp
         | 
| 9 | 
            +
                    include RuboCop::RSpec::FinalEndLocation
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                    attr_reader :original, :corrector, :processed_source
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                    def initialize(node, corrector, processed_source)
         | 
| 14 | 
            +
                      @original = node
         | 
| 15 | 
            +
                      @corrector = corrector
         | 
| 16 | 
            +
                      @processed_source = processed_source # used by RangeHelp
         | 
| 17 | 
            +
                    end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                    def move_before(other)
         | 
| 20 | 
            +
                      position = other.loc.expression
         | 
| 21 | 
            +
                      indent = ' ' * other.loc.column
         | 
| 22 | 
            +
                      newline_indent = "\n#{indent}"
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                      corrector.insert_before(position, source(original) + newline_indent)
         | 
| 25 | 
            +
                      corrector.remove(node_range_with_surrounding_space(original))
         | 
| 26 | 
            +
                    end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                    def move_after(other)
         | 
| 29 | 
            +
                      position = final_end_location(other)
         | 
| 30 | 
            +
                      indent = ' ' * other.loc.column
         | 
| 31 | 
            +
                      newline_indent = "\n#{indent}"
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                      corrector.insert_after(position, newline_indent + source(original))
         | 
| 34 | 
            +
                      corrector.remove(node_range_with_surrounding_space(original))
         | 
| 35 | 
            +
                    end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                    private
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                    def source(node)
         | 
| 40 | 
            +
                      node_range(node).source
         | 
| 41 | 
            +
                    end
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                    def node_range(node)
         | 
| 44 | 
            +
                      node.loc.expression.with(end_pos: final_end_location(node).end_pos)
         | 
| 45 | 
            +
                    end
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                    def node_range_with_surrounding_space(node)
         | 
| 48 | 
            +
                      range = node_range(node)
         | 
| 49 | 
            +
                      range_by_whole_lines(range, include_final_newline: true)
         | 
| 50 | 
            +
                    end
         | 
| 51 | 
            +
                  end
         | 
| 52 | 
            +
                end
         | 
| 53 | 
            +
              end
         | 
| 54 | 
            +
            end
         | 
| @@ -21,7 +21,7 @@ module RuboCop | |
| 21 21 |  | 
| 22 22 | 
             
                  # Decorator of a YARD code object for working with documented rspec cops
         | 
| 23 23 | 
             
                  class CodeObject
         | 
| 24 | 
            -
                     | 
| 24 | 
            +
                    COP_CLASS_NAME = 'RuboCop::Cop::RSpec::Base'
         | 
| 25 25 | 
             
                    RSPEC_NAMESPACE = 'RuboCop::Cop::RSpec'
         | 
| 26 26 |  | 
| 27 27 | 
             
                    def initialize(yardoc)
         | 
| @@ -68,11 +68,7 @@ module RuboCop | |
| 68 68 | 
             
                    end
         | 
| 69 69 |  | 
| 70 70 | 
             
                    def cop_subclass?
         | 
| 71 | 
            -
                       | 
| 72 | 
            -
                      # RuboCop::Cop::WorkaroundCop are shown as having RuboCop::Cop as
         | 
| 73 | 
            -
                      # superclass, while all the following classes are listed as having
         | 
| 74 | 
            -
                      # RuboCop::Cop::RSpec::Cop as their superclass.
         | 
| 75 | 
            -
                      COP_CLASS_NAMES.include?(yardoc.superclass.path)
         | 
| 71 | 
            +
                      yardoc.superclass.path == COP_CLASS_NAME
         | 
| 76 72 | 
             
                    end
         | 
| 77 73 |  | 
| 78 74 | 
             
                    def abstract?
         | 
| @@ -2,12 +2,23 @@ | |
| 2 2 |  | 
| 3 3 | 
             
            module RuboCop
         | 
| 4 4 | 
             
              module RSpec
         | 
| 5 | 
            -
                # Helps determine the offending location if there is not  | 
| 5 | 
            +
                # Helps determine the offending location if there is not an empty line
         | 
| 6 6 | 
             
                # following the node. Allows comments to follow directly after.
         | 
| 7 | 
            -
                module  | 
| 7 | 
            +
                module EmptyLineSeparation
         | 
| 8 8 | 
             
                  include FinalEndLocation
         | 
| 9 9 | 
             
                  include RuboCop::Cop::RangeHelp
         | 
| 10 10 |  | 
| 11 | 
            +
                  def missing_separating_line_offense(node)
         | 
| 12 | 
            +
                    return if last_child?(node)
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                    missing_separating_line(node) do |location|
         | 
| 15 | 
            +
                      msg = yield(node.method_name)
         | 
| 16 | 
            +
                      add_offense(location, message: msg) do |corrector|
         | 
| 17 | 
            +
                        corrector.insert_after(location.end, "\n")
         | 
| 18 | 
            +
                      end
         | 
| 19 | 
            +
                    end
         | 
| 20 | 
            +
                  end
         | 
| 21 | 
            +
             | 
| 11 22 | 
             
                  def missing_separating_line(node)
         | 
| 12 23 | 
             
                    line = final_end_location(node).line
         | 
| 13 24 |  | 
| @@ -32,14 +43,6 @@ module RuboCop | |
| 32 43 |  | 
| 33 44 | 
             
                    node.equal?(node.parent.children.last)
         | 
| 34 45 | 
             
                  end
         | 
| 35 | 
            -
             | 
| 36 | 
            -
                  def autocorrect(node)
         | 
| 37 | 
            -
                    lambda do |corrector|
         | 
| 38 | 
            -
                      missing_separating_line(node) do |location|
         | 
| 39 | 
            -
                        corrector.insert_after(location.end, "\n")
         | 
| 40 | 
            -
                      end
         | 
| 41 | 
            -
                    end
         | 
| 42 | 
            -
                  end
         | 
| 43 46 | 
             
                end
         | 
| 44 47 | 
             
              end
         | 
| 45 48 | 
             
            end
         | 
| @@ -14,72 +14,44 @@ module RuboCop | |
| 14 14 | 
             
                    ExampleGroups::ALL + SharedGroups::ALL + Includes::ALL
         | 
| 15 15 | 
             
                  ).block_pattern
         | 
| 16 16 |  | 
| 17 | 
            +
                  def lets
         | 
| 18 | 
            +
                    find_all_in_scope(node, :let?)
         | 
| 19 | 
            +
                  end
         | 
| 20 | 
            +
             | 
| 17 21 | 
             
                  def subjects
         | 
| 18 | 
            -
                     | 
| 22 | 
            +
                    find_all_in_scope(node, :subject?)
         | 
| 19 23 | 
             
                  end
         | 
| 20 24 |  | 
| 21 25 | 
             
                  def examples
         | 
| 22 | 
            -
                     | 
| 26 | 
            +
                    find_all_in_scope(node, :example?).map(&Example.public_method(:new))
         | 
| 23 27 | 
             
                  end
         | 
| 24 28 |  | 
| 25 29 | 
             
                  def hooks
         | 
| 26 | 
            -
                     | 
| 30 | 
            +
                    find_all_in_scope(node, :hook?).map(&Hook.public_method(:new))
         | 
| 27 31 | 
             
                  end
         | 
| 28 32 |  | 
| 29 33 | 
             
                  private
         | 
| 30 34 |  | 
| 31 | 
            -
                   | 
| 32 | 
            -
                    node.each_child_node.flat_map do |child|
         | 
| 33 | 
            -
                      find_subjects(child)
         | 
| 34 | 
            -
                    end
         | 
| 35 | 
            -
                  end
         | 
| 36 | 
            -
             | 
| 37 | 
            -
                  def find_subjects(node)
         | 
| 38 | 
            -
                    return [] if scope_change?(node)
         | 
| 39 | 
            -
             | 
| 40 | 
            -
                    if subject?(node)
         | 
| 41 | 
            -
                      [node]
         | 
| 42 | 
            -
                    else
         | 
| 43 | 
            -
                      subjects_in_scope(node)
         | 
| 44 | 
            -
                    end
         | 
| 45 | 
            -
                  end
         | 
| 46 | 
            -
             | 
| 47 | 
            -
                  def hooks_in_scope(node)
         | 
| 48 | 
            -
                    node.each_child_node.flat_map do |child|
         | 
| 49 | 
            -
                      find_hooks(child)
         | 
| 50 | 
            -
                    end
         | 
| 51 | 
            -
                  end
         | 
| 52 | 
            -
             | 
| 53 | 
            -
                  def find_hooks(node)
         | 
| 54 | 
            -
                    return [] if scope_change?(node) || example?(node)
         | 
| 55 | 
            -
             | 
| 56 | 
            -
                    if hook?(node)
         | 
| 57 | 
            -
                      [node]
         | 
| 58 | 
            -
                    else
         | 
| 59 | 
            -
                      hooks_in_scope(node)
         | 
| 60 | 
            -
                    end
         | 
| 61 | 
            -
                  end
         | 
| 62 | 
            -
             | 
| 63 | 
            -
                  def examples_in_scope(node, &blk)
         | 
| 64 | 
            -
                    node.each_child_node.flat_map do |child|
         | 
| 65 | 
            -
                      find_examples(child, &blk)
         | 
| 66 | 
            -
                    end
         | 
| 67 | 
            -
                  end
         | 
| 68 | 
            -
             | 
| 69 | 
            -
                  # Recursively search for examples within the current scope
         | 
| 35 | 
            +
                  # Recursively search for predicate within the current scope
         | 
| 70 36 | 
             
                  #
         | 
| 71 | 
            -
                  # Searches node  | 
| 37 | 
            +
                  # Searches node and halts when a scope change is detected
         | 
| 72 38 | 
             
                  #
         | 
| 73 | 
            -
                  # @param node [RuboCop::Node] node to recursively search | 
| 39 | 
            +
                  # @param node [RuboCop::AST::Node] node to recursively search
         | 
| 74 40 | 
             
                  #
         | 
| 75 | 
            -
                  # @return [Array<RuboCop::Node>] discovered  | 
| 76 | 
            -
                  def  | 
| 77 | 
            -
                     | 
| 41 | 
            +
                  # @return [Array<RuboCop::AST::Node>] discovered nodes
         | 
| 42 | 
            +
                  def find_all_in_scope(node, predicate)
         | 
| 43 | 
            +
                    node.each_child_node.flat_map do |child|
         | 
| 44 | 
            +
                      find_all(child, predicate)
         | 
| 45 | 
            +
                    end
         | 
| 46 | 
            +
                  end
         | 
| 78 47 |  | 
| 79 | 
            -
             | 
| 48 | 
            +
                  def find_all(node, predicate)
         | 
| 49 | 
            +
                    if public_send(predicate, node)
         | 
| 80 50 | 
             
                      [node]
         | 
| 51 | 
            +
                    elsif scope_change?(node) || example?(node)
         | 
| 52 | 
            +
                      []
         | 
| 81 53 | 
             
                    else
         | 
| 82 | 
            -
                       | 
| 54 | 
            +
                      find_all_in_scope(node, predicate)
         | 
| 83 55 | 
             
                    end
         | 
| 84 56 | 
             
                  end
         | 
| 85 57 | 
             
                end
         | 
| @@ -4,7 +4,13 @@ module RuboCop | |
| 4 4 | 
             
              module RSpec
         | 
| 5 5 | 
             
                # RuboCop FactoryBot project namespace
         | 
| 6 6 | 
             
                module FactoryBot
         | 
| 7 | 
            -
                  ATTRIBUTE_DEFINING_METHODS = %i[ | 
| 7 | 
            +
                  ATTRIBUTE_DEFINING_METHODS = %i[
         | 
| 8 | 
            +
                    factory
         | 
| 9 | 
            +
                    ignore
         | 
| 10 | 
            +
                    trait
         | 
| 11 | 
            +
                    traits_for_enum
         | 
| 12 | 
            +
                    transient
         | 
| 13 | 
            +
                  ].freeze
         | 
| 8 14 |  | 
| 9 15 | 
             
                  UNPROXIED_METHODS = %i[
         | 
| 10 16 | 
             
                    __send__
         | 
| @@ -4,8 +4,6 @@ module RuboCop | |
| 4 4 | 
             
              module RSpec
         | 
| 5 5 | 
             
                # RSpec public API methods that are commonly used in cops
         | 
| 6 6 | 
             
                module Language
         | 
| 7 | 
            -
                  RSPEC = '{(const {nil? cbase} :RSpec) nil?}'
         | 
| 8 | 
            -
             | 
| 9 7 | 
             
                  # Set of method selectors
         | 
| 10 8 | 
             
                  class SelectorSet
         | 
| 11 9 | 
             
                    def initialize(selectors)
         | 
| @@ -28,8 +26,20 @@ module RuboCop | |
| 28 26 | 
             
                      "(block #{send_pattern} ...)"
         | 
| 29 27 | 
             
                    end
         | 
| 30 28 |  | 
| 29 | 
            +
                    def block_pass_pattern
         | 
| 30 | 
            +
                      "(send #rspec? #{node_pattern_union} _ block_pass)"
         | 
| 31 | 
            +
                    end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                    def block_or_block_pass_pattern
         | 
| 34 | 
            +
                      "{#{block_pattern} #{block_pass_pattern}}"
         | 
| 35 | 
            +
                    end
         | 
| 36 | 
            +
             | 
| 31 37 | 
             
                    def send_pattern
         | 
| 32 | 
            -
                      "(send # | 
| 38 | 
            +
                      "(send #rspec? #{node_pattern_union} ...)"
         | 
| 39 | 
            +
                    end
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                    def send_or_block_or_block_pass_pattern
         | 
| 42 | 
            +
                      "{#{send_pattern} #{block_pattern} #{block_pass_pattern}}"
         | 
| 33 43 | 
             
                    end
         | 
| 34 44 |  | 
| 35 45 | 
             
                    def node_pattern_union
         | 
| @@ -7,17 +7,26 @@ module RuboCop | |
| 7 7 | 
             
                  module NodePattern
         | 
| 8 8 | 
             
                    extend RuboCop::NodePattern::Macros
         | 
| 9 9 |  | 
| 10 | 
            +
                    def_node_matcher :rspec?, '{(const {nil? cbase} :RSpec) nil?}'
         | 
| 11 | 
            +
             | 
| 10 12 | 
             
                    def_node_matcher :example_group?, ExampleGroups::ALL.block_pattern
         | 
| 13 | 
            +
                    def_node_matcher :shared_group?, SharedGroups::ALL.block_pattern
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                    spec_groups = ExampleGroups::ALL + SharedGroups::ALL
         | 
| 16 | 
            +
                    def_node_matcher :spec_group?, spec_groups.block_pattern
         | 
| 11 17 |  | 
| 12 18 | 
             
                    def_node_matcher :example_group_with_body?, <<-PATTERN
         | 
| 13 | 
            -
                      (block #{ExampleGroups::ALL.send_pattern} args  | 
| 19 | 
            +
                      (block #{ExampleGroups::ALL.send_pattern} args !nil?)
         | 
| 14 20 | 
             
                    PATTERN
         | 
| 15 21 |  | 
| 16 22 | 
             
                    def_node_matcher :example?, Examples::ALL.block_pattern
         | 
| 17 23 |  | 
| 18 24 | 
             
                    def_node_matcher :hook?, Hooks::ALL.block_pattern
         | 
| 19 25 |  | 
| 20 | 
            -
                    def_node_matcher :let?, Helpers::ALL. | 
| 26 | 
            +
                    def_node_matcher :let?, Helpers::ALL.block_or_block_pass_pattern
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                    def_node_matcher :include?,
         | 
| 29 | 
            +
                                     Includes::ALL.send_or_block_or_block_pass_pattern
         | 
| 21 30 |  | 
| 22 31 | 
             
                    def_node_matcher :subject?, Subject::ALL.block_pattern
         | 
| 23 32 | 
             
                  end
         | 
| @@ -16,7 +16,7 @@ module RuboCop | |
| 16 16 | 
             
                  private
         | 
| 17 17 |  | 
| 18 18 | 
             
                  def top_level_describe?(node)
         | 
| 19 | 
            -
                    return false unless node. | 
| 19 | 
            +
                    return false unless node.method?(:describe)
         | 
| 20 20 |  | 
| 21 21 | 
             
                    top_level_nodes.include?(node)
         | 
| 22 22 | 
             
                  end
         | 
| @@ -44,7 +44,7 @@ module RuboCop | |
| 44 44 |  | 
| 45 45 | 
             
                  def describe_statement_children(node)
         | 
| 46 46 | 
             
                    node.each_child_node(:send).select do |element|
         | 
| 47 | 
            -
                      element. | 
| 47 | 
            +
                      element.method?(:describe)
         | 
| 48 48 | 
             
                    end
         | 
| 49 49 | 
             
                  end
         | 
| 50 50 | 
             
                end
         | 
| @@ -0,0 +1,55 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module RuboCop
         | 
| 4 | 
            +
              module RSpec
         | 
| 5 | 
            +
                # Helper methods for top level example group cops
         | 
| 6 | 
            +
                module TopLevelGroup
         | 
| 7 | 
            +
                  extend RuboCop::NodePattern::Macros
         | 
| 8 | 
            +
                  include RuboCop::RSpec::Language
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                  def_node_matcher :example_or_shared_group?,
         | 
| 11 | 
            +
                                   (ExampleGroups::ALL + SharedGroups::ALL).block_pattern
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                  def on_new_investigation
         | 
| 14 | 
            +
                    super
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                    return unless root_node
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                    top_level_groups.each do |node|
         | 
| 19 | 
            +
                      example_group?(node, &method(:on_top_level_example_group))
         | 
| 20 | 
            +
                      on_top_level_group(node)
         | 
| 21 | 
            +
                    end
         | 
| 22 | 
            +
                  end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                  def top_level_groups
         | 
| 25 | 
            +
                    @top_level_groups ||=
         | 
| 26 | 
            +
                      top_level_nodes(root_node).select { |n| example_or_shared_group?(n) }
         | 
| 27 | 
            +
                  end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                  private
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                  # Dummy methods to be overridden in the consumer
         | 
| 32 | 
            +
                  def on_top_level_example_group; end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                  def on_top_level_group; end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                  def top_level_group?(node)
         | 
| 37 | 
            +
                    top_level_groups.include?(node)
         | 
| 38 | 
            +
                  end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                  def top_level_nodes(node)
         | 
| 41 | 
            +
                    if node.begin_type?
         | 
| 42 | 
            +
                      node.children
         | 
| 43 | 
            +
                    elsif node.module_type? || node.class_type?
         | 
| 44 | 
            +
                      top_level_nodes(node.body)
         | 
| 45 | 
            +
                    else
         | 
| 46 | 
            +
                      [node]
         | 
| 47 | 
            +
                    end
         | 
| 48 | 
            +
                  end
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                  def root_node
         | 
| 51 | 
            +
                    processed_source.ast
         | 
| 52 | 
            +
                  end
         | 
| 53 | 
            +
                end
         | 
| 54 | 
            +
              end
         | 
| 55 | 
            +
            end
         |