free_mutant/lib/mutant/matcher/builder.rb
Markus Schirp 3390abc675 Use environment object inside matchers
This will allow to use reporters from matchers avoiding stupid direct
writes to $stderr.

Also it will allow to remove matching from CLI altogether in a phase of
the runner. Allowing to decouple Mutant::Config from VM environment
allowing to serialize it ;)

Step by step. Takes a while.
2014-06-30 13:08:52 +00:00

142 lines
3.1 KiB
Ruby

module Mutant
class Matcher
# Builder for complex matchers
class Builder
include Concord.new(:env), AST::Sexp
# Initalize object
#
# @param [Cache] env
#
# @return [undefined]
#
# @api private
#
def initialize(env)
super
@matchers = []
@subject_ignores = []
@subject_selectors = []
end
# Add a subject ignore
#
# @param [Expression] expression
#
# @return [self]
#
# @api private
#
def add_subject_ignore(expression)
@subject_ignores << expression.matcher(env)
self
end
# Add a subject selector
#
# @param [#call] selector
#
# @return [self]
#
# @api private
#
def add_subject_selector(attribute, value)
@subject_selectors << Morpher.compile(s(:eql, s(:attribute, attribute), s(:static, value)))
self
end
# Add a match expression
#
# @param [Expression] expression
#
# @return [self]
#
# @api private
#
def add_match_expression(expression)
@matchers << expression.matcher(env)
self
end
# Return generated matcher
#
# @return [Mutant::Matcher]
#
# @api private
#
def matcher
if @matchers.empty?
return Matcher::Null.new
end
matcher = Matcher::Chain.build(@matchers)
if predicate
Matcher::Filter.new(matcher, predicate)
else
matcher
end
end
private
# Return subject selector
#
# @return [#call]
# if selector is present
#
# @return [nil]
# otherwise
#
# @api private
#
def subject_selector
Morpher::Evaluator::Predicate::Boolean::Or.new(@subject_selectors) if @subject_selectors.any?
end
# Return predicate
#
# @return [#call]
# if filter is needed
#
# @return [nil]
# othrwise
#
# @api private
#
def predicate
if subject_selector && subject_rejector
Morpher::Evaluator::Predicate::Boolean::And.new([
subject_selector,
Morpher::Evaluator::Predicate::Negation.new(subject_rejector)
])
elsif subject_selector
subject_selector
elsif subject_rejector
Morpher::Evaluator::Predicate::Negation.new(subject_rejector)
else
nil
end
end
# Return subject rejector
#
# @return [#call]
# if there is a subject rejector
#
# @return [nil]
# otherwise
#
# @api private
#
def subject_rejector
rejectors = @subject_ignores.flat_map(&:to_a).map do |subject|
Morpher.compile(s(:eql, s(:attribute, :identification), s(:static, subject.identification)))
end
Morpher::Evaluator::Predicate::Boolean::Or.new(rejectors) if rejectors.any?
end
end # Builder
end # Matcher
end # Mutant