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.

Constant Summary collapse

EXECUTABLE =
/(.?CALL|.VAR|.ASGN|DEFN)/.freeze
DOGFOOD =

Deviate from the standard policy above, because all the files are already loaded, so we skip NODE_FCALL.

/(^V?CALL|.VAR|.ASGN|DEFN)/.freeze
IGNORE =

Ruby trace points don’t trigger for argument execution. Constants are loaded when the file loads, so they are less interesting.

/(ARGS|CDECL)/.freeze

Instance Attribute Summary collapse

Attributes inherited from Wrapper

#output

Instance Method Summary collapse

Methods inherited from Wrapper

#expand_path, #mark, #relative_path, #to_h

Constructor Details

#initialize(output, executable: EXECUTABLE, ignore: IGNORE) ⇒ Source

Returns a new instance of Source.



40
41
42
43
44
45
46
47
48
49
50
# File 'lib/covered/source.rb', line 40

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

Instance Attribute Details

#pathsObject (readonly)

Returns the value of attribute paths.



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

def paths
  @paths
end

Instance Method Details

#disableObject



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

def disable
	Eval::disable(self)
	
	super
end

#each(&block) ⇒ Object



117
118
119
120
121
122
123
124
125
# File 'lib/covered/source.rb', line 117

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

#enableObject



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

def enable
	super
	
	Eval::enable(self)
end

#executable?(node) ⇒ Boolean

Returns:

  • (Boolean)


74
75
76
# File 'lib/covered/source.rb', line 74

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

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



82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/covered/source.rb', line 82

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)


78
79
80
# File 'lib/covered/source.rb', line 78

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

#intercept_eval(string, binding = nil, filename = nil, lineno = 1) ⇒ Object



66
67
68
69
70
71
72
# File 'lib/covered/source.rb', line 66

def intercept_eval(string, binding = nil, filename = nil, lineno = 1)
	return unless filename
	
	@mutex.synchronize do
		@paths[filename] = string
	end
end

#parse(path) ⇒ Object



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

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