class RuboCop::Cop::Style::HashSyntax


{foo: foo, bar: baz}
# good - can’t omit ‘baz`
{foo:, bar:}
# good
{foo:, bar: baz}
# bad - mixed syntaxes
{foo:, bar: bar}
# bad - `bar` value can be omitted
{foo: foo, bar: bar}
# bad - `foo` and `bar` values can be omitted
@example EnforcedShorthandSyntax: consistent
{foo:, bar:}
# good
{foo: foo, bar:}
# good
{foo: foo, bar: bar}
# good
@example EnforcedShorthandSyntax: either
{foo: foo, bar: bar}
# good
{foo:, bar:}
# bad
@example EnforcedShorthandSyntax: never
{foo:, bar:}
# good
{foo: foo, bar: bar}
# bad
@example EnforcedShorthandSyntax: always (default)
{:c => 3, ’d’ => 4}
{a: 1, b: 2}
# good
{c: 2, ‘d’ => 3} # should just use hash rockets
{:a => 1, :b => 2}
# bad
@example EnforcedStyle: ruby19_no_mixed_keys
{c: 1, d: 2}
{:a => 1, :b => 2}
# good
{c: 1, ‘d’ => 2}
{:a => 1, b: 2}
# bad
@example EnforcedStyle: no_mixed_keys
{:a => 1, :b => 2}
# good
{c: 1, ‘d’ => 5}
{a: 1, b: 2}
# bad
@example EnforcedStyle: hash_rockets
{d: 1, ‘e’ => 2} # technically not forbidden
{:c => 2, ‘d’ => 2} # acceptable since ‘d’ isn’t a symbol
{a: 2, b: 1}
# good
{b: 1, :c => 2}
{:a => 2}
# bad
@example EnforcedStyle: ruby19 (default)
* consistent - forces use of the 3.1 syntax only if all values can be omitted in the hash
* either - accepts both shorthand and explicit use of hash literal value
* never - forces use of explicit hash literal value
* always - forces use of the 3.1 syntax (e.g. {foo:})
The supported styles are:
the use of Ruby 3.1’s hash value shorthand syntax.
It can enforce either the use of the explicit hash value syntax or
This cop has ‘EnforcedShorthandSyntax` option.
syntax hashes
* ruby19_no_mixed_keys - forces use of ruby 1.9 syntax and forbids mixed
* no_mixed_keys - simply checks for hashes with mixed syntaxes
* hash_rockets - forces use of hash rockets for all hashes
all symbols for keys
* ruby19 - forces use of the 1.9 syntax (e.g. `{a: 1}`) when hashes have
The supported styles are:
A separate offense is registered for each problematic pair.
the use of the newer Ruby 1.9 syntax (when applicable).
It can enforce either the use of the class hash rocket syntax or
Checks hash literal syntax.

def acceptable_19_syntax_symbol?(sym_name)

def acceptable_19_syntax_symbol?(sym_name)
  sym_name.delete_prefix!(':')
  if cop_config['PreferHashRocketsForNonAlnumEndingSymbols'] &&
     # Prefer { :production? => false } over { production?: false } and
     # similarly for other non-alnum final characters (except quotes,
     # to prefer { "x y": 1 } over { :"x y" => 1 }).
     !/[\p{Alnum}"']\z/.match?(sym_name)
    return false
  end
  # Most hash keys can be matched against a simple regex.
  return true if /\A[_a-z]\w*[?!]?\z/i.match?(sym_name)
  # For more complicated hash keys, let the parser validate the syntax.
  parse("{ #{sym_name}: :foo }").valid_syntax?
end

def alternative_style

def alternative_style
  case style
  when :hash_rockets
    :ruby19
  when :ruby19, :ruby19_no_mixed_keys
    :hash_rockets
  end
end

def argument_without_space?(node)

def argument_without_space?(node)
  node.argument? && node.source_range.begin_pos == node.parent.loc.selector.end_pos
end

def autocorrect(corrector, node)

def autocorrect(corrector, node)
  if style == :hash_rockets || force_hash_rockets?(node.parent.pairs)
    autocorrect_hash_rockets(corrector, node)
  elsif style == :ruby19_no_mixed_keys || style == :no_mixed_keys
    autocorrect_no_mixed_keys(corrector, node)
  else
    autocorrect_ruby19(corrector, node)
  end
end

def autocorrect_hash_rockets(corrector, pair_node)

def autocorrect_hash_rockets(corrector, pair_node)
  op = pair_node.loc.operator
  key_with_hash_rocket = ":#{pair_node.key.source}#{pair_node.inverse_delimiter(true)}"
  key_with_hash_rocket += pair_node.key.source if pair_node.value_omission?
  corrector.replace(pair_node.key, key_with_hash_rocket)
  corrector.remove(range_with_surrounding_space(op))
end

def autocorrect_no_mixed_keys(corrector, pair_node)

def autocorrect_no_mixed_keys(corrector, pair_node)
  if pair_node.colon?
    autocorrect_hash_rockets(corrector, pair_node)
  else
    autocorrect_ruby19(corrector, pair_node)
  end
end

def autocorrect_ruby19(corrector, pair_node)

def autocorrect_ruby19(corrector, pair_node)
  range = range_for_autocorrect_ruby19(pair_node)
  space = argument_without_space?(pair_node.parent) ? ' ' : ''
  corrector.replace(range, range.source.sub(/^:(.*\S)\s*=>\s*$/, "#{space}\\1: "))
  hash_node = pair_node.parent
  return unless hash_node.parent&.return_type? && !hash_node.braces?
  corrector.wrap(hash_node, '{', '}')
end

def check(pairs, delim, msg)

def check(pairs, delim, msg)
  pairs.each do |pair|
    if pair.delimiter == delim
      location = pair.source_range.begin.join(pair.loc.operator)
      add_offense(location, message: msg) do |corrector|
        autocorrect(corrector, pair)
        opposite_style_detected
      end
    else
      correct_style_detected
    end
  end
end

def force_hash_rockets?(pairs)

def force_hash_rockets?(pairs)
  cop_config['UseHashRocketsWithSymbolValues'] && pairs.map(&:value).any?(&:sym_type?)
end

def hash_rockets_check(pairs)

def hash_rockets_check(pairs)
  check(pairs, ':', MSG_HASH_ROCKETS)
end

def no_mixed_keys_check(pairs)

def no_mixed_keys_check(pairs)
  if sym_indices?(pairs)
    check(pairs, pairs.first.inverse_delimiter, MSG_NO_MIXED_KEYS)
  else
    check(pairs, ':', MSG_NO_MIXED_KEYS)
  end
end

def on_hash(node)

def on_hash(node)
  pairs = node.pairs
  return if pairs.empty?
  on_hash_for_mixed_shorthand(node)
  if style == :hash_rockets || force_hash_rockets?(pairs)
    hash_rockets_check(pairs)
  elsif style == :ruby19_no_mixed_keys
    ruby19_no_mixed_keys_check(pairs)
  elsif style == :no_mixed_keys
    no_mixed_keys_check(pairs)
  else
    ruby19_check(pairs)
  end
end

def range_for_autocorrect_ruby19(pair_node)

def range_for_autocorrect_ruby19(pair_node)
  key = pair_node.key.source_range
  operator = pair_node.loc.operator
  range = key.join(operator)
  range_with_surrounding_space(range, side: :right)
end

def ruby19_check(pairs)

def ruby19_check(pairs)
  check(pairs, '=>', MSG_19) if sym_indices?(pairs)
end

def ruby19_no_mixed_keys_check(pairs)

def ruby19_no_mixed_keys_check(pairs)
  if force_hash_rockets?(pairs)
    check(pairs, ':', MSG_HASH_ROCKETS)
  elsif sym_indices?(pairs)
    check(pairs, '=>', MSG_19)
  else
    check(pairs, ':', MSG_NO_MIXED_KEYS)
  end
end

def sym_indices?(pairs)

def sym_indices?(pairs)
  pairs.all? { |p| word_symbol_pair?(p) }
end

def word_symbol_pair?(pair)

def word_symbol_pair?(pair)
  return false unless pair.key.sym_type? || pair.key.dsym_type?
  acceptable_19_syntax_symbol?(pair.key.source)
end