mutant 0.8.7 → 0.8.8
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 +5 -0
- data/README.md +64 -3
- data/config/flay.yml +1 -1
- data/lib/mutant.rb +2 -0
- data/lib/mutant/cli.rb +1 -1
- data/lib/mutant/env/bootstrap.rb +36 -8
- data/lib/mutant/expression/method.rb +3 -5
- data/lib/mutant/expression/methods.rb +2 -4
- data/lib/mutant/expression/namespace.rb +4 -8
- data/lib/mutant/matcher.rb +3 -18
- data/lib/mutant/matcher/chain.rb +7 -13
- data/lib/mutant/matcher/compiler.rb +2 -13
- data/lib/mutant/matcher/filter.rb +6 -19
- data/lib/mutant/matcher/method.rb +124 -104
- data/lib/mutant/matcher/method/instance.rb +40 -34
- data/lib/mutant/matcher/method/singleton.rb +80 -61
- data/lib/mutant/matcher/methods.rb +19 -29
- data/lib/mutant/matcher/namespace.rb +22 -16
- data/lib/mutant/matcher/null.rb +4 -7
- data/lib/mutant/matcher/scope.rb +23 -13
- data/lib/mutant/matcher/static.rb +17 -0
- data/lib/mutant/mutation.rb +0 -5
- data/lib/mutant/reporter/cli/format.rb +2 -3
- data/lib/mutant/reporter/cli/printer/env_progress.rb +37 -11
- data/lib/mutant/reporter/cli/printer/status_progressive.rb +1 -1
- data/lib/mutant/scope.rb +6 -0
- data/lib/mutant/subject/method.rb +0 -7
- data/lib/mutant/subject/method/instance.rb +0 -10
- data/lib/mutant/subject/method/singleton.rb +0 -10
- data/lib/mutant/version.rb +1 -1
- data/lib/mutant/zombifier.rb +2 -1
- data/mutant-rspec.gemspec +1 -1
- data/spec/integration/mutant/rspec_spec.rb +1 -1
- data/spec/shared/method_matcher_behavior.rb +21 -14
- data/spec/spec_helper.rb +6 -0
- data/spec/unit/mutant/env/boostrap_spec.rb +88 -26
- data/spec/unit/mutant/env_spec.rb +0 -1
- data/spec/unit/mutant/expression/method_spec.rb +3 -3
- data/spec/unit/mutant/expression/methods_spec.rb +3 -4
- data/spec/unit/mutant/expression/namespace/flat_spec.rb +2 -3
- data/spec/unit/mutant/expression/namespace/recursive_spec.rb +2 -4
- data/spec/unit/mutant/matcher/chain_spec.rb +21 -29
- data/spec/unit/mutant/matcher/compiler/subject_prefix_spec.rb +16 -13
- data/spec/unit/mutant/matcher/compiler_spec.rb +49 -60
- data/spec/unit/mutant/matcher/filter_spec.rb +15 -31
- data/spec/unit/mutant/matcher/method/instance_spec.rb +84 -128
- data/spec/unit/mutant/matcher/method/singleton_spec.rb +48 -52
- data/spec/unit/mutant/matcher/methods/instance_spec.rb +21 -24
- data/spec/unit/mutant/matcher/methods/singleton_spec.rb +18 -21
- data/spec/unit/mutant/matcher/namespace_spec.rb +30 -38
- data/spec/unit/mutant/matcher/null_spec.rb +5 -20
- data/spec/unit/mutant/matcher/scope_spec.rb +33 -0
- data/spec/unit/mutant/matcher/static_spec.rb +11 -0
- data/spec/unit/mutant/mutation_spec.rb +30 -10
- data/spec/unit/mutant/reporter/cli/printer/env_progress_spec.rb +6 -0
- data/spec/unit/mutant/reporter/cli/printer/env_result_spec.rb +2 -0
- data/spec/unit/mutant/reporter/cli/printer/status_spec.rb +10 -0
- data/spec/unit/mutant/reporter/cli_spec.rb +4 -0
- data/spec/unit/mutant/subject/method/instance_spec.rb +0 -28
- data/spec/unit/mutant/subject/method/singleton_spec.rb +0 -28
- data/test_app/Gemfile.rspec3.4 +7 -0
- data/test_app/lib/test_app.rb +16 -12
- data/test_app/lib/test_app/literal.rb +3 -0
- metadata +9 -2
| @@ -3,62 +3,68 @@ module Mutant | |
| 3 3 | 
             
                class Method
         | 
