class RuboCop::Cop::AlignmentCorrector

variable column_delta.
the left or to the right, amount being determined by the instance
This class does auto-correction of nodes that should just be moved to

def align_end(corrector, processed_source, node, align_to)

def align_end(corrector, processed_source, node, align_to)
  @processed_source = processed_source
  whitespace = whitespace_range(node)
  return false unless whitespace.source.strip.empty?
  column = alignment_column(align_to)
  corrector.replace(whitespace, ' ' * column)
end

def alignment_column(align_to)

def alignment_column(align_to)
  if !align_to
    0
  elsif align_to.respond_to?(:loc)
    align_to.source_range.column
  else
    align_to.column
  end
end

def autocorrect_line(corrector, line_begin_pos, expr, column_delta,

def autocorrect_line(corrector, line_begin_pos, expr, column_delta,
                     taboo_ranges)
  range = calculate_range(expr, line_begin_pos, column_delta)
  # We must not change indentation of heredoc strings or inside other
  # string literals
  return if taboo_ranges.any? { |t| within?(range, t) }
  if column_delta.positive? && range.resize(1).source != "\n"
    corrector.insert_before(range, ' ' * column_delta)
  elsif /\A[ \t]+\z/.match?(range.source)
    remove(range, corrector)
  end
end

def block_comment_within?(expr)

def block_comment_within?(expr)
  processed_source.comments.select(&:document?).any? do |c|
    within?(c.loc.expression, expr)
  end
end

def calculate_range(expr, line_begin_pos, column_delta)

def calculate_range(expr, line_begin_pos, column_delta)
  return range_between(line_begin_pos, line_begin_pos) if column_delta.positive?
  starts_with_space = expr.source_buffer.source[line_begin_pos].start_with?(' ')
  if starts_with_space
    range_between(line_begin_pos, line_begin_pos + column_delta.abs)
  else
    range_between(line_begin_pos - column_delta.abs, line_begin_pos)
  end
end

def correct(corrector, processed_source, node, column_delta)

def correct(corrector, processed_source, node, column_delta)
  return unless node
  @processed_source = processed_source
  expr = node.respond_to?(:loc) ? node.loc.expression : node
  return if block_comment_within?(expr)
  taboo_ranges = inside_string_ranges(node)
  each_line(expr) do |line_begin_pos|
    autocorrect_line(corrector, line_begin_pos, expr, column_delta, taboo_ranges)
  end
end

def delimited_string_literal?(node)

- The source map of `__FILE__` responds to neither :begin nor :end.
nil.
- The source map of `?a` responds to :begin and :end but its end is
characters between two delimiters:
Some special kinds of string literals are not composed of literal
def delimited_string_literal?(node)
  loc = node.location
  loc.respond_to?(:begin) && loc.begin && loc.respond_to?(:end) && loc.end
end

def each_line(expr)

def each_line(expr)
  line_begin_pos = expr.begin_pos
  expr.source.each_line do |line|
    yield line_begin_pos
    line_begin_pos += line.length
  end
end

def inside_string_range(node)

def inside_string_range(node)
  loc = node.location
  if node.heredoc?
    loc.heredoc_body.join(loc.heredoc_end)
  elsif delimited_string_literal?(node)
    loc.begin.end.join(loc.end.begin)
  end
end

def inside_string_ranges(node)

def inside_string_ranges(node)
  return [] unless node.is_a?(Parser::AST::Node)
  node.each_node(:str, :dstr, :xstr).map { |n| inside_string_range(n) }.compact
end

def remove(range, corrector)

def remove(range, corrector)
  original_stderr = $stderr
  $stderr = StringIO.new # Avoid error messages on console
  corrector.remove(range)
rescue RuntimeError
  range = range_between(range.begin_pos + 1, range.end_pos + 1)
  retry if /^ +$/.match?(range.source)
ensure
  $stderr = original_stderr
end

def whitespace_range(node)

def whitespace_range(node)
  begin_pos = node.loc.end.begin_pos
  range_between(begin_pos - node.loc.end.column, begin_pos)
end