lib/dry/schema/message_set.rb in dry-schema-1.4.3 vs lib/dry/schema/message_set.rb in dry-schema-1.5.0

- old
+ new

@@ -1,8 +1,8 @@ # frozen_string_literal: true -require 'dry/equalizer' +require "dry/equalizer" module Dry module Schema # A set of messages used to generate errors # @@ -16,16 +16,10 @@ # A list of compiled message objects # # @return [Array<Message>] attr_reader :messages - # An internal hash that is filled in with dumped messages - # when a message set is coerced to a hash - # - # @return [Hash<Symbol=>[Array,Hash]>] - attr_reader :placeholders - # Options hash # # @return [Hash] attr_reader :options @@ -36,11 +30,10 @@ # @api private def initialize(messages, options = EMPTY_HASH) @messages = messages @options = options - initialize_placeholders! end # Iterate over messages # # @example @@ -110,46 +103,42 @@ private # @api private def messages_map(messages = self.messages) - return EMPTY_HASH if empty? + combine_message_hashes(messages.map(&:to_h)) + end - messages.group_by(&:path).reduce(placeholders) do |hash, (path, msgs)| - node = path.reduce(hash) { |a, e| a[e] } - - msgs.each do |msg| - node << msg + # @api private + def combine_message_hashes(hashes) + hashes.reduce(EMPTY_HASH.dup) do |a, e| + a.merge(e) do |_, *values| + combine_message_values(values) end - - node.map!(&:dump) - - hash end end # @api private - def paths - @paths ||= messages.map(&:path).uniq + def combine_message_values(values) + hashes, other = partition_message_values(values) + combined = combine_message_hashes(hashes) + flattened = other.flatten + + if flattened.empty? + combined + elsif combined.empty? + flattened + else + [flattened, combined] + end end # @api private - def initialize_placeholders! - return @placeholders = EMPTY_HASH if empty? - - @placeholders = paths.reduce(EMPTY_HASH.dup) do |hash, path| - curr_idx = 0 - last_idx = path.size - 1 - node = hash - - while curr_idx <= last_idx - key = path[curr_idx] - node = (node[key] || node[key] = curr_idx < last_idx ? {} : []) - curr_idx += 1 - end - - hash - end + def partition_message_values(values) + values + .map { |value| value.is_a?(Array) ? value : [value] } + .reduce(EMPTY_ARRAY.dup, :+) + .partition { |value| value.is_a?(Hash) && !value[:text].is_a?(String) } end end end end