| 4 4 | 
             
                  # Matcher for instance methods
         | 
| 5 5 | 
             
                  class Instance < self
         | 
| 6 | 
            -
                    SUBJECT_CLASS = Subject::Method::Instance
         | 
| 7 6 |  | 
| 8 7 | 
             
                    # Dispatching builder, detects memoizable case
         | 
| 9 8 | 
             
                    #
         | 
| 10 | 
            -
                    # @param [Env::Boostrap] env
         | 
| 11 9 | 
             
                    # @param [Class, Module] scope
         | 
| 12 10 | 
             
                    # @param [UnboundMethod] method
         | 
| 13 11 | 
             
                    #
         | 
| 14 12 | 
             
                    # @return [Matcher::Method::Instance]
         | 
| 15 13 | 
             
                    #
         | 
| 16 14 | 
             
                    # @api private
         | 
| 17 | 
            -
                    def self. | 
| 15 | 
            +
                    def self.new(scope, target_method)
         | 
| 18 16 | 
             
                      name = target_method.name
         | 
| 19 | 
            -
                       | 
| 20 | 
            -
                         | 
| 21 | 
            -
             | 
| 22 | 
            -
             | 
| 23 | 
            -
             | 
| 24 | 
            -
             | 
| 25 | 
            -
                    NAME_INDEX = 0
         | 
| 26 | 
            -
             | 
| 27 | 
            -
                  private
         | 
| 17 | 
            +
                      evaluator =
         | 
| 18 | 
            +
                        if scope.include?(Memoizable) && scope.memoized?(name)
         | 
| 19 | 
            +
                          Evaluator::Memoized
         | 
| 20 | 
            +
                        else
         | 
| 21 | 
            +
                          Evaluator
         | 
| 22 | 
            +
                        end
         | 
| 28 23 |  | 
| 29 | 
            -
             | 
| 30 | 
            -
                    #
         | 
| 31 | 
            -
                    # @param [Parser::AST::Node] node
         | 
| 32 | 
            -
                    #
         | 
| 33 | 
            -
                    # @return [Boolean]
         | 
| 34 | 
            -
                    #
         | 
| 35 | 
            -
                    # @api private
         | 
| 36 | 
            -
                    def match?(node)
         | 
| 37 | 
            -
                      location   = node.location       || return
         | 
| 38 | 
            -
                      expression = location.expression || return
         | 
| 39 | 
            -
             | 
| 40 | 
            -
                      expression.line.equal?(source_line)           &&
         | 
| 41 | 
            -
                      node.type.equal?(:def)                        &&
         | 
| 42 | 
            -
                      node.children[NAME_INDEX].equal?(method_name)
         | 
| 24 | 
            +
                      super(scope, target_method, evaluator)
         | 
| 43 25 | 
             
                    end
         | 
| 44 26 |  | 
| 45 | 
            -
                    #  | 
| 46 | 
            -
                    class  | 
| 47 | 
            -
                      SUBJECT_CLASS = Subject::Method::Instance | 
| 27 | 
            +
                    # Instance method specific evaluator
         | 
| 28 | 
            +
                    class Evaluator < Evaluator
         | 
| 29 | 
            +
                      SUBJECT_CLASS = Subject::Method::Instance
         | 
| 30 | 
            +
                      NAME_INDEX    = 0
         | 
| 48 31 |  | 
| 49 32 | 
             
                    private
         | 
| 50 33 |  | 
| 51 | 
            -
                      #  | 
| 34 | 
            +
                      # Check if node is matched
         | 
| 35 | 
            +
                      #
         | 
| 36 | 
            +
                      # @param [Parser::AST::Node] node
         | 
| 52 37 | 
             
                      #
         | 
| 53 | 
            -
                      # @return [ | 
| 38 | 
            +
                      # @return [Boolean]
         | 
| 54 39 | 
             
                      #
         | 
| 55 40 | 
             
                      # @api private
         | 
| 56 | 
            -
                      def  | 
| 57 | 
            -
                         | 
| 41 | 
            +
                      def match?(node)
         | 
| 42 | 
            +
                        n_def?(node)                           &&
         | 
| 43 | 
            +
                        node.location.line.equal?(source_line) &&
         | 
