class RuboCop::Cop::Layout::SpaceInsideHashLiteralBraces

Checks that braces used for hash literals have or don’t have surrounding space depending on configuration.

@example EnforcedStyle: space (default)

# The `space` style enforces that hash literals have
# surrounding space.

# bad
h = {a: 1, b: 2}

# good
h = { a: 1, b: 2 }

@example EnforcedStyle: no_space

# The `no_space` style enforces that hash literals have
# no surrounding space.

# bad
h = { a: 1, b: 2 }

# good
h = {a: 1, b: 2}

@example EnforcedStyle: compact

# The `compact` style normally requires a space inside
# hash braces, with the exception that successive left
# braces or right braces are collapsed together in nested hashes.

# bad
h = { a: { b: 2 } }
foo = { { a: 1 } => { b: { c: 2 } } }

# good
h = { a: { b: 2 }}
foo = {{ a: 1 } => { b: { c: 2 }}}

@example EnforcedStyleForEmptyBraces: no_space (default)

# The `no_space` EnforcedStyleForEmptyBraces style enforces that
# empty hash braces do not contain spaces.

# bad
foo = { }
bar = {    }
baz = {
}

# good
foo = {}
bar = {}
baz = {}

@example EnforcedStyleForEmptyBraces: space

# The `space` EnforcedStyleForEmptyBraces style enforces that
# empty hash braces contain space.

# bad
foo = {}

# good
foo = { }
foo = {    }
foo = {
}

Constants

MSG

Public Instance Methods

on_hash(node) click to toggle source
# File lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb, line 78
def on_hash(node)
  tokens = processed_source.tokens_within(node)
  return unless tokens.first.left_brace? && tokens.last.right_curly_brace?

  check(tokens[0], tokens[1])
  check(tokens[-2], tokens[-1]) if tokens.size > 2
  check_whitespace_only_hash(node) if enforce_no_space_style_for_empty_braces?
end

Private Instance Methods

ambiguous_or_unexpected_style_detected(style, is_match) click to toggle source
# File lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb, line 137
def ambiguous_or_unexpected_style_detected(style, is_match)
  if is_match
    ambiguous_style_detected(style, :compact)
  else
    unexpected_style_detected(style)
  end
end
autocorrect(corrector, range) click to toggle source
# File lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb, line 129
def autocorrect(corrector, range)
  case range.source
  when /\s/ then corrector.remove(range)
  when '{' then corrector.insert_after(range, ' ')
  else corrector.insert_before(range, ' ')
  end
end
check(token1, token2) click to toggle source
# File lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb, line 89
def check(token1, token2)
  # No offense if line break inside.
  return if token1.line < token2.line
  return if token2.comment? # Also indicates there's a line break.

  is_empty_braces = token1.left_brace? && token2.right_curly_brace?
  expect_space    = expect_space?(token1, token2)

  if offense?(token1, expect_space)
    incorrect_style_detected(token1, token2, expect_space, is_empty_braces)
  else
    correct_style_detected
  end
end
check_whitespace_only_hash(node) click to toggle source
# File lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb, line 184
def check_whitespace_only_hash(node)
  range = range_inside_hash(node)
  return unless range.source.match?(/\A\s+\z/m)

  add_offense(
    range,
    message: format(MSG, problem: 'empty hash literal braces detected')
  ) do |corrector|
    corrector.remove(range)
  end
end
enforce_no_space_style_for_empty_braces?() click to toggle source
# File lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb, line 200
def enforce_no_space_style_for_empty_braces?
  cop_config['EnforcedStyleForEmptyBraces'] == 'no_space'
end
expect_space?(token1, token2) click to toggle source
# File lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb, line 104
def expect_space?(token1, token2)
  is_same_braces  = token1.type == token2.type
  is_empty_braces = token1.left_brace? && token2.right_curly_brace?

  if is_same_braces && style == :compact
    false
  elsif is_empty_braces
    !enforce_no_space_style_for_empty_braces?
  else
    style != :no_space
  end
end
incorrect_style_detected(token1, token2, expect_space, is_empty_braces) click to toggle source
# File lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb, line 117
def incorrect_style_detected(token1, token2,
                             expect_space, is_empty_braces)
  brace = (token1.text == '{' ? token1 : token2).pos
  range = expect_space ? brace : space_range(brace)
  detected_style = expect_space ? 'no_space' : 'space'

  add_offense(range, message: message(brace, is_empty_braces, expect_space)) do |corrector|
    autocorrect(corrector, range)
    ambiguous_or_unexpected_style_detected(detected_style, token1.text == token2.text)
  end
end
message(brace, is_empty_braces, expect_space) click to toggle source
# File lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb, line 150
def message(brace, is_empty_braces, expect_space)
  inside_what = if is_empty_braces
                  'empty hash literal braces'
                else
                  brace.source
                end
  problem = expect_space ? 'missing' : 'detected'
  format(MSG, problem: "#{inside_what} #{problem}")
end
offense?(token1, expect_space) click to toggle source
# File lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb, line 145
def offense?(token1, expect_space)
  has_space = token1.space_after?
  expect_space ? !has_space : has_space
end
range_inside_hash(node) click to toggle source
# File lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb, line 196
def range_inside_hash(node)
  range_between(node.location.begin.end_pos, node.location.end.begin_pos)
end
range_of_space_to_the_left(range) click to toggle source
# File lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb, line 176
def range_of_space_to_the_left(range)
  src = range.source_buffer.source
  begin_pos = range.begin_pos
  begin_pos -= 1 while /[ \t]/.match?(src[begin_pos - 1])

  range_between(begin_pos, range.end_pos - 1)
end
range_of_space_to_the_right(range) click to toggle source
# File lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb, line 168
def range_of_space_to_the_right(range)
  src = range.source_buffer.source
  end_pos = range.end_pos
  end_pos += 1 while /[ \t]/.match?(src[end_pos])

  range_between(range.begin_pos + 1, end_pos)
end
space_range(token_range) click to toggle source
# File lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb, line 160
def space_range(token_range)
  if token_range.source == '{'
    range_of_space_to_the_right(token_range)
  else
    range_of_space_to_the_left(token_range)
  end
end