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