mutant 0.11.18 → 0.11.19
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/lib/mutant/ast/find_metaclass_containing.rb +1 -1
- data/lib/mutant/ast/meta/const.rb +1 -1
- data/lib/mutant/ast/meta/optarg.rb +1 -1
- data/lib/mutant/ast/meta/resbody.rb +1 -1
- data/lib/mutant/ast/meta/send.rb +3 -3
- data/lib/mutant/ast/meta/symbol.rb +1 -1
- data/lib/mutant/ast/types.rb +2 -1311
- data/lib/mutant/bootstrap.rb +2 -2
- data/lib/mutant/cli/command/environment/run.rb +1 -1
- data/lib/mutant/cli/command/environment.rb +1 -3
- data/lib/mutant/cli/command/util.rb +6 -6
- data/lib/mutant/config/coverage_criteria.rb +13 -4
- data/lib/mutant/config.rb +51 -24
- data/lib/mutant/context.rb +1 -6
- data/lib/mutant/env.rb +1 -1
- data/lib/mutant/expression/method.rb +6 -3
- data/lib/mutant/expression/methods.rb +2 -2
- data/lib/mutant/expression/namespace.rb +2 -2
- data/lib/mutant/expression/parser.rb +1 -1
- data/lib/mutant/hooks.rb +4 -4
- data/lib/mutant/isolation/fork.rb +1 -1
- data/lib/mutant/license/subscription/commercial.rb +3 -3
- data/lib/mutant/license/subscription/opensource.rb +5 -9
- data/lib/mutant/license/subscription.rb +1 -1
- data/lib/mutant/matcher/chain.rb +1 -1
- data/lib/mutant/matcher/config.rb +10 -4
- data/lib/mutant/matcher/descendants.rb +1 -1
- data/lib/mutant/matcher/filter.rb +1 -1
- data/lib/mutant/matcher/method/instance.rb +9 -4
- data/lib/mutant/matcher/method/metaclass.rb +4 -17
- data/lib/mutant/matcher/method/singleton.rb +3 -13
- data/lib/mutant/matcher/method.rb +4 -4
- data/lib/mutant/matcher/methods.rb +4 -2
- data/lib/mutant/matcher/namespace.rb +2 -2
- data/lib/mutant/matcher/scope.rb +3 -3
- data/lib/mutant/matcher/static.rb +1 -1
- data/lib/mutant/matcher.rb +2 -2
- data/lib/mutant/meta/example/verification.rb +2 -2
- data/lib/mutant/meta/example.rb +4 -4
- data/lib/mutant/mutation/config.rb +10 -4
- data/lib/mutant/mutation/runner/sink.rb +80 -0
- data/lib/mutant/mutation/runner.rb +61 -0
- data/lib/mutant/mutation.rb +1 -1
- data/lib/mutant/mutator/node/block.rb +2 -2
- data/lib/mutant/mutator/node/define.rb +1 -1
- data/lib/mutant/mutator/node/if.rb +9 -0
- data/lib/mutant/mutator/node/rescue.rb +1 -1
- data/lib/mutant/mutator/node/send.rb +4 -4
- data/lib/mutant/mutator/regexp.rb +2 -2
- data/lib/mutant/parallel/source.rb +1 -1
- data/lib/mutant/pipe.rb +3 -3
- data/lib/mutant/registry.rb +2 -2
- data/lib/mutant/reporter/cli/format.rb +3 -3
- data/lib/mutant/reporter/cli/printer.rb +2 -2
- data/lib/mutant/reporter/cli.rb +4 -4
- data/lib/mutant/reporter/sequence.rb +1 -1
- data/lib/mutant/repository.rb +1 -1
- data/lib/mutant/result.rb +1 -1
- data/lib/mutant/scope.rb +1 -1
- data/lib/mutant/selector/expression.rb +1 -1
- data/lib/mutant/subject.rb +2 -2
- data/lib/mutant/timer.rb +3 -3
- data/lib/mutant/transform.rb +14 -14
- data/lib/mutant/version.rb +1 -1
- data/lib/mutant.rb +13 -11
- metadata +9 -9
- data/lib/mutant/runner/sink.rb +0 -78
- data/lib/mutant/runner.rb +0 -60
    
        data/lib/mutant/bootstrap.rb
    CHANGED
    
    | @@ -51,7 +51,7 @@ module Mutant | |
| 51 51 | 
             
                      env.with(
         | 
| 52 52 | 
             
                        integration: integration,
         | 
| 53 53 | 
             
                        mutations:   mutations,
         | 
| 54 | 
            -
                        selector:    Selector::Expression.new(integration),
         | 
| 54 | 
            +
                        selector:    Selector::Expression.new(integration: integration),
         | 
| 55 55 | 
             
                        subjects:    selected_subjects
         | 
| 56 56 | 
             
                      )
         | 
| 57 57 | 
             
                    end
         | 
| @@ -115,7 +115,7 @@ module Mutant | |
| 115 115 |  | 
| 116 116 | 
             
                    scopes = env.world.object_space.each_object(Module).with_object([]) do |scope, aggregate|
         | 