| 44 | 
            +
                        node.children.fetch(NAME_INDEX).equal?(method_name)
         | 
| 58 45 | 
             
                      end
         | 
| 59 46 |  | 
| 60 | 
            -
             | 
| 47 | 
            +
                      # Evaluator specialized for memoized instance mthods
         | 
| 48 | 
            +
                      class Memoized < self
         | 
| 49 | 
            +
                        SUBJECT_CLASS = Subject::Method::Instance::Memoized
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                      private
         | 
| 52 | 
            +
             | 
| 53 | 
            +
                        # Source location
         | 
| 54 | 
            +
                        #
         | 
| 55 | 
            +
                        # @return [Array{String,Fixnum}]
         | 
| 56 | 
            +
                        #
         | 
| 57 | 
            +
                        # @api private
         | 
| 58 | 
            +
                        def source_location
         | 
| 59 | 
            +
                          scope
         | 
| 60 | 
            +
                            .unmemoized_instance_method(method_name)
         | 
| 61 | 
            +
                            .source_location
         | 
| 62 | 
            +
                        end
         | 
| 63 | 
            +
             | 
| 64 | 
            +
                      end # Memoized
         | 
| 65 | 
            +
                    end # Evaluator
         | 
| 61 66 |  | 
| 67 | 
            +
                    private_constant(*constants(false))
         | 
| 62 68 | 
             
                  end # Instance
         | 
| 63 69 | 
             
                end # Method
         | 
| 64 70 | 
             
              end # Matcher
         | 
| @@ -3,79 +3,98 @@ module Mutant | |
| 3 3 | 
             
                class Method
         | 
| 4 4 | 
             
                  # Matcher for singleton methods
         | 
| 5 5 | 
             
                  class Singleton < self
         | 
| 6 | 
            -
                    SUBJECT_CLASS  = Subject::Method::Singleton
         | 
| 7 | 
            -
                    RECEIVER_INDEX = 0
         | 
| 8 | 
            -
                    NAME_INDEX     = 1
         | 
| 9 6 |  | 
| 10 | 
            -
             | 
| 11 | 
            -
             | 
| 12 | 
            -
                    # Test for node match
         | 
| 7 | 
            +
                    # New singleton method matcher
         | 
| 13 8 | 
             
                    #
         | 
| 14 | 
            -
                    # @param [ | 
| 9 | 
            +
                    # @param [Class, Module] scope
         | 
| 10 | 
            +
                    # @param [Symbol] method_name
         | 
| 15 11 | 
             
                    #
         | 
| 16 | 
            -
                    # @return [ | 
| 12 | 
            +
                    # @return [Matcher::Method::Singleton]
         | 
| 17 13 | 
             
                    #
         | 
| 18 14 | 
             
                    # @api private
         | 
| 19 | 
            -
                    def  | 
| 20 | 
            -
                       | 
| 15 | 
            +
                    def self.new(scope, method_name)
         | 
| 16 | 
            +
                      super(scope, method_name, Evaluator)
         | 
| 21 17 | 
             
                    end
         | 
| 22 18 |  | 
| 23 | 
            -
                    #  | 
| 24 | 
            -
                     | 
| 25 | 
            -
             | 
| 26 | 
            -
             | 
| 27 | 
            -
             | 
| 28 | 
            -
                    #
         | 
| 29 | 
            -
                    # @api private
         | 
| 30 | 
            -
                    def line?(node)
         | 
| 31 | 
            -
                      expression = node.location.expression
         | 
| 32 | 
            -
                      return false unless expression
         | 
| 33 | 
            -
                      expression.line.equal?(source_line)
         | 
| 34 | 
            -
                    end
         | 
| 19 | 
            +
                    # Singleton method evaluator
         | 
| 20 | 
            +
                    class Evaluator < Evaluator
         | 
| 21 | 
            +
                      SUBJECT_CLASS  = Subject::Method::Singleton
         | 
| 22 | 
            +
                      RECEIVER_INDEX = 0
         | 
| 23 | 
            +
                      NAME_INDEX     = 1
         | 
| 35 24 |  | 
| 36 | 
            -
                     | 
| 37 | 
            -
                    #
         | 
| 38 | 
            -
                    # @param [Parser::AST::Node] node
         | 
| 39 | 
            -
                    #
         | 
| 40 | 
            -
                    # @return [Boolean]
         | 
| 41 | 
            -
                    #
         | 
