Skip to content

Commit

Permalink
Reduce matcher interface
Browse files Browse the repository at this point in the history
* New primary interface #call makes specs and implementations much
  easier
* We had #each mostly for historical reasons that are not relevant
  anymore
* Mutation covers the Mutant::Matcher namespace
  • Loading branch information
mbj committed Oct 28, 2015
1 parent db71d01 commit 9d5f379
Show file tree
Hide file tree
Showing 38 changed files with 728 additions and 679 deletions.
2 changes: 1 addition & 1 deletion config/flay.yml
@@ -1,3 +1,3 @@
---
threshold: 18
total_score: 1253
total_score: 1234
2 changes: 2 additions & 0 deletions lib/mutant.rb
Expand Up @@ -132,6 +132,7 @@ def self.ci?
require 'mutant/loader'
require 'mutant/context'
require 'mutant/context/scope'
require 'mutant/scope'
require 'mutant/subject'
require 'mutant/subject/method'
require 'mutant/subject/method/instance'
Expand All @@ -148,6 +149,7 @@ def self.ci?
require 'mutant/matcher/scope'
require 'mutant/matcher/filter'
require 'mutant/matcher/null'
require 'mutant/matcher/static'
require 'mutant/expression'
require 'mutant/expression/parser'
require 'mutant/expression/method'
Expand Down
12 changes: 6 additions & 6 deletions lib/mutant/env/bootstrap.rb
Expand Up @@ -84,7 +84,7 @@ def env
def scope_name(scope)
scope.name
rescue => exception
warn("#{scope.class}#name from: #{scope.inspect} raised an error: #{exception.inspect}. #{SEMANTICS_MESSAGE}")
warn("#{scope.class}#name from: #{scope} raised an error: #{exception.inspect}. #{SEMANTICS_MESSAGE}")
nil
end

Expand All @@ -95,7 +95,7 @@ def scope_name(scope)
# @api private
def infect
config.includes.each(&$LOAD_PATH.method(:<<))
config.requires.each(&method(:require))
config.requires.each(&Kernel.method(:require))
@integration = config.integration.new(config).setup
end

Expand All @@ -105,7 +105,7 @@ def infect
#
# @api private
def matched_subjects
Matcher::Compiler.call(self, config.matcher).to_a
Matcher::Compiler.call(config.matcher).call(self)
end

# Initialize matchable scopes
Expand All @@ -115,8 +115,8 @@ def matched_subjects
# @api private
def initialize_matchable_scopes
scopes = ObjectSpace.each_object(Module).each_with_object([]) do |scope, aggregate|
expression = expression(scope)
aggregate << Matcher::Scope.new(self, scope, expression) if expression
expression = expression(scope) || next
aggregate << Scope.new(scope, expression)
end

@matchable_scopes = scopes.sort_by { |scope| scope.expression.syntax }
Expand All @@ -137,7 +137,7 @@ def expression(scope)
name = scope_name(scope) or return

unless name.instance_of?(String)
warn("#{scope.class}#name from: #{scope.inspect} returned #{name.inspect}. #{SEMANTICS_MESSAGE}")
warn("#{scope.class}#name from: #{scope} returned #{name}. #{SEMANTICS_MESSAGE}")
return
end

Expand Down
8 changes: 3 additions & 5 deletions lib/mutant/expression/method.rb
Expand Up @@ -32,15 +32,13 @@ def syntax

# Matcher for expression
#
# @param [Env] env
#
# @return [Matcher]
#
# @api private
def matcher(env)
methods_matcher = MATCHERS.fetch(scope_symbol).new(env, scope)
def matcher
methods_matcher = MATCHERS.fetch(scope_symbol).new(scope)

Matcher::Filter.build(methods_matcher) { |subject| subject.expression.eql?(self) }
Matcher::Filter.new(methods_matcher, ->(subject) { subject.expression.eql?(self) })
end

private
Expand Down
6 changes: 2 additions & 4 deletions lib/mutant/expression/methods.rb
Expand Up @@ -26,13 +26,11 @@ def syntax

# Matcher on expression
#
# @param [Env] env
#
# @return [Matcher::Method]
#
# @api private
def matcher(env)
MATCHERS.fetch(scope_symbol).new(env, scope)
def matcher
MATCHERS.fetch(scope_symbol).new(scope)
end