| 117 117 | 
             
                      expression = expression(config.reporter, config.expression_parser, scope) || next
         | 
| 118 | 
            -
                      aggregate << Scope.new(scope, expression)
         | 
| 118 | 
            +
                      aggregate << Scope.new(raw: scope, expression: expression)
         | 
| 119 119 | 
             
                    end
         | 
| 120 120 |  | 
| 121 121 | 
             
                    scopes.sort_by { |scope| scope.expression.syntax }
         | 
| @@ -105,9 +105,7 @@ module Mutant | |
| 105 105 | 
             
                      parser.on('--since REVISION', 'Only select subjects touched since REVISION') do |revision|
         | 
| 106 106 | 
             
                        add_matcher(
         | 
| 107 107 | 
             
                          :subject_filters,
         | 
| 108 | 
            -
                          Repository::SubjectFilter.new(
         | 
| 109 | 
            -
                            Repository::Diff.new(to: revision, world: world)
         | 
| 110 | 
            -
                          )
         | 
| 108 | 
            +
                          Repository::SubjectFilter.new(diff: Repository::Diff.new(to: revision, world: world))
         | 
| 111 109 | 
             
                        )
         | 
| 112 110 | 
             
                      end
         | 
| 113 111 | 
             
                    end
         | 
| @@ -35,7 +35,7 @@ module Mutant | |
| 35 35 | 
             
                        memoize :node
         | 
| 36 36 |  | 
| 37 37 | 
             
                        class File < self
         | 
| 38 | 
            -
                          include  | 
| 38 | 
            +
                          include Anima.new(:pathname, :source)
         | 
| 39 39 |  | 
| 40 40 | 
             
                          public :source
         | 
| 41 41 |  | 
| @@ -45,7 +45,7 @@ module Mutant | |
| 45 45 | 
             
                        end # File
         | 
| 46 46 |  | 
| 47 47 | 
             
                        class Source < self
         | 
| 48 | 
            -
                          include  | 
| 48 | 
            +
                          include Anima.new(:source)
         | 
| 49 49 |  | 
| 50 50 | 
             
                          def identification
         | 
| 51 51 | 
             
                            '<cli-source>'
         | 
| @@ -62,7 +62,7 @@ module Mutant | |
| 62 62 |  | 
| 63 63 | 
             
                      def add_target_options(parser)
         | 
| 64 64 | 
             
                        parser.on('-e', '--evaluate SOURCE') do |source|
         | 
| 65 | 
            -
                          @targets << Target::Source.new(source)
         | 
| 65 | 
            +
                          @targets << Target::Source.new(source: source)
         | 
| 66 66 | 
             
                        end
         | 
| 67 67 |  | 
| 68 68 | 
             
                        parser.on('-i', '--ignore-pattern AST_PATTERN') do |pattern|
         | 
| @@ -78,8 +78,8 @@ module Mutant | |
| 78 78 | 
             
                          node:   target.node
         | 
| 79 79 | 
             
                        ).each do |mutation|
         | 
| 80 80 | 
             
                          Reporter::CLI::Printer::Mutation.call(
         | 
| 81 | 
            -
                             | 
| 82 | 
            -
                             | 
| 81 | 
            +
                            object: Mutant::Mutation::Evil.new(subject: target, node: mutation),
         | 
| 82 | 
            +
                            output: world.stdout
         | 
| 83 83 | 
             
                          )
         | 
| 84 84 | 
             
                        end
         | 
| 85 85 | 
             
                      end
         | 
| @@ -97,7 +97,7 @@ module Mutant | |
| 97 97 | 
             
                      end
         | 
| 98 98 |  | 
| 99 99 | 
             
                      def read_file(pathname)
         | 
| 100 | 
            -
                        Either::Right.new(Target::File.new(pathname, pathname.read))
         | 
| 100 | 
            +
                        Either::Right.new(Target::File.new(pathname: pathname, source: pathname.read))
         | 
| 101 101 | 
             
                      rescue StandardError => exception
         | 
| 102 102 | 
             
                        Either::Left.new("Cannot read file: #{exception}")
         | 
| 103 103 | 
             
                      end
         | 
| @@ -20,12 +20,21 @@ module Mutant | |
| 20 20 |  | 
| 21 21 | 
             
                  TRANSFORM =
         | 