| 42 | 
            -
                    # @api private
         | 
| 43 | 
            -
                    def name?(node)
         | 
| 44 | 
            -
                      node.children[NAME_INDEX].equal?(method_name)
         | 
| 45 | 
            -
                    end
         | 
| 25 | 
            +
                    private
         | 
| 46 26 |  | 
| 47 | 
            -
             | 
| 48 | 
            -
             | 
| 49 | 
            -
             | 
| 50 | 
            -
             | 
| 51 | 
            -
             | 
| 52 | 
            -
             | 
| 53 | 
            -
             | 
| 54 | 
            -
             | 
| 55 | 
            -
             | 
| 56 | 
            -
                      case receiver.type
         | 
| 57 | 
            -
                      when :self
         | 
| 58 | 
            -
                        true
         | 
| 59 | 
            -
                      when :const
         | 
| 60 | 
            -
                        receiver_name?(receiver)
         | 
| 61 | 
            -
                      else
         | 
| 62 | 
            -
                        env.warn(format('Can only match :defs on :self or :const got %s unable to match', receiver.type.inspect))
         | 
| 63 | 
            -
                        false
         | 
| 27 | 
            +
                      # Test for node match
         | 
| 28 | 
            +
                      #
         | 
| 29 | 
            +
                      # @param [Parser::AST::Node] node
         | 
| 30 | 
            +
                      #
         | 
| 31 | 
            +
                      # @return [Boolean]
         | 
| 32 | 
            +
                      #
         | 
| 33 | 
            +
                      # @api private
         | 
| 34 | 
            +
                      def match?(node)
         | 
| 35 | 
            +
                        n_defs?(node) && line?(node) && name?(node) && receiver?(node)
         | 
| 64 36 | 
             
                      end
         | 
| 65 | 
            -
                    end
         | 
| 66 37 |  | 
| 67 | 
            -
             | 
| 68 | 
            -
             | 
| 69 | 
            -
             | 
| 70 | 
            -
             | 
| 71 | 
            -
             | 
| 72 | 
            -
             | 
| 73 | 
            -
             | 
| 74 | 
            -
             | 
| 75 | 
            -
             | 
| 76 | 
            -
             | 
| 77 | 
            -
             | 
| 38 | 
            +
                      # Test for line match
         | 
| 39 | 
            +
                      #
         | 
| 40 | 
            +
                      # @param [Parser::AST::Node] node
         | 
| 41 | 
            +
                      #
         | 
| 42 | 
            +
                      # @return [Boolean]
         | 
| 43 | 
            +
                      #
         | 
| 44 | 
            +
                      # @api private
         | 
| 45 | 
            +
                      def line?(node)
         | 
| 46 | 
            +
                        node
         | 
| 47 | 
            +
                          .location
         | 
| 48 | 
            +
                          .line
         | 
| 49 | 
            +
                          .equal?(source_line)
         | 
| 50 | 
            +
                      end
         | 
| 51 | 
            +
             | 
| 52 | 
            +
                      # Test for name match
         | 
| 53 | 
            +
                      #
         | 
| 54 | 
            +
                      # @param [Parser::AST::Node] node
         | 
| 55 | 
            +
                      #
         | 
| 56 | 
            +
                      # @return [Boolean]
         | 
| 57 | 
            +
                      #
         | 
| 58 | 
            +
                      # @api private
         | 
| 59 | 
            +
                      def name?(node)
         | 
| 60 | 
            +
                        node.children.fetch(NAME_INDEX).equal?(method_name)
         | 
| 61 | 
            +
                      end
         | 
| 62 | 
            +
             | 
| 63 | 
            +
                      # Test for receiver match
         | 
| 64 | 
            +
                      #
         | 
| 65 | 
            +
                      # @param [Parser::AST::Node] node
         | 
| 66 | 
            +
                      #
         | 
| 67 | 
            +
                      # @return [Boolean]
         | 
| 68 | 
            +
                      #
         | 
| 69 | 
            +
                      # @api private
         | 
| 70 | 
            +
                      def receiver?(node)
         | 
| 71 | 
            +
                        receiver = node.children.fetch(RECEIVER_INDEX)
         | 
| 72 | 
            +
                        case receiver.type
         | 
| 73 | 
            +
                        when :self
         | 
| 74 | 
            +
                          true
         | 
| 75 | 
            +
                        when :const
         | 
