module SyntaxTree::HashKeyFormatter
def for(container)
def for(container) (assocs = container.assocs).each_with_index do |assoc, index| if assoc.is_a?(AssocSplat) # Splat nodes do not impact the formatting choice. elsif assoc.value.nil? # If the value is nil, then it has been omitted. In this case we # have to match the existing formatting because standardizing would # potentially break the code. For example: # # { first:, "second" => "value" } # return Identity.new else # Otherwise, we need to check the type of the key. If it's a label # or dynamic symbol, we can use labels. If it's a symbol literal # then it needs to match a certain pattern to be used as a label. If # it's anything else, then we need to use hash rockets. case assoc.key when Label, DynaSymbol # Here labels can be used. when SymbolLiteral # When attempting to convert a hash rocket into a hash label, # you need to take care because only certain patterns are # allowed. Ruby source says that they have to match keyword # arguments to methods, but don't specify what that is. After # some experimentation, it looks like it's: value = assoc.key.value.value if !value.match?(/^[_A-Za-z]/) || value.end_with?("=") if omitted_value?(assocs[(index + 1)..]) return Identity.new else return Rockets.new end end else if omitted_value?(assocs[(index + 1)..]) return Identity.new else return Rockets.new end end end end Labels.new end
def omitted_value?(assocs)
def omitted_value?(assocs) assocs.any? { |assoc| !assoc.is_a?(AssocSplat) && assoc.value.nil? } end