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