# Length of match with other expression
Expand Down
12 changes: 4 additions & 8 deletions lib/mutant/expression/namespace.rb
Expand Up @@ -35,13 +35,11 @@ def syntax

# Matcher for expression
#
# @param [Env::Bootstrap] env
#
# @return [Matcher]
#
# @api private
def matcher(env)
Matcher::Namespace.new(env, self)
def matcher
Matcher::Namespace.new(self)
end

# Length of match with other expression
Expand Down Expand Up @@ -71,13 +69,11 @@ class Exact < self

# Matcher matcher on expression
#
# @param [Env::Bootstrap] env
#
# @return [Matcher]
#
# @api private
def matcher(env)
Matcher::Scope.new(env, Object.const_get(scope_name), self)
def matcher
Matcher::Scope.new(Object.const_get(scope_name))
end

# Syntax for expression
Expand Down
21 changes: 3 additions & 18 deletions lib/mutant/matcher.rb
@@ -1,30 +1,15 @@
module Mutant
# Abstract matcher to find subjects to mutate
class Matcher
include Adamantium::Flat, Enumerable, AbstractType
include Adamantium::Flat, AbstractType

# Default matcher build implementation
# Call matcher
#
# @param [Env] env
# @param [Object] input
#
# @return [undefined]
#
# @api private
def self.build(*arguments)
new(*arguments)
end

# Enumerate subjects
#
# @return [self]
# if block given
#
# @return [Enumerable<Subject>]
# otherwise
#
# @api private
abstract_method :each
abstract_method :call

end # Matcher
end # Mutant
20 changes: 7 additions & 13 deletions lib/mutant/matcher/chain.rb
@@ -1,26 +1,20 @@
module Mutant
class Matcher
# A chain of matchers
# Matcher chaining results of other matchers together
class Chain < self
include Concord.new(:matchers)

# Enumerate subjects
# Call matcher
#
# @return [Enumerator<Subject]
# if no block given
# @param [Env] env
#
# @return [self]
# otherwise
# @return [Enumerable<Subject>]
#
# @api private
def each(&block)
return to_enum unless block_given?

matchers.each do |matcher|
matcher.each(&block)
def call(env)
matchers.flat_map do |matcher|
matcher.call(env)
end

self
end

end # Chain
Expand Down
15 changes: 2 additions & 13 deletions lib/mutant/matcher/compiler.rb
Expand Up @@ -3,7 +3,7 @@ class Matcher

# Compiler for complex matchers
class Compiler
include Concord.new(:env, :config), AST::Sexp, Procto.call(:result)
include Concord.new(:config), AST::Sexp, Procto.call(:result)

# Generated matcher
#
Expand All @@ -12,7 +12,7 @@ class Compiler
# @api private
def result
Filter.new(
Chain.build(config.match_expressions.map(&method(:matcher))),
Chain.new(config.match_expressions.map(&:matcher)),
Morpher::Evaluator::Predicate::Boolean::And.new(
[
ignored_subjects,
Expand Down Expand Up @@ -61,17 +61,6 @@ def filtered_subjects
Morpher::Evaluator::Predicate::Boolean::And.new(config.subject_filters)
end

# Matcher for expression on env
#
# @param [Mutant::Expression] expression
#
# @return [Matcher]
#
# @api private
def matcher(expression)
expression.matcher(env)
end

end # Compiler
end # Matcher
end # Mutant
25 changes: 6 additions & 19 deletions lib/mutant/matcher/filter.rb
Expand Up @@ -4,30 +4,17 @@ class Matcher
class Filter < self
include Concord.new(:matcher, :predicate)

# New matcher
#
# @param [Matcher] matcher
#
# @return [Matcher]
#
# @api private
def self.build(matcher, &predicate)
new(matcher, predicate)
end

# Enumerate matches
#
# @return [self]
# if block given
# @param [Env] env
#
# @return [Enumerator<Subject>]
# otherwise
# @return [Enumerable<Subject>]
#
# @api private
def each(&block)
return to_enum unless block_given?
matcher.select(&predicate.method(:call)).each(&block)
self
def call(env)
matcher
.call(env)
.select(&predicate.method(:call))
end

end # Filter
Expand Down

0 comments on commit 9d5f379

Please sign in to comment.