Module: Mutineer::ChangedLines
- Defined in:
- lib/mutineer/changed_lines.rb
Overview
Maps each source file to the set of NEW-side line numbers that changed since a
given git ref, by parsing git diff --unified=0. Used to restrict mutations
to only the diff (issue #2): on a PR you care whether the changed code is
tested, so mutating just those lines is fast and actionable.
git is an external tool, not a gem dependency — shelling out is fine. The pure
parse carries the logic; git_diff is injectable so it stays testable
without invoking git.
Constant Summary collapse
- HUNK =
/^@@ -\d+(?:,\d+)? \+(\d+)(?:,(\d+))? @@/
Class Method Summary collapse
-
.for(ref:, files:, project_root:, runner: method(:git_diff)) ⇒ Object
{ absolute_file_path => Set
} of changed new-side lines per file. -
.git_diff(ref, abs_file, project_root) ⇒ Object
stdout of
git -C <root> diff --unified=0 <ref> -- <file>, "" on failure. -
.parse(diff_text) ⇒ Object
Parse
git diff --unified=0output into the set of NEW-side line numbers added/modified.
Class Method Details
.for(ref:, files:, project_root:, runner: method(:git_diff)) ⇒ Object
{ absolute_file_path => Setrunner is injected so tests can supply canned diff text per file.
39 40 41 42 43 44 |
# File 'lib/mutineer/changed_lines.rb', line 39 def for(ref:, files:, project_root:, runner: method(:git_diff)) files.each_with_object({}) do |file, acc| abs = File.(file, project_root) acc[abs] = parse(runner.call(ref, abs, project_root)) end end |
.git_diff(ref, abs_file, project_root) ⇒ Object
stdout of git -C <root> diff --unified=0 <ref> -- <file>, "" on failure.
47 48 49 50 51 52 53 54 |
# File 'lib/mutineer/changed_lines.rb', line 47 def git_diff(ref, abs_file, project_root) out, _err, status = Open3.capture3( "git", "-C", project_root, "diff", "--unified=0", ref, "--", abs_file ) status.success? ? out : "" rescue StandardError "" end |
.parse(diff_text) ⇒ Object
Parse git diff --unified=0 output into the set of NEW-side line numbers
added/modified. With --unified=0 each hunk's +c,d block is exactly the
changed lines: c..c+d-1. d absent means 1 line; d == 0 is a pure
deletion and contributes nothing.
24 25 26 27 28 29 30 31 32 33 34 35 |
# File 'lib/mutineer/changed_lines.rb', line 24 def parse(diff_text) lines = Set.new diff_text.each_line do |row| m = HUNK.match(row) or next start = m[1].to_i count = m[2].nil? ? 1 : m[2].to_i next if count.zero? lines.merge(start...(start + count)) end lines end |