Class: Testprune::SemanticMap
- Inherits:
-
Object
- Object
- Testprune::SemanticMap
- Defined in:
- lib/testprune/semantic_map.rb
Overview
Parses one source file with Prism and resolves Coverage locations to AST-aware semantic units:
- methods (DefNode) -> "Class#method"
- branch arms (IfNode/CaseNode/…) -> "if then-branch", labelled by the
innermost enclosing control node
- lines collapse to their innermost enclosing method, or a per-file
top-level unit when outside any def — so straight-line code still
contributes a stable unit.
Defined Under Namespace
Instance Attribute Summary collapse
-
#units ⇒ Object
readonly
Returns the value of attribute units.
Class Method Summary collapse
Instance Method Summary collapse
- #add_control(node, type) ⇒ Object
-
#add_method(node, scope, sep) ⇒ Object
Registration callbacks used by the Visitor.
- #branch_unit(type, start_line, start_col, _end_line, _end_col) ⇒ Object
-
#initialize(path, source, relpath) ⇒ SemanticMap
constructor
A new instance of SemanticMap.
- #line_unit(lineno) ⇒ Object
-
#method_unit(start_line, start_col) ⇒ Object
Resolution used when building footprints.
Constructor Details
#initialize(path, source, relpath) ⇒ SemanticMap
Returns a new instance of SemanticMap.
26 27 28 29 30 31 32 33 34 |
# File 'lib/testprune/semantic_map.rb', line 26 def initialize(path, source, relpath) @path = path @relpath = relpath @units = {} # id => Unit @methods_by_pos = {} # [start_line, start_col] => Unit @method_intervals = [] # [start_line, end_line, Unit] @controls = [] # [sl, sc, el, ec, type] Visitor.new(self).visit(Prism.parse(source).value) end |
Instance Attribute Details
#units ⇒ Object (readonly)
Returns the value of attribute units.
24 25 26 |
# File 'lib/testprune/semantic_map.rb', line 24 def units @units end |
Class Method Details
.for_file(path, relpath:) ⇒ Object
17 18 19 20 21 22 |
# File 'lib/testprune/semantic_map.rb', line 17 def self.for_file(path, relpath:) # Read with replacement for invalid/undefined bytes so non-UTF-8 content # (Latin-1 comments, etc.) never raises an encoding error. source = File.read(path, encoding: 'UTF-8:UTF-8', invalid: :replace, undef: :replace) new(path, source, relpath) end |
Instance Method Details
#add_control(node, type) ⇒ Object
51 52 53 54 |
# File 'lib/testprune/semantic_map.rb', line 51 def add_control(node, type) loc = node.location @controls << [loc.start_line, loc.start_column, loc.end_line, loc.end_column, type] end |
#add_method(node, scope, sep) ⇒ Object
Registration callbacks used by the Visitor.
38 39 40 41 42 43 44 45 46 47 48 49 |
# File 'lib/testprune/semantic_map.rb', line 38 def add_method(node, scope, sep) loc = node.location sl = loc.start_line sc = loc.start_column owner = scope.empty? ? '' : "#{scope.join('::')}#{sep}" id = "#{@relpath}#m@#{sl}:#{sc}" unit = Unit.new(id: id, kind: :method, label: "#{owner}#{node.name} (#{@relpath}:#{sl})", file: @relpath, line: sl) @units[id] = unit @methods_by_pos[[sl, sc]] = unit @method_intervals << [sl, loc.end_line, unit] end |
#branch_unit(type, start_line, start_col, _end_line, _end_col) ⇒ Object
62 63 64 65 66 67 68 69 70 |
# File 'lib/testprune/semantic_map.rb', line 62 def branch_unit(type, start_line, start_col, _end_line, _end_col) id = "#{@relpath}#b:#{type}@#{start_line}:#{start_col}" @units[id] ||= begin control_type = innermost_control(start_line, start_col) || type Unit.new(id: id, kind: :branch, label: "#{control_type} #{type}-branch (#{@relpath}:#{start_line})", file: @relpath, line: start_line) end end |
#line_unit(lineno) ⇒ Object
72 73 74 75 76 77 78 79 80 |
# File 'lib/testprune/semantic_map.rb', line 72 def line_unit(lineno) best = nil @method_intervals.each do |sl, el, unit| next unless lineno >= sl && lineno <= el best = unit if best.nil? || sl > best.line end best || toplevel_unit end |
#method_unit(start_line, start_col) ⇒ Object
Resolution used when building footprints.
58 59 60 |
# File 'lib/testprune/semantic_map.rb', line 58 def method_unit(start_line, start_col) @methods_by_pos[[start_line, start_col]] end |