Module: Canon::Rebaseliner::HeredocRewriter

Defined in:
lib/canon/rebaseliner/heredoc_rewriter.rb

Overview

Replace a heredoc's body in a spec file with new content, preserving the heredoc's opening style (<<~ re-indented, <<-/<< verbatim).

Class Method Summary collapse

Class Method Details

.format_body(new_body, style, terminator_indent) ⇒ Object

Format the new body to fit the heredoc style.

  • :squiggly (<<~): re-indent each line to the terminator column.
  • :dash / :strict: write verbatim (the original code is indentation-sensitive, leave it alone). Always ensures a single trailing newline before the terminator line.


27
28
29
30
31
32
33
34
35
36
37
38
39
# File 'lib/canon/rebaseliner/heredoc_rewriter.rb', line 27

def format_body(new_body, style, terminator_indent)
  normalised = new_body.dup
  normalised << "\n" unless normalised.end_with?("\n")

  case style
  when :squiggly
    indent = " " * (terminator_indent || 0)
    stripped = strip_common_leading_whitespace(normalised)
    stripped.lines.map { |line| line == "\n" ? line : "#{indent}#{line}" }.join
  else
    normalised
  end
end

.rewrite!(spec, new_body) ⇒ void

This method returns an undefined value.

Parameters:

  • spec (HeredocTarget)

    description of the heredoc to rewrite

  • new_body (String)

    new heredoc body (pretty-printed actual); may or may not have a trailing newline; the rewriter normalises.



14
15
16
17
18
19
20
# File 'lib/canon/rebaseliner/heredoc_rewriter.rb', line 14

def rewrite!(spec, new_body)
  body = format_body(new_body, spec.style, spec.terminator_indent)
  new_source = spec.source.byteslice(0, spec.content_start_offset) +
    body +
    spec.source.byteslice(spec.content_end_offset..-1)
  AtomicWriter.write(spec.spec_path, new_source)
end

.strip_common_leading_whitespace(text) ⇒ Object

Remove the largest common leading-whitespace prefix from a multi-line string, mirroring <<~'s own behaviour. Blank lines don't constrain the prefix.



44
45
46
47
48
49
50
51
52
53
# File 'lib/canon/rebaseliner/heredoc_rewriter.rb', line 44

def strip_common_leading_whitespace(text)
  lines = text.lines
  leading = lines
    .reject { |l| l.chomp.empty? }
    .map { |l| l[/\A[ \t]*/].length }
    .min || 0
  return text if leading.zero?

  lines.map { |l| l.chomp.empty? ? l : l[leading..] }.join
end