| 22 22 | 
             
                    Transform::Sequence.new(
         | 
| 23 | 
            -
                      [
         | 
| 23 | 
            +
                      steps: [
         | 
| 24 24 | 
             
                        Transform::Hash.new(
         | 
| 25 25 | 
             
                          optional: [
         | 
| 26 | 
            -
                            Transform::Hash::Key.new( | 
| 27 | 
            -
             | 
| 28 | 
            -
             | 
| 26 | 
            +
                            Transform::Hash::Key.new(
         | 
| 27 | 
            +
                              transform: Transform::BOOLEAN,
         | 
| 28 | 
            +
                              value:     'process_abort'
         | 
| 29 | 
            +
                            ),
         | 
| 30 | 
            +
                            Transform::Hash::Key.new(
         | 
| 31 | 
            +
                              transform: Transform::BOOLEAN,
         | 
| 32 | 
            +
                              value:     'test_result'
         | 
| 33 | 
            +
                            ),
         | 
| 34 | 
            +
                            Transform::Hash::Key.new(
         | 
| 35 | 
            +
                              transform: Transform::BOOLEAN,
         | 
| 36 | 
            +
                              value:     'timeout'
         | 
| 37 | 
            +
                            )
         | 
| 29 38 | 
             
                          ],
         | 
| 30 39 | 
             
                          required: []
         | 
| 31 40 | 
             
                        ),
         | 
    
        data/lib/mutant/config.rb
    CHANGED
    
    | @@ -101,8 +101,8 @@ module Mutant | |
| 101 101 | 
             
                def self.load_contents(env, path)
         | 
| 102 102 | 
             
                  Transform::Named
         | 
| 103 103 | 
             
                    .new(
         | 
| 104 | 
            -
                      path.to_s,
         | 
| 105 | 
            -
                      sequence(env.config.reporter)
         | 
| 104 | 
            +
                      name:      path.to_s,
         | 
| 105 | 
            +
                      transform: sequence(env.config.reporter)
         | 
| 106 106 | 
             
                    )
         | 
| 107 107 | 
             
                    .call(path)
         | 
| 108 108 | 
             
                    .lmap(&:compact_message)
         | 
| @@ -111,11 +111,11 @@ module Mutant | |
| 111 111 |  | 
| 112 112 | 
             
                def self.sequence(reporter)
         | 
| 113 113 | 
             
                  Transform::Sequence.new(
         | 
| 114 | 
            -
                    [
         | 
| 115 | 
            -
                      Transform::Exception.new(SystemCallError, :read.to_proc),
         | 
| 116 | 
            -
                      Transform::Exception.new(YAML::SyntaxError, YAML.public_method(:safe_load)),
         | 
| 117 | 
            -
                      Transform::Primitive.new(Hash),
         | 
| 118 | 
            -
                      Transform::Success.new(->(hash) { deprecations(reporter, hash) }),
         | 
| 114 | 
            +
                    steps: [
         | 
| 115 | 
            +
                      Transform::Exception.new(error_class: SystemCallError,   block: :read.to_proc),
         | 
| 116 | 
            +
                      Transform::Exception.new(error_class: YAML::SyntaxError, block: YAML.public_method(:safe_load)),
         | 
| 117 | 
            +
                      Transform::Primitive.new(primitive: Hash),
         | 
| 118 | 
            +
                      Transform::Success.new(block: ->(hash) { deprecations(reporter, hash) }),
         | 
| 119 119 | 
             
                      *TRANSFORMS
         | 
| 120 120 | 
             
                    ]
         | 
| 121 121 | 
             
                  )
         | 
| @@ -130,10 +130,10 @@ module Mutant | |
| 130 130 | 
             
                end
         | 
| 131 131 |  | 
| 132 132 | 
             
                PATHNAME_ARRAY = Transform::Array.new(
         | 
| 133 | 
            -
                  Transform::Sequence.new(
         | 
| 134 | 
            -
                    [
         | 
| 133 | 
            +
                  transform: Transform::Sequence.new(
         | 
| 134 | 
            +
                    steps: [
         | 
| 135 135 | 
             
                      Transform::STRING,
         | 
| 136 | 
            -
                      Transform::Exception.new(ArgumentError, Pathname.public_method(:new))
         | 
| 136 | 
            +
                      Transform::Exception.new(error_class: ArgumentError, block: Pathname.public_method(:new))
         | 
| 137 137 | 
             
                    ]
         | 
| 138 138 | 
             
                  )
         | 
| 139 139 | 
             
                )
         | 
| @@ -170,24 +170,51 @@ module Mutant | |
| 170 170 | 
             
                TRANSFORMS = [
         | 
| 171 171 | 
             
                  Transform::Hash.new(
         | 
| 172 172 | 
             
                    optional: [
         | 
| 173 | 
            -
                      Transform::Hash::Key.new('coverage_criteria', ->(value) { CoverageCriteria::TRANSFORM.call(value) }),
         | 
| 174 173 | 
             
                      Transform::Hash::Key.new(
         | 
| 175 | 
            -
                         | 
| 176 | 
            -
                         | 
| 177 | 
            -
             | 
| 178 | 
            -
             | 
| 174 | 
            +
                        transform: ->(value) { CoverageCriteria::TRANSFORM.call(value) },
         | 
| 175 | 
            +
                        value:     'coverage_criteria'
         | 
| 176 | 
            +
                      ),
         | 
| 177 | 
            +
                      Transform::Hash::Key.new(
         | 
| 178 | 
            +
                        transform: Transform::Sequence.new(
         | 
| 179 | 
            +
                          steps: [
         | 
| 180 | 
            +
                            Transform::Primitive.new(primitive: Hash),
         | 
| 179 181 | 
             
                            Transform::Block.capture(:environment_variables, &method(:parse_environment_variables))
         | 
| 180 182 | 
             
                          ]
         | 
| 181 | 
            -
                        )
         | 
| 183 | 
            +
                        ),
         | 
| 184 | 
            +
                        value:     'environment_variables'
         | 
| 185 | 
            +
                      ),
         | 
| 186 | 
            +
                      Transform::Hash::Key.new(
         | 
| 187 | 
            +
                        transform: Transform::BOOLEAN,
         | 
| 188 | 
            +
                        value:     'fail_fast'
         | 
| 189 | 
            +
                      ),
         | 
| 190 | 
            +
                      Transform::Hash::Key.new(
         | 
| 191 | 
            +
                        transform: PATHNAME_ARRAY,
         | 
| 192 | 
            +
                        value:     'hooks'
         | 
| 193 | 
            +
                      ),
         | 
| 194 | 
            +
                      Transform::Hash::Key.new(
         | 
| 195 | 
            +
                        transform: Transform::STRING_ARRAY,
         | 
| 196 | 
            +
                        value:     'includes'
         | 
| 182 197 | 
             
                      ),
         | 
| 183 | 
            -
                      Transform::Hash::Key.new( | 
| 184 | 
            -
             | 
| 185 | 
            -
             | 
| 186 | 
            -
                       | 
| 187 | 
            -
                      Transform::Hash::Key.new( | 
| 188 | 
            -
             | 
| 189 | 
            -
             | 
| 190 | 
            -
                       | 
| 198 | 
            +
                      Transform::Hash::Key.new(
         | 
| 199 | 
            +
                        transform: Transform::STRING,
         | 
| 200 | 
            +
                        value:     'integration'
         | 
| 201 | 
            +
                      ),
         | 
| 202 | 
            +
                      Transform::Hash::Key.new(
         | 
| 203 | 
            +
                        transform: Transform::INTEGER,
         | 
| 204 | 
            +
                        value:     'jobs'
         | 
| 205 | 
            +
                      ),
         | 
| 206 | 
            +
                      Transform::Hash::Key.new(
         | 
| 207 | 
            +
                        transform: Matcher::Config::LOADER,
         | 
| 208 | 
            +
                        value:     'matcher'
         | 
| 209 | 
            +
                      ),
         | 
| 210 | 
            +
                      Transform::Hash::Key.new(
         | 
| 211 | 
            +
                        transform: Mutation::Config::TRANSFORM,
         | 
| 212 | 
            +
                        value:     'mutation'
         | 
| 213 | 
            +
                      ),
         | 
| 214 | 
            +
                      Transform::Hash::Key.new(
         | 
| 215 | 
            +
                        transform: Transform::STRING_ARRAY,
         | 
| 216 | 
            +
                        value:     'requires'
         | 
| 217 | 
            +
                      )
         | 
| 191 218 | 
             
                    ],
         | 
| 192 219 | 
             
                    required: []
         | 
| 193 220 | 
             
                  ),
         | 
    
        data/lib/mutant/context.rb
    CHANGED
    
    | @@ -3,7 +3,7 @@ | |
| 3 3 | 
             
            module Mutant
         | 
| 4 4 | 
             
              # An abstract context where mutations can be applied to.
         | 
| 5 5 | 
             
              class Context
         | 
| 6 | 
            -
                include Adamantium,  | 
| 6 | 
            +
                include Adamantium, Anima.new(:scope, :source_path)
         | 
| 7 7 | 
             
                extend AST::Sexp
         | 
| 8 8 |  | 
| 9 9 | 
             
                NAMESPACE_DELIMITER = '::'
         | 
| @@ -74,11 +74,6 @@ module Mutant | |
| 74 74 | 
             
                end
         | 
| 75 75 | 
             
                memoize :match_expressions
         | 
| 76 76 |  | 
| 77 | 
            -
                # Scope wrapped by context
         | 
| 78 | 
            -
                #
         | 
| 79 | 
            -
                # @return [Module|Class]
         | 
| 80 | 
            -
                attr_reader :scope
         | 
| 81 | 
            -
             | 
| 82 77 | 
             
              private
         | 
| 83 78 |  | 
| 84 79 | 
             
                def name_nesting
         | 
    
        data/lib/mutant/env.rb
    CHANGED
    
    
| @@ -41,11 +41,14 @@ module Mutant | |
| 41 41 | 
             
                  # @return [Matcher]
         | 
| 42 42 | 
             
                  def matcher
         | 
| 43 43 | 
             
                    matcher_candidates = MATCHERS.fetch(scope_symbol)
         | 
| 44 | 
            -
                      .map { |submatcher| submatcher.new(scope) }
         | 
| 44 | 
            +
                      .map { |submatcher| submatcher.new(scope: scope) }
         | 
| 45 45 |  | 
| 46 | 
            -
                    methods_matcher = Matcher::Chain.new(matcher_candidates)
         | 
| 46 | 
            +
                    methods_matcher = Matcher::Chain.new(matchers: matcher_candidates)
         | 
| 47 47 |  | 
| 48 | 
            -
                    Matcher::Filter.new( | 
| 48 | 
            +
                    Matcher::Filter.new(
         | 
| 49 | 
            +
                      matcher:   methods_matcher,
         | 
| 50 | 
            +
                      predicate: ->(subject) { subject.expression.eql?(self) }
         | 
| 51 | 
            +
                    )
         | 
| 49 52 | 
             
                  end
         | 
| 50 53 |  | 
| 51 54 | 
             
                  def self.try_parse(input)
         | 
| @@ -36,9 +36,9 @@ module Mutant | |
| 36 36 | 
             
                  # @return [Matcher::Method]
         | 
| 37 37 | 
             
                  def matcher
         | 
| 38 38 | 
             
                    matcher_candidates = MATCHERS.fetch(scope_symbol)
         | 
| 39 | 
            -
                      .map { |submatcher| submatcher.new(scope) }
         | 
| 39 | 
            +
                      .map { |submatcher| submatcher.new(scope: scope) }
         | 
| 40 40 |  | 
| 41 | 
            -
                    Matcher::Chain.new(matcher_candidates)
         | 
| 41 | 
            +
                    Matcher::Chain.new(matchers: matcher_candidates)
         | 
| 42 42 | 
             
                  end
         | 
| 43 43 |  | 
| 44 44 | 
             
                  # Length of match with other expression
         | 
| @@ -35,7 +35,7 @@ module Mutant | |
| 35 35 | 
             
                    #
         | 
| 36 36 | 
             
                    # @return [Matcher]
         | 
| 37 37 | 
             
                    def matcher
         | 
| 38 | 
            -
                      Matcher::Namespace.new(self)
         | 
| 38 | 
            +
                      Matcher::Namespace.new(expression: self)
         | 
| 39 39 | 
             
                    end
         | 
| 40 40 |  | 
| 41 41 | 
             
                    # Length of match with other expression
         | 
| @@ -69,7 +69,7 @@ module Mutant | |
| 69 69 | 
             
                      scope = find_scope
         | 
| 70 70 |  | 
| 71 71 | 
             
                      if scope
         | 
| 72 | 
            -
                        Matcher::Scope.new(scope)
         | 
| 72 | 
            +
                        Matcher::Scope.new(scope: scope)
         | 
| 73 73 | 
             
                      else
         | 
| 74 74 | 
             
                        Matcher::Null.new
         | 
| 75 75 | 
             
                      end
         | 
    
        data/lib/mutant/hooks.rb
    CHANGED
    
    | @@ -2,7 +2,7 @@ | |
| 2 2 |  | 
| 3 3 | 
             
            module Mutant
         | 
| 4 4 | 
             
              class Hooks
         | 
| 5 | 
            -
                include Adamantium,  | 
| 5 | 
            +
                include Adamantium, Anima.new(:map)
         | 
| 6 6 |  | 
| 7 7 | 
             
                DEFAULTS = %i[
         | 
| 8 8 | 
             
                  env_infection_pre
         | 
| @@ -23,12 +23,12 @@ module Mutant | |
| 23 23 | 
             
                end
         | 
| 24 24 |  | 
| 25 25 | 
             
                def self.empty
         | 
| 26 | 
            -
                  new(DEFAULTS)
         | 
| 26 | 
            +
                  new(map: DEFAULTS)
         | 
| 27 27 | 
             
                end
         | 
| 28 28 |  | 
| 29 29 | 
             
                def merge(other)
         | 
| 30 30 | 
             
                  self.class.new(
         | 
| 31 | 
            -
                    other.map.merge(map) { |_key, new, old| (old + new).freeze }.freeze
         | 
| 31 | 
            +
                    map: other.map.merge(map) { |_key, new, old| (old + new).freeze }.freeze
         | 
| 32 32 | 
             
                  )
         | 
| 33 33 | 
             
                end
         | 
| 34 34 |  | 
| @@ -54,7 +54,7 @@ module Mutant | |
| 54 54 | 
             
                  end
         | 
| 55 55 |  | 
| 56 56 | 
             
                  def to_hooks
         | 
| 57 | 
            -
                    Hooks.new(@map.transform_values(&:freeze).freeze)
         | 
| 57 | 
            +
                    Hooks.new(map: @map.transform_values(&:freeze).freeze)
         | 
| 58 58 | 
             
                  end
         | 
| 59 59 | 
             
                end # Builder
         | 
| 60 60 |  | 
| @@ -5,14 +5,14 @@ module Mutant | |
| 5 5 | 
             
                class Subscription
         | 
| 6 6 | 
             
                  class Commercial < self
         | 
| 7 7 | 
             
                    class Author
         | 
| 8 | 
            -
                      include  | 
| 8 | 
            +
                      include Anima.new(:email)
         | 
| 9 9 |  | 
| 10 10 | 
             
                      alias_method :to_s, :email
         | 
| 11 11 | 
             
                      public :to_s
         | 
| 12 12 | 
             
                    end
         | 
| 13 13 |  | 
| 14 14 | 
             
                    def self.from_json(value)
         | 
| 15 | 
            -
                      new(value.fetch('authors'). | 
| 15 | 
            +
                      new(licensed: value.fetch('authors').to_set { |email| Author.new(email: email) })
         | 
| 16 16 | 
             
                    end
         | 
| 17 17 |  | 
| 18 18 | 
             
                    def call(world)
         | 
| @@ -43,7 +43,7 @@ module Mutant | |
| 43 43 | 
             
                      world
         | 
| 44 44 | 
             
                        .capture_stdout(command)
         | 
| 45 45 | 
             
                        .fmap(&:chomp)
         | 
| 46 | 
            -
                        .fmap | 
| 46 | 
            +
                        .fmap { |email| Author.new(email: email) }
         | 
| 47 47 | 
             
                        .fmap { |value| Set.new([value]) }
         | 
| 48 48 | 
             
                        .from_right { Set.new }
         | 
| 49 49 | 
             
                    end
         | 
| @@ -5,7 +5,7 @@ module Mutant | |
| 5 5 | 
             
                class Subscription
         | 
| 6 6 | 
             
                  class Opensource < self
         | 
| 7 7 | 
             
                    class Repository
         | 
| 8 | 
            -
                      include  | 
| 8 | 
            +
                      include Anima.new(:host, :path)
         | 
| 9 9 |  | 
| 10 10 | 
             
                      REMOTE_REGEXP    = /\A[^\t]+\t(?<url>[^ ]+) \((?:fetch|push)\)\n\z/.freeze
         | 
| 11 11 | 
             
                      GIT_SSH_REGEXP   = %r{\A[^@]+@(?<host>[^:/]+)[:/](?<path>.+?)(?:\.git)?\z}.freeze
         | 
| @@ -18,7 +18,8 @@ module Mutant | |
| 18 18 | 
             
                      end
         | 
| 19 19 |  | 
| 20 20 | 
             
                      def self.parse(input)
         | 
| 21 | 
            -
                         | 
| 21 | 
            +
                        host, path = *input.split('/', 2).map(&:downcase)
         | 
| 22 | 
            +
                        new(host: host, path: path)
         | 
| 22 23 | 
             
                      end
         | 
| 23 24 |  | 
| 24 25 | 
             
                      def self.parse_remote(input)
         | 
| @@ -36,7 +37,7 @@ module Mutant | |
| 36 37 | 
             
                          fail "Unmatched git remote URL: #{input.inspect}"
         | 
| 37 38 | 
             
                        end
         | 
| 38 39 |  | 
| 39 | 
            -
                        new(match[:host], match[:path].downcase)
         | 
| 40 | 
            +
                        new(host: match[:host], path: match[:path].downcase)
         | 
| 40 41 | 
             
                      end
         | 
| 41 42 | 
             
                      private_class_method :parse_url
         | 
| 42 43 |  | 
| @@ -52,12 +53,7 @@ module Mutant | |
| 52 53 | 
             
                    end # Opensource
         | 
| 53 54 |  | 
| 54 55 | 
             
                    def self.from_json(value)
         | 
| 55 | 
            -
                      new(
         | 
| 56 | 
            -
                        value
         | 
| 57 | 
            -
                          .fetch('repositories')
         | 
| 58 | 
            -
                          .map(&Repository.public_method(:parse))
         | 
| 59 | 
            -
                          .to_set
         | 
| 60 | 
            -
                      )
         | 
| 56 | 
            +
                      new(licensed: value.fetch('repositories').map(&Repository.public_method(:parse)).to_set)
         | 
| 61 57 | 
             
                    end
         | 
| 62 58 |  | 
| 63 59 | 
             
                    def call(world)
         | 
    
        data/lib/mutant/matcher/chain.rb
    CHANGED
    
    
| @@ -31,15 +31,21 @@ module Mutant | |
| 31 31 | 
             
                    Mutant::Config::DEFAULT.expression_parser.call(input)
         | 
| 32 32 | 
             
                  end
         | 
| 33 33 |  | 
| 34 | 
            -
                  expression_array = Transform::Array.new(expression)
         | 
| 34 | 
            +
                  expression_array = Transform::Array.new(transform: expression)
         | 
| 35 35 |  | 
| 36 36 | 
             
                  LOADER =
         | 
| 37 37 | 
             
                    Transform::Sequence.new(
         | 
| 38 | 
            -
                      [
         | 
| 38 | 
            +
                      steps: [
         | 
| 39 39 | 
             
                        Transform::Hash.new(
         | 
| 40 40 | 
             
                          optional: [
         | 
| 41 | 
            -
                            Transform::Hash::Key.new( | 
| 42 | 
            -
             | 
| 41 | 
            +
                            Transform::Hash::Key.new(
         | 
| 42 | 
            +
                              transform: expression_array,
         | 
| 43 | 
            +
                              value:     'subjects'
         | 
| 44 | 
            +
                            ),
         | 
| 45 | 
            +
                            Transform::Hash::Key.new(
         | 
| 46 | 
            +
                              transform: expression_array,
         | 
| 47 | 
            +
                              value:     'ignore'
         | 
| 48 | 
            +
                            )
         | 
| 43 49 | 
             
                          ],
         | 
| 44 50 | 
             
                          required: []
         | 
| 45 51 | 
             
                        ),
         | 
| @@ -10,7 +10,7 @@ module Mutant | |
| 10 10 | 
             
                    const = env.world.try_const_get(const_name) or return EMPTY_ARRAY
         | 
| 11 11 |  | 
| 12 12 | 
             
                    Chain.new(
         | 
| 13 | 
            -
                      matched_scopes(env, const).map { |scope| Scope.new(scope.raw) }
         | 
| 13 | 
            +
                      matchers: matched_scopes(env, const).map { |scope| Scope.new(scope: scope.raw) }
         | 
| 14 14 | 
             
                    ).call(env)
         | 
| 15 15 | 
             
                  end
         | 
| 16 16 |  | 
| @@ -12,7 +12,9 @@ module Mutant | |
| 12 12 | 
             
                    # @param [UnboundMethod] method
         | 
| 13 13 | 
             
                    #
         | 
| 14 14 | 
             
                    # @return [Matcher::Method::Instance]
         | 
| 15 | 
            -
                     | 
| 15 | 
            +
                    #
         | 
| 16 | 
            +
                    # rubocop:disable Metrics/MethodLength
         | 
| 17 | 
            +
                    def self.new(scope:, target_method:)
         | 
| 16 18 | 
             
                      evaluator =
         | 
| 17 19 | 
             
                        if memoized_method?(scope, target_method.name)
         | 
| 18 20 | 
             
                          Evaluator::Memoized
         | 
| @@ -20,8 +22,13 @@ module Mutant | |
| 20 22 | 
             
                          Evaluator
         | 
| 21 23 | 
             
                        end
         | 
| 22 24 |  | 
| 23 | 
            -
                      super( | 
| 25 | 
            +
                      super(
         | 
| 26 | 
            +
                        evaluator:     evaluator,
         | 
| 27 | 
            +
                        scope:         scope,
         | 
| 28 | 
            +
                        target_method: target_method
         | 
| 29 | 
            +
                      )
         | 
| 24 30 | 
             
                    end
         | 
| 31 | 
            +
                    # rubocop:enable Metrics/MethodLength
         | 
| 25 32 |  | 
| 26 33 | 
             
                    def self.memoized_method?(scope, method_name)
         | 
| 27 34 | 
             
                      scope < Adamantium && scope.memoized?(method_name)
         | 
| @@ -37,8 +44,6 @@ module Mutant | |
| 37 44 | 
             
                    private
         | 
| 38 45 |  | 
| 39 46 | 
             
                      def match?(node)
         | 
| 40 | 
            -
                        n_def?(node)                           &&
         | 
| 41 | 
            -
                        node.location.line.equal?(source_line) &&
         | 
| 42 47 | 
             
                        node.children.fetch(NAME_INDEX).equal?(method_name)
         | 
| 43 48 | 
             
                      end
         | 
| 44 49 |  | 
| @@ -11,12 +11,9 @@ module Mutant | |
| 11 11 |  | 
| 12 12 | 
             
                    # New singleton method matcher
         | 
| 13 13 | 
             
                    #
         | 
| 14 | 
            -
                    # @param [Class, Module] scope
         | 
| 15 | 
            -
                    # @param [Symbol] method_name
         | 
| 16 | 
            -
                    #
         | 
| 17 14 | 
             
                    # @return [Matcher::Method::Singleton]
         | 
| 18 | 
            -
                    def self.new(scope | 
| 19 | 
            -
                      super(scope,  | 
| 15 | 
            +
                    def self.new(scope:, target_method:)
         | 
| 16 | 
            +
                      super(scope: scope, target_method: target_method, evaluator: Evaluator)
         | 
| 20 17 | 
             
                    end
         | 
| 21 18 |  | 
| 22 19 | 
             
                    # Metaclass method evaluator
         | 
| @@ -34,10 +31,7 @@ module Mutant | |
| 34 31 | 
             
                    private
         | 
| 35 32 |  | 
| 36 33 | 
             
                      def match?(node)
         | 
| 37 | 
            -
                         | 
| 38 | 
            -
                          name?(node) &&
         | 
| 39 | 
            -
                          line?(node) &&
         | 
| 40 | 
            -
                          metaclass_receiver?(node)
         | 
| 34 | 
            +
                        name?(node) && metaclass_receiver?(node)
         | 
| 41 35 | 
             
                      end
         | 
| 42 36 |  | 
| 43 37 | 
             
                      def metaclass_receiver?(node)
         | 
| @@ -46,14 +40,7 @@ module Mutant | |
| 46 40 | 
             
                      end
         | 
| 47 41 |  | 
| 48 42 | 
             
                      def metaclass_containing(node)
         | 
| 49 | 
            -
                        AST::FindMetaclassContaining.call(ast, node)
         | 
| 50 | 
            -
                      end
         | 
| 51 | 
            -
             | 
| 52 | 
            -
                      def line?(node)
         | 
| 53 | 
            -
                        node
         | 
| 54 | 
            -
                          .location
         | 
| 55 | 
            -
                          .line
         | 
| 56 | 
            -
                          .equal?(source_line)
         | 
| 43 | 
            +
                        AST::FindMetaclassContaining.call(ast: ast, target: node)
         | 
| 57 44 | 
             
                      end
         | 
| 58 45 |  | 
| 59 46 | 
             
                      def name?(node)
         | 
| @@ -8,12 +8,9 @@ module Mutant | |
| 8 8 |  | 
| 9 9 | 
             
                    # New singleton method matcher
         | 
| 10 10 | 
             
                    #
         | 
| 11 | 
            -
                    # @param [Class, Module] scope
         | 
| 12 | 
            -
                    # @param [Symbol] method_name
         | 
| 13 | 
            -
                    #
         | 
| 14 11 | 
             
                    # @return [Matcher::Method::Singleton]
         | 
| 15 | 
            -
                    def self.new(scope | 
| 16 | 
            -
                      super(scope,  | 
| 12 | 
            +
                    def self.new(scope:, target_method:)
         | 
| 13 | 
            +
                      super(scope: scope, target_method: target_method, evaluator: Evaluator)
         | 
| 17 14 | 
             
                    end
         | 
| 18 15 |  | 
| 19 16 | 
             
                    # Singleton method evaluator
         | 
| @@ -27,14 +24,7 @@ module Mutant | |
| 27 24 | 
             
                    private
         | 
| 28 25 |  | 
| 29 26 | 
             
                      def match?(node)
         | 
| 30 | 
            -
                         | 
| 31 | 
            -
                      end
         | 
| 32 | 
            -
             | 
| 33 | 
            -
                      def line?(node)
         | 
| 34 | 
            -
                        node
         | 
| 35 | 
            -
                          .location
         | 
| 36 | 
            -
                          .line
         | 
| 37 | 
            -
                          .equal?(source_line)
         | 
| 27 | 
            +
                        name?(node) && receiver?(node)
         | 
| 38 28 | 
             
                      end
         | 
| 39 29 |  | 
| 40 30 | 
             
                      def name?(node)
         | 
| @@ -6,7 +6,7 @@ module Mutant | |
| 6 6 | 
             
                class Method < self
         | 
| 7 7 | 
             
                  include AbstractType,
         | 
| 8 8 | 
             
                          Adamantium,
         | 
| 9 | 
            -
                           | 
| 9 | 
            +
                          Anima.new(:scope, :target_method, :evaluator)
         | 
| 10 10 |  | 
| 11 11 | 
             
                  SOURCE_LOCATION_WARNING_FORMAT =
         | 
| 12 12 | 
             
                    '%s does not have a valid source location, unable to emit subject'
         | 
| @@ -20,7 +20,7 @@ module Mutant | |
| 20 20 | 
             
                  #
         | 
| 21 21 | 
             
                  # @return [Enumerable<Subject>]
         | 
| 22 22 | 
             
                  def call(env)
         | 
| 23 | 
            -
                    evaluator.call(scope, target_method, env)
         | 
| 23 | 
            +
                    evaluator.call(scope: scope, target_method: target_method, env: env)
         | 
| 24 24 | 
             
                  end
         | 
| 25 25 |  | 
| 26 26 | 
             
                  # Abstract method match evaluator
         | 
| @@ -32,7 +32,7 @@ module Mutant | |
| 32 32 | 
             
                    include(
         | 
| 33 33 | 
             
                      AbstractType,
         | 
| 34 34 | 
             
                      Adamantium,
         | 
| 35 | 
            -
                       | 
| 35 | 
            +
                      Anima.new(:scope, :target_method, :env),
         | 
| 36 36 | 
             
                      Procto,
         | 
| 37 37 | 
             
                      AST::NodePredicates
         | 
| 38 38 | 
             
                    )
         | 
| @@ -80,7 +80,7 @@ module Mutant | |
| 80 80 | 
             
                    end
         | 
| 81 81 |  | 
| 82 82 | 
             
                    def context
         | 
| 83 | 
            -
                      Context.new(scope, source_path)
         | 
| 83 | 
            +
                      Context.new(scope: scope, source_path: source_path)
         | 
| 84 84 | 
             
                    end
         | 
| 85 85 |  | 
| 86 86 | 
             
                    def ast
         | 
| @@ -4,7 +4,7 @@ module Mutant | |
| 4 4 | 
             
              class Matcher
         | 
| 5 5 | 
             
                # Abstract base class for matcher that returns method subjects from scope
         | 
| 6 6 | 
             
                class Methods < self
         | 
| 7 | 
            -
                  include AbstractType,  | 
| 7 | 
            +
                  include AbstractType, Anima.new(:scope)
         | 
| 8 8 |  | 
| 9 9 | 
             
                  CANDIDATE_NAMES = %i[
         | 
| 10 10 | 
             
                    public_instance_methods
         | 
| @@ -21,7 +21,9 @@ module Mutant | |
| 21 21 | 
             
                  # @return [Enumerable<Subject>]
         | 
| 22 22 | 
             
                  def call(env)
         | 
| 23 23 | 
             
                    Chain.new(
         | 
| 24 | 
            -
                      methods(env).map  | 
| 24 | 
            +
                      matchers: methods(env).map do |target_method|
         | 
| 25 | 
            +
                        matcher.new(scope: scope, target_method: target_method)
         | 
| 26 | 
            +
                      end
         | 
| 25 27 | 
             
                    ).call(env)
         | 
| 26 28 | 
             
                  end
         | 
| 27 29 |  |