free_mutant/lib/mutant/mutator.rb

143 lines
2.5 KiB
Ruby
Raw Normal View History

module Mutant
# Generator for mutations
class Mutator
2012-11-26 05:30:00 -05:00
include Adamantium::Flat, AbstractType
# Run mutator on input
#
2014-06-09 22:13:15 -04:00
# @param [Object] input
# the input to mutate
#
# @param [Mutator] parent
#
# @return [self]
#
# @api private
2013-12-07 15:11:04 -05:00
def self.each(input, parent = nil, &block)
return to_enum(__method__, input, parent) unless block_given?
REGISTRY.lookup(input).new(input, parent, block)
self
end
# Register node class handler
#
# @return [undefined]
#
# @api private
def self.handle(*types)
types.each do |type|
REGISTRY.register(type, self)
2013-06-04 09:27:16 -04:00
end
end
private_class_method :handle
# Mutation input
#
# @return [Object]
#
# @api private
attr_reader :input
# Parent context of input
#
# @return [Object]
#
# @api private
attr_reader :parent
private
# Initialize object
#
# @param [Object] input
# @param [Object] parent
# @param [#call(node)] block
#
# @return [undefined]
#
# @api private
def initialize(input, parent, block)
@input, @parent, @block = input, parent, block
@seen = Set.new
guard(input)
dispatch
end
# Test if generated object is not guarded from emitting
#
# @param [Object] object
#
2014-06-15 15:27:57 -04:00
# @return [Boolean]
#
# @api private
def new?(object)
!@seen.include?(object)
end
# Add object to guarded values
#
# @param [Object] object
#
# @return [undefined]
#
# @api private
def guard(object)
@seen << object
end
# Dispatch node generations
#
# @return [undefined]
#
# @api private
abstract_method :dispatch
# Emit generated mutation if object is not equivalent to input
#
# @param [Object] object
#
# @return [undefined]
#
# @api private
def emit(object)
return unless new?(object)
guard(object)
emit!(object)
end
# Call block with node
#
# @param [Parser::AST::Node] node
#
# @return [self]
#
# @api private
def emit!(node)
@block.call(node)
self
end
# Run input with mutator
#
# @return [undefined]
#
# @api private
def run(mutator)
mutator.new(input, self, method(:emit))
end
# Shortcut to create a new unfrozen duplicate of input
#
# @return [Object]
#
# @api private
def dup_input
input.dup
end
end # Mutator
end # Mutant