class RuboCop::Cop::Style::IndentHash
than the start of the line where the opening curly brace is.
Other hash literals shall have their first key indented one step more
opening parenthesis.
indented one step (two spaces) more than the position inside the
opening parenthesis of the method call, shall have their first key
where the opening curly brace of the hash is on the same line as the
Hash literals that are arguments in a method call with parentheses, and
other keys’ indentations are handled by the AlignHash cop.
where the opening brace and the first key are on separate lines. The
This cops checks the indentation of the first key in a hash literal
def base_column(left_brace, left_parenthesis)
def base_column(left_brace, left_parenthesis) if left_parenthesis && style == :special_inside_parentheses left_parenthesis.column + 1 else left_brace.source_line =~ /\S/ end end
def base_description(left_parenthesis)
def base_description(left_parenthesis) if left_parenthesis && style == :special_inside_parentheses 'the first position after the preceding left parenthesis' else 'the start of the line where the left curly brace is' end end
def check(hash_node, left_brace, left_parenthesis)
def check(hash_node, left_brace, left_parenthesis) return if ignored_node?(hash_node) first_pair = hash_node.children.first if first_pair left_brace = hash_node.loc.begin return if first_pair.loc.expression.line == left_brace.line if separator_style?(first_pair) check_based_on_longest_key(hash_node.children, left_brace, left_parenthesis) else check_first_pair(first_pair, left_brace, left_parenthesis, 0) end end check_right_brace(hash_node.loc.end, left_brace, left_parenthesis) end
def check_based_on_longest_key(pairs, left_brace, left_parenthesis)
def check_based_on_longest_key(pairs, left_brace, left_parenthesis) key_lengths = pairs.map do |pair| pair.children.first.loc.expression.length end check_first_pair(pairs.first, left_brace, left_parenthesis, key_lengths.max - key_lengths.first) end
def check_first_pair(first_pair, left_brace, left_parenthesis, offset)
def check_first_pair(first_pair, left_brace, left_parenthesis, offset) column = first_pair.loc.expression.column expected_column = base_column(left_brace, left_parenthesis) + configured_indentation_width + offset @column_delta = expected_column - column if @column_delta == 0 correct_style_detected else incorrect_style_detected(column, offset, first_pair, left_parenthesis, left_brace) end end
def check_right_brace(right_brace, left_brace, left_parenthesis)
def check_right_brace(right_brace, left_brace, left_parenthesis) return if right_brace.source_line[0...right_brace.column] =~ /\S/ expected_column = base_column(left_brace, left_parenthesis) @column_delta = expected_column - right_brace.column return if @column_delta == 0 msg = if style == :special_inside_parentheses && left_parenthesis 'Indent the right brace the same as the first position ' \ 'after the preceding left parenthesis.' else 'Indent the right brace the same as the start of the line ' \ 'where the left brace is.' end add_offense(right_brace, right_brace, msg) end
def incorrect_style_detected(column, offset, first_pair,
def incorrect_style_detected(column, offset, first_pair, left_parenthesis, left_brace) add_offense(first_pair, :expression, message(base_description(left_parenthesis))) do if column == unexpected_column(left_brace, left_parenthesis, offset) opposite_style_detected else unrecognized_style_detected end end end
def message(base_description)
def message(base_description) format('Use %d spaces for indentation in a hash, relative to %s.', configured_indentation_width, base_description) end
def on_hash(node)
def on_hash(node) left_brace = node.loc.begin check(node, left_brace, nil) if left_brace end
def on_send(node)
def on_send(node) _receiver, _method_name, *args = *node left_parenthesis = node.loc.begin return unless left_parenthesis args.each do |arg| on_node(:hash, arg, :send) do |hash_node| left_brace = hash_node.loc.begin if left_brace && left_brace.line == left_parenthesis.line check(hash_node, left_brace, left_parenthesis) ignore_node(hash_node) end end end end
def separator_style?(first_pair)
def separator_style?(first_pair) separator = first_pair.loc.operator key = "Enforced#{separator.is?(':') ? 'Colon' : 'HashRocket'}Style" config.for_cop('Style/AlignHash')[key] == 'separator' end
def unexpected_column(left_brace, left_parenthesis, offset)
Returns the "unexpected column", which is the column that would be
def unexpected_column(left_brace, left_parenthesis, offset) # Set a crazy value by default, indicating that there's no other # configuration that can be chosen to make the used indentation # accepted. unexpected_base_column = -1000 if left_parenthesis unexpected_base_column = if style == :special_inside_parentheses left_brace.source_line =~ /\S/ else left_parenthesis.column + 1 end end unexpected_base_column + configured_indentation_width + offset end