class RuboCop::Cop::Style::AlignHash

literal are aligned.
Here we check if the keys, separators, and values of a multi-line hash

def adjust(corrector, delta, range)

def adjust(corrector, delta, range)
  if delta > 0
    corrector.insert_before(range, ' ' * delta)
  elsif delta < 0
    range = Parser::Source::Range.new(range.source_buffer,
                                      range.begin_pos - delta.abs,
                                      range.begin_pos)
    corrector.remove(range)
  end
end

def alignment_for(pair)

def alignment_for(pair)
  if pair.loc.operator.is?('=>')
    @alignment_for_hash_rockets
  else
    @alignment_for_colons
  end
end

def autocorrect(node)

def autocorrect(node)
  # We can't use the instance variable inside the lambda. That would
  # just give each lambda the same reference and they would all get the
  # last value of each. Some local variables fix the problem.
  key_delta       = @column_deltas[:key] || 0
  separator_delta = @column_deltas[:separator] || 0
  value_delta     = @column_deltas[:value] || 0
  key, value = *node
  key_column = key.source_range.column
  key_delta = -key_column if key_delta < -key_column
  lambda do |corrector|
    if value.nil?
      adjust(corrector, key_delta, node.source_range)
    else
      adjust(corrector, key_delta, key.source_range)
      adjust(corrector, separator_delta, node.loc.operator)
      adjust(corrector, value_delta, value.source_range)
    end
  end
end

def check_pairs(node)

def check_pairs(node)
  first_pair = node.children.first
  @column_deltas = alignment_for(first_pair)
                   .deltas_for_first_pair(first_pair, node)
  add_offense(first_pair, :expression) unless good_alignment?
  node.children.each do |current|
    @column_deltas = alignment_for(current).deltas(first_pair, current)
    add_offense(current, :expression) unless good_alignment?
  end
end

def explicit_hash?(node)

def explicit_hash?(node)
  node.loc.begin
end

def good_alignment?

def good_alignment?
  @column_deltas.values.compact.none? { |v| v != 0 }
end

def hash?(node)

def hash?(node)
  node.respond_to?(:type) && node.type == :hash
end

def ignore_last_argument_hash?(node)

def ignore_last_argument_hash?(node)
  case cop_config['EnforcedLastArgumentHashStyle']
  when 'always_inspect'  then false
  when 'always_ignore'   then true
  when 'ignore_explicit' then explicit_hash?(node)
  when 'ignore_implicit' then !explicit_hash?(node)
  end
end

def new_alignment(key)

def new_alignment(key)
  case cop_config[key]
  when 'key'       then KeyAlignment.new
  when 'table'     then TableAlignment.new
  when 'separator' then SeparatorAlignment.new
  else raise "Unknown #{key}: #{cop_config[key]}"
  end
end

def on_hash(node)

def on_hash(node)
  return if ignored_node?(node)
  return if node.children.empty?
  return unless node.multiline?
  @alignment_for_hash_rockets ||=
    new_alignment('EnforcedHashRocketStyle')
  @alignment_for_colons ||= new_alignment('EnforcedColonStyle')
  unless @alignment_for_hash_rockets.checkable_layout(node) &&
         @alignment_for_colons.checkable_layout(node)
    return
  end
  check_pairs(node)
end

def on_send(node)

def on_send(node)
  return unless (last_child = node.children.last) &&
                hash?(last_child) &&
                ignore_last_argument_hash?(last_child)
  ignore_node(last_child)
end