| 76 | 
            +
                          receiver_name?(receiver)
         | 
| 77 | 
            +
                        else
         | 
| 78 | 
            +
                          env.warn(format('Can only match :defs on :self or :const got %s unable to match', receiver.type.inspect))
         | 
| 79 | 
            +
                          nil
         | 
| 80 | 
            +
                        end
         | 
| 81 | 
            +
                      end
         | 
| 82 | 
            +
             | 
| 83 | 
            +
                      # Test if receiver name matches context
         | 
| 84 | 
            +
                      #
         | 
| 85 | 
            +
                      # @param [Parser::AST::Node] node
         | 
| 86 | 
            +
                      #
         | 
| 87 | 
            +
                      # @return [Boolean]
         | 
| 88 | 
            +
                      #
         | 
| 89 | 
            +
                      # @api private
         | 
| 90 | 
            +
                      def receiver_name?(node)
         | 
| 91 | 
            +
                        name = node.children.fetch(NAME_INDEX)
         | 
| 92 | 
            +
                        name.to_s.eql?(context.unqualified_name)
         | 
| 93 | 
            +
                      end
         | 
| 94 | 
            +
             | 
| 95 | 
            +
                    end # Evaluator
         | 
| 78 96 |  | 
| 97 | 
            +
                    private_constant(*constants(false))
         | 
| 79 98 | 
             
                  end # Singleton
         | 
| 80 99 | 
             
                end # Method
         | 
| 81 100 | 
             
              end # Matcher
         | 
| @@ -2,23 +2,27 @@ module Mutant | |
| 2 2 | 
             
              class Matcher
         | 
| 3 3 | 
             
                # Abstract base class for matcher that returns method subjects from scope
         | 
| 4 4 | 
             
                class Methods < self
         | 
| 5 | 
            -
                  include AbstractType, Concord | 
| 5 | 
            +
                  include AbstractType, Concord.new(:scope)
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                  CANDIDATE_NAMES = IceNine.deep_freeze(%i[
         | 
| 8 | 
            +
                    public_instance_methods
         | 
| 9 | 
            +
                    private_instance_methods
         | 
| 10 | 
            +
                    protected_instance_methods
         | 
| 11 | 
            +
                  ])
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                  private_constant(*constants(false))
         | 
| 6 14 |  | 
| 7 15 | 
             
                  # Enumerate subjects
         | 
| 8 16 | 
             
                  #
         | 
| 9 | 
            -
                  # @ | 
| 10 | 
            -
                  #   if block given
         | 
| 17 | 
            +
                  # @param [Env] env
         | 
| 11 18 | 
             
                  #
         | 
| 12 | 
            -
                  # @return [ | 
| 13 | 
            -
                  #   otherwise
         | 
| 19 | 
            +
                  # @return [Enumerable<Subject>]
         | 
| 14 20 | 
             
                  #
         | 
| 15 21 | 
             
                  # @api private
         | 
| 16 | 
            -
                  def  | 
| 17 | 
            -
                     | 
| 18 | 
            -
             | 
| 19 | 
            -
                     | 
| 20 | 
            -
             | 
| 21 | 
            -
                    self
         | 
| 22 | 
            +
                  def call(env)
         | 
| 23 | 
            +
                    Chain.new(
         | 
| 24 | 
            +
                      methods.map { |method| matcher.new(scope, method) }
         | 
| 25 | 
            +
                    ).call(env)
         | 
| 22 26 | 
             
                  end
         | 
| 23 27 |  | 
| 24 28 | 
             
                private
         | 
| @@ -45,29 +49,16 @@ module Mutant | |
| 45 49 | 
             
                  end
         | 
| 46 50 | 
             
                  memoize :methods
         | 
| 47 51 |  | 
| 48 | 
            -
                  # Subjects detected on scope
         | 
| 49 | 
            -
                  #
         | 
| 50 | 
            -
                  # @return [Array<Subject>]
         | 
| 51 | 
            -
                  #
         | 
| 52 | 
            -
                  # @api private
         | 
| 53 | 
            -
                  def subjects
         | 
| 54 | 
            -
                    methods.map do |method|
         | 
| 55 | 
            -
                      matcher.build(env, scope, method)
         | 
| 56 | 
            -
                    end.flat_map(&:to_a)
         | 
| 57 | 
            -
                  end
         | 
| 58 | 
            -
                  memoize :subjects
         | 
