app/models/coupdoeil/params.rb
# frozen_string_literal: true module Coupdoeil module Params extend self GLOBAL_ID_KEY = "_cd_globalid" RESERVED_KEYS = [GLOBAL_ID_KEY, GLOBAL_ID_KEY.to_sym].freeze private_constant :RESERVED_KEYS, :GLOBAL_ID_KEY SerializationError = Class.new(StandardError) def deserialize_global_id(hash) = GlobalID::Locator.locate hash[GLOBAL_ID_KEY] def deserialize_hash(serialized_hash) = serialized_hash.transform_values { deserialize_param(_1) } def serialized_global_id?(hash) = hash.size == 1 && hash.include?(GLOBAL_ID_KEY) def serialize(*params) ActiveSupport::Notifications.instrument("serialize_hovercard_params.coupdoeil") do params.map { |param| serialize_param(param) } end end def deserialize(params) Array.wrap(params).map { |param| deserialize_param(param) } rescue StandardError raise DeserializationError end def serialize_param(param) case param when GlobalID::Identification convert_to_global_id_hash(param) when Array param.map { serialize_param(_1) } when Hash serialize_hash(param) else param end end def serialize_hash(param) param.each_with_object({}) do |(key, value), hash| hash[serialize_hash_key(key)] = serialize_param(value) end end def serialize_hash_key(key) case key when *RESERVED_KEYS raise Coupdoeil::SerializationError, "Can't serialize a Hash with reserved key #{key.inspect}" when String, Symbol key.to_s else raise Coupdoeil::SerializationError, "Only string and symbol hash keys may be serialized as hovercard params, but #{key.inspect} is a #{key.class}" end end def convert_to_global_id_hash(param) { GLOBAL_ID_KEY => param.to_global_id.to_s } rescue URI::GID::MissingModelIdError raise Coupdoeil::SerializationError, "Unable to serialize #{param.class} " \ "without an id. (Maybe you forgot to call save?)" end def deserialize_param(param) case param when Array param.map { |arg| deserialize_param(arg) } when Hash if serialized_global_id?(param) deserialize_global_id param else deserialize_hash(param) end else param end end end end