diff --git a/templates/lib/prism/node.rb.erb b/templates/lib/prism/node.rb.erb index fb13051aba..4d9a8ebf32 100644 --- a/templates/lib/prism/node.rb.erb +++ b/templates/lib/prism/node.rb.erb @@ -551,7 +551,16 @@ module Prism #: (Array[Symbol]? keys) -> Hash[Symbol, untyped] def deconstruct_keys(keys) # :nodoc: - { <%= (["node_id: node_id", "location: location"] + node.fields.map { |field| "#{field.name}: #{field.name}" }).join(", ") %> } + <%- deconstruct = [:node_id, :location, *node.fields.map { |field| field.name.to_sym }, *node.fields.select { |field| field.is_a?(Prism::Template::LocationField) || field.is_a?(Prism::Template::OptionalLocationField) }.map { |field| field.name.delete_suffix("_loc").to_sym }].uniq -%> + (keys || %i[<%= deconstruct.join(" ") %>]).each_with_object( + {} #: Hash[Symbol, untyped] + ) do |key, deconstructed| + case key + <%- deconstruct.each do |key| -%> + when <%= "%-24s then" % [key.inspect] %> deconstructed[<%= key.inspect %>] = self.<%= key %> + <%- end -%> + end + end end # See `Node#type`. diff --git a/test/prism/ruby/deconstruct_keys_test.rb b/test/prism/ruby/deconstruct_keys_test.rb new file mode 100644 index 0000000000..f81b06ef2e --- /dev/null +++ b/test/prism/ruby/deconstruct_keys_test.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +require_relative "../test_helper" + +module Prism + class DeconstructKeysTest < TestCase + def test_deconstruct_keys + node = Prism.parse_statement("1.to_s") + + deconstruct_all = node.deconstruct_keys(nil) + assert_equal deconstruct_all[:node_id], node.node_id + assert_equal deconstruct_all[:message], "to_s" + + deconstruct_receiver = node.deconstruct_keys([:receiver]) + assert_equal 1, deconstruct_receiver[:receiver].value + refute_includes deconstruct_receiver.keys, :message + + deconstruct_invalid = node.deconstruct_keys([:invalid]) + refute_includes deconstruct_invalid.keys, :invalid + end + end +end