class Covered::Source

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

def disable

def disable
	@trace&.disable
	
	super
end

def each(&block)

def each(&block)
	@output.each do |coverage|
		if top = parse(coverage.path)
			self.expand(top, coverage)
		end
		
		yield coverage.freeze
	end
end

def enable

def enable
	super
	
	@trace&.enable
end

def executable?(node)

def executable?(node)
	EXECUTABLE[node.type]
end

def expand(node, coverage, level = 0)

def expand(node, coverage, level = 0)
	if node.is_a? Parser::AST::Node
		if ignore?(node)
			# coverage.annotate(node.location.line, "ignoring #{node.type}")
		else
			if executable?(node)
				# coverage.annotate(node.location.line, "executable #{node.type}")
				coverage.counts[node.location.line] ||= 0
			elsif node.location
				# coverage.annotate(node.location.line, "not executable #{node.type}") rescue nil
			end
			
			if node.type == :send
				# coverage.annotate(node.location.line, "ignoring #{node.type} children")
			end
			
			expand(node.children, coverage, level + 1)
		end
	elsif node.is_a? Array
		node.each do |child|
			expand(child, coverage, level)
		end
	else
		return false
	end
end

def ignore?(node)

def ignore?(node)
	node.nil? || IGNORE[node.type]
end

def initialize(output)

def initialize(output)
	super(output)
	
	@paths = {}
	@mutex = Mutex.new
	
	@annotations = {}
	
	begin
		@trace = TracePoint.new(:script_compiled) do |trace|
			instruction_sequence = trace.instruction_sequence
			# We only track source files which begin at line 1, as these represent whole files instead of monkey patches.
			if instruction_sequence.first_lineno <= 1
				# Extract the source path and source itself and save it for later:
				if path = instruction_sequence.path and source = trace.eval_script
					@mutex.synchronize do
						@paths[path] = source
					end
				end
			end
		end
	rescue
		warn "Script coverage disabled: #{$!}"
		@trace = nil
	end
end

def parse(path)

def parse(path)
	if source = @paths[path]
		Parser::CurrentRuby.parse(source)
	elsif File.exist?(path)
		Parser::CurrentRuby.parse_file(path)
	else
		warn "Couldn't parse #{path}, file doesn't exist?"
	end
rescue
	warn "Couldn't parse #{path}: #{$!}"
end