class RuboCop::Cop::Layout::FirstHashElementIndentation

Checks the indentation of the first key in a hash literal where the opening brace and the first key are on separate lines. The other keys’ indentations are handled by the HashAlignment cop.

By default, Hash literals that are arguments in a method call with parentheses, and where the opening curly brace of the hash is on the same line as the opening parenthesis of the method call, shall have their first key indented one step (two spaces) more than the position inside the opening parenthesis.

Other hash literals shall have their first key indented one step more than the start of the line where the opening curly brace is.

This default style is called ‘special_inside_parentheses’. Alternative styles are ‘consistent’ and ‘align_braces’. Here are examples:

@example EnforcedStyle: special_inside_parentheses (default)

# The `special_inside_parentheses` style enforces that the first key
# in a hash literal where the opening brace and the first key are on
# separate lines is indented one step (two spaces) more than the
# position inside the opening parentheses.

# bad
hash = {
  key: :value
}
and_in_a_method_call({
  no: :difference
                     })
takes_multi_pairs_hash(x: {
  a: 1,
  b: 2
},
                       y: {
                         c: 1,
                         d: 2
                       })

# good
special_inside_parentheses
hash = {
  key: :value
}
but_in_a_method_call({
                       its_like: :this
                     })
takes_multi_pairs_hash(x: {
                         a: 1,
                         b: 2
                       },
                       y: {
                         c: 1,
                         d: 2
                       })

@example EnforcedStyle: consistent

# The `consistent` style enforces that the first key in a hash
# literal where the opening brace and the first key are on
# separate lines is indented the same as a hash literal which is not
# defined inside a method call.

# bad
hash = {
  key: :value
}
but_in_a_method_call({
                       its_like: :this
                      })

# good
hash = {
  key: :value
}
and_in_a_method_call({
  no: :difference
})

@example EnforcedStyle: align_braces

# The `align_brackets` style enforces that the opening and closing
# braces are indented to the same position.

# bad
and_now_for_something = {
                          completely: :different
}
takes_multi_pairs_hash(x: {
  a: 1,
  b: 2
},
                        y: {
                             c: 1,
                             d: 2
                           })

# good
and_now_for_something = {
                          completely: :different
                        }
takes_multi_pairs_hash(x: {
                            a: 1,
                            b: 2
                          },
                       y: {
                            c: 1,
                            d: 2
                          })

Constants

MSG

Public Instance Methods

on_csend(node)
Alias for: on_send
on_hash(node) click to toggle source
# File lib/rubocop/cop/layout/first_hash_element_indentation.rb, line 122
def on_hash(node)
  check(node, nil) if node.loc.begin
end
on_send(node) click to toggle source
# File lib/rubocop/cop/layout/first_hash_element_indentation.rb, line 126
def on_send(node)
  return if enforce_first_argument_with_fixed_indentation?

  each_argument_node(node, :hash) do |hash_node, left_parenthesis|
    check(hash_node, left_parenthesis)
  end
end
Also aliased as: on_csend

Private Instance Methods

argument_alignment_config() click to toggle source
# File lib/rubocop/cop/layout/first_hash_element_indentation.rb, line 233
def argument_alignment_config
  config.for_cop('Layout/ArgumentAlignment')
end
autocorrect(corrector, node) click to toggle source
# File lib/rubocop/cop/layout/first_hash_element_indentation.rb, line 137
def autocorrect(corrector, node)
  AlignmentCorrector.correct(corrector, processed_source, node, @column_delta)
end
base_description(indent_base_type) click to toggle source

Returns the description of what the correct indentation is based on.

# File lib/rubocop/cop/layout/first_hash_element_indentation.rb, line 191
def base_description(indent_base_type)
  case indent_base_type
  when :left_brace_or_bracket
    'the position of the opening brace'
  when :first_column_after_left_parenthesis
    'the first position after the preceding left parenthesis'
  when :parent_hash_key
    'the parent hash key'
  else
    'the start of the line where the left curly brace is'
  end
end
brace_alignment_style() click to toggle source
# File lib/rubocop/cop/layout/first_hash_element_indentation.rb, line 141
def brace_alignment_style
  :align_braces
end
check(hash_node, left_parenthesis) click to toggle source
# File lib/rubocop/cop/layout/first_hash_element_indentation.rb, line 145
def check(hash_node, left_parenthesis)
  return if ignored_node?(hash_node)

  left_brace = hash_node.loc.begin
  first_pair = hash_node.pairs.first

  if first_pair
    return if same_line?(first_pair, left_brace)

    if separator_style?(first_pair)
      check_based_on_longest_key(hash_node, left_brace, left_parenthesis)
    else
      check_first(first_pair, left_brace, left_parenthesis, 0)
    end
  end

  check_right_brace(hash_node.loc.end, first_pair, left_brace, left_parenthesis)
end
check_based_on_longest_key(hash_node, left_brace, left_parenthesis) click to toggle source
# File lib/rubocop/cop/layout/first_hash_element_indentation.rb, line 184
def check_based_on_longest_key(hash_node, left_brace, left_parenthesis)
  key_lengths = hash_node.keys.map { |key| key.source_range.length }
  check_first(hash_node.pairs.first, left_brace, left_parenthesis,
              key_lengths.max - key_lengths.first)
end
check_right_brace(right_brace, first_pair, left_brace, left_parenthesis) click to toggle source
# File lib/rubocop/cop/layout/first_hash_element_indentation.rb, line 164
def check_right_brace(right_brace, first_pair, left_brace, left_parenthesis)
  # if the right brace is on the same line as the last value, accept
  return if /\S/.match?(right_brace.source_line[0...right_brace.column])

  expected_column, indent_base_type = indent_base(left_brace, first_pair, left_parenthesis)
  @column_delta = expected_column - right_brace.column
  return if @column_delta.zero?

  message = message_for_right_brace(indent_base_type)
  add_offense(right_brace, message: message) do |corrector|
    autocorrect(corrector, right_brace)
  end
end
enforce_first_argument_with_fixed_indentation?() click to toggle source
# File lib/rubocop/cop/layout/first_hash_element_indentation.rb, line 227
def enforce_first_argument_with_fixed_indentation?
  return false unless argument_alignment_config['Enabled']

  argument_alignment_config['EnforcedStyle'] == 'with_fixed_indentation'
end
message(base_description) click to toggle source
# File lib/rubocop/cop/layout/first_hash_element_indentation.rb, line 204
def message(base_description)
  format(
    MSG,
    configured_indentation_width: configured_indentation_width,
    base_description: base_description
  )
end
message_for_right_brace(indent_base_type) click to toggle source
# File lib/rubocop/cop/layout/first_hash_element_indentation.rb, line 212
def message_for_right_brace(indent_base_type)
  case indent_base_type
  when :left_brace_or_bracket
    'Indent the right brace the same as the left brace.'
  when :first_column_after_left_parenthesis
    'Indent the right brace the same as the first position ' \
    'after the preceding left parenthesis.'
  when :parent_hash_key
    'Indent the right brace the same as the parent hash key.'
  else
    'Indent the right brace the same as the start of the line ' \
    'where the left brace is.'
  end
end
separator_style?(first_pair) click to toggle source
# File lib/rubocop/cop/layout/first_hash_element_indentation.rb, line 178
def separator_style?(first_pair)
  separator = first_pair.loc.operator
  key = "Enforced#{separator.is?(':') ? 'Colon' : 'HashRocket'}Style"
  config.for_cop('Layout/HashAlignment')[key] == 'separator'
end