Class: DeepCover::CoveredCode

Inherits:
Object
  • Object
show all
Defined in:
lib/deep_cover/covered_code.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(path: nil, source: nil, lineno: 1, tracker_global: DEFAULTS[:tracker_global], tracker_storage: TrackerBucket[tracker_global].create_storage, local_var: '_temp') ⇒ CoveredCode

Returns a new instance of CoveredCode.



10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# File 'lib/deep_cover/covered_code.rb', line 10

def initialize(
  path: nil,
  source: nil,
  lineno: 1,
  tracker_global: DEFAULTS[:tracker_global],
  tracker_storage: TrackerBucket[tracker_global].create_storage,
  local_var: '_temp'
)
  raise 'Must provide either path or source' unless path || source

  @path = path &&= Pathname(path)
  @buffer = Parser::Source::Buffer.new('', lineno)
  @buffer.source = source || path.read
  @tracker_count = 0
  @tracker_storage = tracker_storage
  @local_var = local_var
  @covered_source = instrument_source
end

Instance Attribute Details

#bufferObject

Returns the value of attribute buffer.



8
9
10
# File 'lib/deep_cover/covered_code.rb', line 8

def buffer
  @buffer
end

#covered_sourceObject

Returns the value of attribute covered_source.



8
9
10
# File 'lib/deep_cover/covered_code.rb', line 8

def covered_source
  @covered_source
end

#local_varObject

Returns the value of attribute local_var.



8
9
10
# File 'lib/deep_cover/covered_code.rb', line 8

def local_var
  @local_var
end

#pathObject

Returns the value of attribute path.



8
9
10
# File 'lib/deep_cover/covered_code.rb', line 8

def path
  @path
end

#tracker_storageObject

Returns the value of attribute tracker_storage.



8
9
10
# File 'lib/deep_cover/covered_code.rb', line 8

def tracker_storage
  @tracker_storage
end

Instance Method Details

#char_cover(**options) ⇒ Object



61
62
63
# File 'lib/deep_cover/covered_code.rb', line 61

def char_cover(**options)
  Analyser::PerChar.new(self, **options).results
end

#commentsObject



73
74
75
76
# File 'lib/deep_cover/covered_code.rb', line 73

def comments
  root
  @comments
end

#compileObject



102
103
104
# File 'lib/deep_cover/covered_code.rb', line 102

def compile
  RubyVM::InstructionSequence.compile(covered_source, path.to_s, path.to_s)
end

#compile_or_warnObject



106
107
108
109
110
# File 'lib/deep_cover/covered_code.rb', line 106

def compile_or_warn
  warn_instead_of_syntax_error do
    compile
  end
end

#coverObject



53
54
55
# File 'lib/deep_cover/covered_code.rb', line 53

def cover
  global[nb] ||= Array.new(@tracker_count, 0)
end

#covered_astObject



69
70
71
# File 'lib/deep_cover/covered_code.rb', line 69

def covered_ast
  root.main
end

#each_node(*args, &block) ⇒ Object



85
86
87
# File 'lib/deep_cover/covered_code.rb', line 85

def each_node(*args, &block)
  covered_ast.each_node(*args, &block)
end

#execute_code(binding: DeepCover::GLOBAL_BINDING.dup) ⇒ Object



42
43
44
45
# File 'lib/deep_cover/covered_code.rb', line 42

def execute_code(binding: DeepCover::GLOBAL_BINDING.dup)
  eval(@covered_source, binding, (@path || '<raw_code>').to_s, lineno) # rubocop:disable Security/Eval
  self
end

#execute_code_or_warn(*args) ⇒ Object



47
48
49
50
51
# File 'lib/deep_cover/covered_code.rb', line 47

def execute_code_or_warn(*args)
  warn_instead_of_syntax_error do
    execute_code(*args)
  end
end

#freezeObject



112
113
114
115
116
117
118
# File 'lib/deep_cover/covered_code.rb', line 112

def freeze
  unless frozen? # Guard against reentrance
    super
    root.each_node(&:freeze)
  end
  self
end

#inspectObject Also known as: to_s



120
121
122
# File 'lib/deep_cover/covered_code.rb', line 120

def inspect
  %{#<DeepCover::CoveredCode "#{path}">}
end

#instrument_sourceObject



89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/deep_cover/covered_code.rb', line 89

def instrument_source
  rewriter = Parser::Source::TreeRewriter.new(@buffer)
  covered_ast.each_node(:postorder) do |node|
    node.rewriting_rules.each do |range, rule|
      prefix, _node, suffix = rule.partition('%{node}')
      prefix = yield prefix, node, range.begin, :prefix if block_given? && !prefix.empty?
      suffix = yield suffix, node, range.end, :suffix if block_given? && !suffix.empty?
      rewriter.wrap(range, prefix, suffix)
    end
  end
  rewriter.process
end

#line_coverage(**options) ⇒ Object



57
58
59
# File 'lib/deep_cover/covered_code.rb', line 57

def line_coverage(**options)
  Analyser::PerLine.new(self, **options).results
end

#linenoObject



29
30
31
# File 'lib/deep_cover/covered_code.rb', line 29

def lineno
  @buffer.first_line
end

#nb_linesObject



33
34
35
36
37
38
39
40
# File 'lib/deep_cover/covered_code.rb', line 33

def nb_lines
  lines = buffer.source_lines
  if lines.empty?
    0
  else
    lines.size - (lines.last.empty? ? 1 : 0)
  end
end

#rootObject



78
79
80
81
82
83
# File 'lib/deep_cover/covered_code.rb', line 78

def root
  @root ||= begin
    ast, @comments = parser.parse_with_comments(@buffer)
    Node::Root.new(ast, self)
  end
end

#tracker_hits(tracker_id) ⇒ Object



65
66
67
# File 'lib/deep_cover/covered_code.rb', line 65

def tracker_hits(tracker_id)
  cover.fetch(tracker_id)
end

#warn_instead_of_syntax_errorObject

&block



125
126
127
128
129
130
131
132
133
134
# File 'lib/deep_cover/covered_code.rb', line 125

def warn_instead_of_syntax_error # &block
  yield
rescue ::SyntaxError => e
  warn Tools.strip_heredoc(<<-MSG)
      DeepCover is getting confused with the file #{path} and it won't be instrumented.
      Please report this error and provide the source code around the following lines:
      #{e}
  MSG
  nil
end