class Covered::Source

The source map, loads the source file, parses the AST to generate which lines contain executable code.

def disable

def disable
	Eval::disable(self)
	
	super
end

def each(&block)

def each(&block)
	@output.each do |coverage|
		# This is a little bit inefficient, perhaps add a cache layer?
		if top = parse(coverage.path)
			expand(top, coverage.counts)
		end
		
		yield coverage.freeze
	end
end

def enable

def enable
	super
	
	Eval::enable(self)
end

def executable?(node)

def executable?(node)
	node.type =~ @executable
end

def expand(node, counts)

def expand(node, counts)
	# puts "#{node.first_lineno}: #{node.inspect}"
	
	counts[node.first_lineno] ||= 0 if executable?(node)
	
	node.children.each do |child|
		next if child.nil? or ignore?(child)
		
		expand(child, counts)
	end
end

def ignore?(node)

def ignore?(node)
	# NODE_ARGS Ruby doesn't report execution of arguments in :line tracepoint.
	node.type =~ @ignore
end

def initialize(output, executable: EXECUTABLE, ignore: IGNORE)

def initialize(output, executable: EXECUTABLE, ignore: IGNORE)
	super(output)
	
	@paths = {}
	@mutex = Mutex.new
	
	@executable = executable
	@ignore = ignore
end

def intercept_eval(string, binding = nil, filename = nil, lineno = 1)

def intercept_eval(string, binding = nil, filename = nil, lineno = 1)
	return unless filename
	
	# TODO replace with Concurrent::Map
	@mutex.synchronize do
		@paths[filename] = string
	end
end

def parse(path)

def parse(path)
	# puts "Parse #{path}"
	
	if source = @paths[path]
		RubyVM::AST.parse(source)
	elsif File.exist?(path)
		RubyVM::AST.parse_file(path)
	else
		warn "Couldn't parse #{path}, file doesn't exist?"
	end
end