| 59 | 
            -
             | 
| 60 52 | 
             
                  # Candidate method names on target scope
         | 
| 61 53 | 
             
                  #
         | 
| 62 54 | 
             
                  # @return [Enumerable<Symbol>]
         | 
| 63 55 | 
             
                  #
         | 
| 64 56 | 
             
                  # @api private
         | 
| 65 57 | 
             
                  def candidate_names
         | 
| 66 | 
            -
                     | 
| 67 | 
            -
                      candidate_scope. | 
| 68 | 
            -
                       | 
| 69 | 
            -
                       | 
| 70 | 
            -
                    ).sort
         | 
| 58 | 
            +
                    CANDIDATE_NAMES
         | 
| 59 | 
            +
                      .map(&candidate_scope.method(:public_send))
         | 
| 60 | 
            +
                      .reduce(:+)
         | 
| 61 | 
            +
                      .sort
         | 
| 71 62 | 
             
                  end
         | 
| 72 63 |  | 
| 73 64 | 
             
                  # Candidate scope
         | 
| @@ -133,7 +124,6 @@ module Mutant | |
| 133 124 | 
             
                    end
         | 
| 134 125 |  | 
| 135 126 | 
             
                  end # Instance
         | 
| 136 | 
            -
             | 
| 137 127 | 
             
                end # Methods
         | 
| 138 128 | 
             
              end # Matcher
         | 
| 139 129 | 
             
            end # Mutant
         | 
| @@ -1,34 +1,40 @@ | |
| 1 1 | 
             
            module Mutant
         | 
| 2 2 | 
             
              class Matcher
         | 
| 3 | 
            -
             | 
| 4 3 | 
             
                # Matcher for specific namespace
         | 
| 5 4 | 
             
                class Namespace < self
         | 
