Class: Covered::Source

Inherits:
Wrapper show all
Defined in:
lib/covered/source.rb

Overview

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

Instance Attribute Summary collapse

Attributes inherited from Wrapper

#output

Instance Method Summary collapse

Methods inherited from Wrapper

#accept?, #expand_path, #mark, #relative_path, #to_h

Methods inherited from Base

#accept?, #expand_path, #mark, #relative_path

Constructor Details

#initialize(output) ⇒ Source

Returns a new instance of Source.


29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# File 'lib/covered/source.rb', line 29

def initialize(output)
	super(output)
	
	@paths = {}
	@mutex = Mutex.new
	
	@annotations = {}
	
	begin
		@trace = TracePoint.new(:script_compiled) do |event|
			if path = event.instruction_sequence&.path and source = event.eval_script
				@mutex.synchronize do
					@paths[path] = source
				end
			end
		end
	rescue
		warn "Script coverage disabled: #{$!}"
		@trace = nil
	end
end

Instance Attribute Details

#pathsObject (readonly)

Returns the value of attribute paths


63
64
65
# File 'lib/covered/source.rb', line 63

def paths
  @paths
end

Instance Method Details

#disableObject


57
58
59
60
61
# File 'lib/covered/source.rb', line 57

def disable
	@trace&.disable
	
	super
end

#each(&block) ⇒ Object


108
109
110
111
112
113
114
115
116
# File 'lib/covered/source.rb', line 108

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

#enableObject


51
52
53
54
55
# File 'lib/covered/source.rb', line 51

def enable
	super
	
	@trace&.enable
end

#executable?(node) ⇒ Boolean

Returns:

  • (Boolean)

65
66
67
# File 'lib/covered/source.rb', line 65

def executable?(node)
	node.type == :send
end

#expand(node, coverage, level = 0) ⇒ Object


73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/covered/source.rb', line 73

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.first_lineno, "executable #{node.type}")
				coverage.counts[node.location.line] ||= 0
			else
				# coverage.annotate(node.first_lineno, "not executable #{node.type}")
			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

#ignore?(node) ⇒ Boolean

Returns:

  • (Boolean)

69
70
71
# File 'lib/covered/source.rb', line 69

def ignore?(node)
	node.nil? or node.type == :arg
end

#parse(path) ⇒ Object


96
97
98
99
100
101
102
103
104
105
106
# File 'lib/covered/source.rb', line 96

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