# frozen_string_literal: true class NiceHash ################################################## # Flattens a nested hash so keys become dot-notation strings. # # @param hash [Hash] The hash to flatten # @param prefix [String] Internal: current path prefix for recursion # # @return [Hash] Flat hash with string keys like "user.address.city" # # @example # NiceHash.flatten_keys({ user: { address: { city: "Madrid" } } }) # #=> { "user.address.city" => "Madrid" } ################################################## def self.flatten_keys(hash, prefix = "") return {} unless hash.is_a?(Hash) result = {} hash.each do |k, v| path = prefix.empty? ? k.to_s : "#{prefix}.#{k}" if v.is_a?(Hash) result.merge!(flatten_keys(v, path)) else result[path] = v end end result end ################################################## # Unflattens a hash with dot-notation keys into a nested hash. # # @param hash [Hash] Flat hash with string keys like "user.address.city" # # @return [Hash] Nested hash # # @example # NiceHash.unflatten_keys({ "user.address.city" => "Madrid" }) # #=> { user: { address: { city: "Madrid" } } } ################################################## def self.unflatten_keys(hash) return {} unless hash.is_a?(Hash) result = {} hash.each do |key_str, value| keys = key_str.to_s.split(".") keys = keys.map { |k| k.match?(/\A\d+\z/) ? k.to_i : k.to_sym } current = result keys[0..-2].each do |k| current[k] = {} unless current[k].is_a?(Hash) current = current[k] end current[keys[-1]] = value end result end end