lib/dry/schema/extensions/hints/message_set_methods.rb in dry-schema-1.3.0 vs lib/dry/schema/extensions/hints/message_set_methods.rb in dry-schema-1.3.1

- old
+ new

@@ -10,11 +10,11 @@ module MessageSetMethods # Filtered message hints from all messages # # @return [Array<Message::Hint>] attr_reader :hints - + # Configuration option to enable/disable showing errors # # @return [Boolean] attr_reader :failures @@ -35,9 +35,56 @@ # @api public def to_h @to_h ||= failures ? messages_map : messages_map(hints) end alias_method :to_hash, :to_h + + private + + # @api private + def unique_paths + messages.uniq(&:path).map(&:path) + end + + # @api private + def messages_map(messages = self.messages) + return EMPTY_HASH if empty? + + messages.reduce(placeholders) { |hash, msg| + node = msg.path.reduce(hash) { |a, e| a.is_a?(Hash) ? a[e] : a.last[e] } + (node[0].is_a?(::Array) ? node[0] : node) << msg.dump + hash + } + end + + # @api private + # + # rubocop:disable Metrics/AbcSize + # rubocop:disable Metrics/PerceivedComplexity + def initialize_placeholders! + @placeholders = unique_paths.each_with_object(EMPTY_HASH.dup) { |path, hash| + curr_idx = 0 + last_idx = path.size - 1 + node = hash + + while curr_idx <= last_idx + key = path[curr_idx] + + next_node = + if node.is_a?(Array) && key.is_a?(Symbol) + node_hash = (node << [] << {}).last + node_hash[key] || (node_hash[key] = curr_idx < last_idx ? {} : []) + else + node[key] || (node[key] = curr_idx < last_idx ? {} : []) + end + + node = next_node + curr_idx += 1 + end + } + end + # rubocop:enable Metrics/AbcSize + # rubocop:enable Metrics/PerceivedComplexity end end end end end