2012-08-19 15:29:11 -04:00
|
|
|
module Zombie
|
2012-08-29 07:38:40 -04:00
|
|
|
# Setup zombie
|
|
|
|
#
|
|
|
|
# @return [self]
|
|
|
|
#
|
|
|
|
# @api private
|
|
|
|
#
|
2012-08-19 15:29:11 -04:00
|
|
|
def self.setup
|
|
|
|
files.each do |path|
|
|
|
|
path = "#{File.expand_path(path, root)}.rb"
|
|
|
|
ast = File.read(path).to_ast
|
|
|
|
zombify(ast, path)
|
|
|
|
end
|
2012-08-29 07:38:40 -04:00
|
|
|
|
|
|
|
self
|
2012-08-19 15:29:11 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
# Return library root directory
|
|
|
|
#
|
|
|
|
# @return [String]
|
|
|
|
#
|
|
|
|
# @api private
|
|
|
|
#
|
|
|
|
def self.root
|
|
|
|
File.expand_path('../../../lib',__FILE__)
|
|
|
|
end
|
|
|
|
private_class_method :root
|
|
|
|
|
2013-01-04 16:16:03 -05:00
|
|
|
class DummySubject
|
|
|
|
|
|
|
|
# Return line
|
|
|
|
#
|
|
|
|
# @return [Fixnum]
|
|
|
|
#
|
|
|
|
# @api private
|
|
|
|
#
|
|
|
|
attr_reader :source_line
|
|
|
|
|
|
|
|
# Return path
|
|
|
|
#
|
|
|
|
# @return [String]
|
|
|
|
#
|
|
|
|
# @api private
|
|
|
|
#
|
|
|
|
attr_reader :source_path
|
|
|
|
|
|
|
|
private
|
|
|
|
|
|
|
|
# Initialize object
|
|
|
|
#
|
|
|
|
# @param [String] path
|
|
|
|
# @param [Fixnum] line
|
|
|
|
#
|
|
|
|
# @return [undefined]
|
|
|
|
#
|
|
|
|
# @api private
|
|
|
|
#
|
|
|
|
def initialize(path, line)
|
|
|
|
@source_path, @source_line = path, line
|
|
|
|
end
|
|
|
|
end
|
2012-08-19 15:29:11 -04:00
|
|
|
|
|
|
|
# Replace Mutant with Zombie namespace
|
|
|
|
#
|
|
|
|
# @param [Rubinius::AST::Node]
|
|
|
|
#
|
|
|
|
# @api private
|
|
|
|
#
|
|
|
|
# @return [undefined]
|
|
|
|
#
|
|
|
|
def self.zombify(root, path)
|
|
|
|
node = find_mutant(root)
|
|
|
|
unless node
|
|
|
|
raise "unable to find mutant in AST from: #{path.inspect}"
|
|
|
|
end
|
|
|
|
|
|
|
|
name = node.name
|
|
|
|
|
|
|
|
node.name = Rubinius::AST::ModuleName.new(name.line, :Zombie)
|
|
|
|
|
|
|
|
scope = node.body
|
|
|
|
|
|
|
|
unless scope.kind_of?(Rubinius::AST::EmptyBody)
|
|
|
|
node.body = Rubinius::AST::ModuleScope.new(scope.line, node.name, scope.body)
|
|
|
|
end
|
|
|
|
|
2013-01-04 16:16:03 -05:00
|
|
|
::Mutant::Loader::Eval.run(root, DummySubject.new(path, 1))
|
2012-08-19 15:29:11 -04:00
|
|
|
end
|
|
|
|
private_class_method :zombify
|
|
|
|
|
|
|
|
# Find mutant module in AST
|
|
|
|
#
|
|
|
|
# @param [Rubinius::AST::Node]
|
|
|
|
#
|
|
|
|
# @return [Rubinius::AST::Node]
|
|
|
|
#
|
|
|
|
def self.find_mutant(root)
|
|
|
|
if is_mutant?(root)
|
|
|
|
return root
|
|
|
|
end
|
|
|
|
|
|
|
|
unless root.kind_of?(Rubinius::AST::Block)
|
|
|
|
raise "Cannot find mutant in: #{root.class}"
|
|
|
|
end
|
|
|
|
|
|
|
|
root.array.each do |node|
|
|
|
|
return node if is_mutant?(node)
|
|
|
|
end
|
|
|
|
|
|
|
|
nil
|
|
|
|
end
|
|
|
|
private_class_method :find_mutant
|
|
|
|
|
|
|
|
# Test if node is mutant module
|
|
|
|
#
|
|
|
|
# @param [Rubinius::AST::Node]
|
|
|
|
#
|
|
|
|
# @return [true]
|
|
|
|
# returns true if node is the mutant module
|
|
|
|
#
|
|
|
|
# @return [false]
|
|
|
|
# returns false otherwise
|
|
|
|
#
|
|
|
|
# @api private
|
|
|
|
#
|
|
|
|
def self.is_mutant?(node)
|
|
|
|
node.kind_of?(Rubinius::AST::Module) && is_mutant_name?(node.name)
|
|
|
|
end
|
|
|
|
private_class_method :is_mutant?
|
|
|
|
|
|
|
|
# Test if node is mutant module name
|
|
|
|
#
|
|
|
|
# @param [Rubinius::AST::ModuleName]
|
|
|
|
#
|
|
|
|
# @return [true]
|
|
|
|
# returns true if node is the mutant module name
|
|
|
|
#
|
|
|
|
# @return [false]
|
|
|
|
# returns false otherwise
|
|
|
|
#
|
|
|
|
# @api private
|
|
|
|
#
|
|
|
|
def self.is_mutant_name?(node)
|
|
|
|
node.name == :Mutant
|
|
|
|
end
|
|
|
|
private_class_method :is_mutant_name?
|
|
|
|
|
|
|
|
# Return all library files the mutant is made of.
|
|
|
|
#
|
|
|
|
# @return [Array<String>]
|
|
|
|
#
|
|
|
|
# @api private
|
|
|
|
#
|
|
|
|
# FIXME:
|
|
|
|
# Yeah looks very ugly but im currently to exited to do a cleanup.
|
|
|
|
#
|
|
|
|
def self.files
|
2013-01-03 17:40:05 -05:00
|
|
|
block = File.read('lib/mutant.rb').to_ast
|
2012-08-19 15:29:11 -04:00
|
|
|
files = block.array.select do |node|
|
|
|
|
node.class == Rubinius::AST::SendWithArguments &&
|
|
|
|
node.receiver.class == Rubinius::AST::Self &&
|
|
|
|
node.name == :require
|
|
|
|
end.map do |node|
|
|
|
|
arguments = node.arguments.array
|
|
|
|
raise unless arguments.one?
|
|
|
|
argument = arguments.first
|
|
|
|
raise unless argument.class == Rubinius::AST::StringLiteral
|
|
|
|
argument.string
|
|
|
|
end.select do |file|
|
|
|
|
file =~ /\Amutant/
|
|
|
|
end
|
|
|
|
end
|
|
|
|
private_class_method :files
|
|
|
|
end
|