| 6 | 
            -
                  include Concord::Public.new(: | 
| 5 | 
            +
                  include Concord::Public.new(:expression)
         | 
| 7 6 |  | 
| 8 7 | 
             
                  # Enumerate subjects
         | 
| 9 8 | 
             
                  #
         | 
| 10 | 
            -
                  # @ | 
| 11 | 
            -
                  #   if block given
         | 
| 9 | 
            +
                  # @param [Env] env
         | 
| 12 10 | 
             
                  #
         | 
| 13 | 
            -
                  # @return [ | 
| 14 | 
            -
                  #   otherwise
         | 
| 11 | 
            +
                  # @return [Enumerable<Subject>]
         | 
| 15 12 | 
             
                  #
         | 
| 16 13 | 
             
                  # @api private
         | 
| 17 | 
            -
                  def  | 
| 18 | 
            -
                     | 
| 19 | 
            -
             | 
| 20 | 
            -
                    env | 
| 21 | 
            -
                      scope.each(&block) if match?(scope)
         | 
| 22 | 
            -
                    end
         | 
| 23 | 
            -
             | 
| 24 | 
            -
                    self
         | 
| 14 | 
            +
                  def call(env)
         | 
| 15 | 
            +
                    Chain.new(
         | 
| 16 | 
            +
                      matched_scopes(env).map { |scope| Scope.new(scope.raw) }
         | 
| 17 | 
            +
                    ).call(env)
         | 
| 25 18 | 
             
                  end
         | 
| 26 19 |  | 
| 27 20 | 
             
                private
         | 
| 28 21 |  | 
| 29 | 
            -
                  #  | 
| 22 | 
            +
                  # The matched scopes
         | 
| 23 | 
            +
                  #
         | 
| 24 | 
            +
                  # @param [Env] env
         | 
| 25 | 
            +
                  #
         | 
| 26 | 
            +
                  # @return [Enumerable<Scope>]
         | 
| 27 | 
            +
                  #
         | 
| 28 | 
            +
                  # @api private
         | 
| 29 | 
            +
                  def matched_scopes(env)
         | 
| 30 | 
            +
                    env
         | 
| 31 | 
            +
                      .matchable_scopes
         | 
| 32 | 
            +
                      .select(&method(:match?))
         | 
| 33 | 
            +
                  end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                  # Test scope if matches expression
         | 
| 30 36 | 
             
                  #
         | 
| 31 | 
            -
                  # @param [ | 
| 37 | 
            +
                  # @param [Scope] scope
         | 
| 32 38 | 
             
                  #
         | 
| 33 39 | 
             
                  # @return [Boolean]
         | 
| 34 40 | 
             
                  #
         | 
    
        data/lib/mutant/matcher/null.rb
    CHANGED
    
    | @@ -6,16 +6,13 @@ module Mutant | |
| 6 6 |  | 
| 7 7 | 
             
                  # Enumerate subjects
         | 
| 8 8 | 
             
                  #
         | 
| 9 | 
            -
                  # @ | 
| 10 | 
            -
                  #   if no block given
         | 
| 9 | 
            +
                  # @param [Env] env
         | 
| 11 10 | 
             
                  #
         | 
| 12 | 
            -
                  # @return [ | 
| 13 | 
            -
                  #   otherwise
         | 
| 11 | 
            +
                  # @return [Enumerable<Subject>]
         | 
| 14 12 | 
             
                  #
         | 
| 15 13 | 
             
                  # @api private
         | 
| 16 | 
            -
                  def  | 
| 17 | 
            -
                     | 
| 18 | 
            -
                    self
         | 
| 14 | 
            +
                  def call(_env)
         | 
| 15 | 
            +
                    EMPTY_ARRAY
         | 
| 19 16 | 
             
                  end
         | 
| 20 17 |  | 
| 21 18 | 
             
                end # Null
         | 
    
        data/lib/mutant/matcher/scope.rb
    CHANGED
    
    | @@ -1,31 +1,41 @@ | |
| 1 1 | 
             
            module Mutant
         | 
| 2 2 | 
             
              class Matcher
         | 
| 3 | 
            -
                # Matcher  | 
| 3 | 
            +
                # Matcher expanding Mutant::Scope objects into method matches
         | 
| 4 | 
            +
                # at singleton or instance level
         | 
| 5 | 
            +
                #
         | 
| 6 | 
            +
                # If we *ever* get other subjects than methods, its likely the place
         | 
| 7 | 
            +
                # to hook in custom matchers. In that case the scope matchers to expand
         | 
| 8 | 
            +
                # should be passed as arguments to the constructor.
         | 
| 4 9 | 
             
                class Scope < self
         | 
| 5 | 
            -
                  include Concord | 
| 10 | 
            +
                  include Concord.new(:scope)
         | 
| 6 11 |  | 
| 7 12 | 
             
                  MATCHERS = [
         | 
| 8 13 | 
             
                    Matcher::Methods::Singleton,
         | 
| 9 14 | 
             
                    Matcher::Methods::Instance
         | 
| 10 15 | 
             
                  ].freeze
         | 
| 11 16 |  | 
| 12 | 
            -
                   | 
| 17 | 
            +
                  private_constant(*constants(false))
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                  # Matched subjects
         | 
| 13 20 | 
             
                  #
         | 
| 14 | 
            -
                  # @ | 
| 15 | 
            -
                  #   if block given
         | 
| 21 | 
            +
                  # @param [Env] env
         | 
| 16 22 | 
             
                  #
         | 
| 17 | 
            -
                  # @return [ | 
| 18 | 
            -
                  #   otherwise
         | 
| 23 | 
            +
                  # @return [Enumerable<Subject>]
         | 
| 19 24 | 
             
                  #
         | 
| 20 25 | 
             
                  # @api private
         | 
| 21 | 
            -
                  def  | 
| 22 | 
            -
                     | 
| 26 | 
            +
                  def call(env)
         | 
| 27 | 
            +
                    Chain.new(effective_matchers).call(env)
         | 
| 28 | 
            +
                  end
         | 
| 23 29 |  | 
| 24 | 
            -
             | 
| 25 | 
            -
                      matcher.new(env, scope).each(&block)
         | 
| 26 | 
            -
                    end
         | 
| 30 | 
            +
                private
         | 
| 27 31 |  | 
| 28 | 
            -
             | 
| 32 | 
            +
                  # Effective matchers
         | 
| 33 | 
            +
                  #
         | 
| 34 | 
            +
                  # @return [Enumerable<Matcher>]
         | 
| 35 | 
            +
                  #
         | 
| 36 | 
            +
                  # @api private
         | 
| 37 | 
            +
                  def effective_matchers
         | 
| 38 | 
            +
                    MATCHERS.map { |matcher| matcher.new(scope) }
         | 
| 29 39 | 
             
                  end
         | 
| 30 40 |  | 
| 31 41 | 
             
                end # Scope
         |