107 lines
3.1 KiB
Ruby
107 lines
3.1 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require "dry/validation/message"
|
|
|
|
module Dry
|
|
module Validation
|
|
module Messages
|
|
# Resolve translated messages from failure arguments
|
|
#
|
|
# @api public
|
|
class Resolver
|
|
# @!attribute [r] messages
|
|
# @return [Messages::I18n, Messages::YAML] messages backend
|
|
# @api private
|
|
attr_reader :messages
|
|
|
|
# @api private
|
|
def initialize(messages)
|
|
@messages = messages
|
|
end
|
|
|
|
# Resolve Message object from provided args and path
|
|
#
|
|
# This is used internally by contracts when rules are applied
|
|
# If message argument is a Hash, then it MUST have a :text key,
|
|
# which value will be used as the message value
|
|
#
|
|
# @return [Message, Message::Localized]
|
|
#
|
|
# @api public
|
|
def call(message:, tokens:, path:, meta: EMPTY_HASH)
|
|
case message
|
|
when Symbol
|
|
Message[->(**opts) { message(message, path: path, tokens: tokens, **opts) }, path, meta]
|
|
when String
|
|
Message[message, path, meta]
|
|
when Hash
|
|
meta = message.dup
|
|
text = meta.delete(:text) { |key|
|
|
raise ArgumentError, <<~STR
|
|
+message+ Hash must contain :#{key} key (#{message.inspect} given)
|
|
STR
|
|
}
|
|
|
|
call(message: text, tokens: tokens, path: path, meta: meta)
|
|
else
|
|
raise ArgumentError, <<~STR
|
|
+message+ must be either a Symbol, String or Hash (#{message.inspect} given)
|
|
STR
|
|
end
|
|
end
|
|
alias_method :[], :call
|
|
|
|
# Resolve a message
|
|
#
|
|
# @return [String]
|
|
#
|
|
# @api public
|
|
#
|
|
# rubocop:disable Metrics/AbcSize
|
|
def message(rule, tokens: EMPTY_HASH, locale: nil, full: false, path:)
|
|
keys = path.to_a.compact
|
|
msg_opts = tokens.merge(path: keys, locale: locale || messages.default_locale)
|
|
|
|
if keys.empty?
|
|
template, meta = messages["rules.#{rule}", msg_opts]
|
|
else
|
|
template, meta = messages[rule, msg_opts.merge(path: keys.join(DOT))]
|
|
template, meta = messages[rule, msg_opts.merge(path: keys.last)] unless template
|
|
end
|
|
|
|
unless template
|
|
raise MissingMessageError, <<~STR
|
|
Message template for #{rule.inspect} under #{keys.join(DOT).inspect} was not found
|
|
STR
|
|
end
|
|
|
|
parsed_tokens = parse_tokens(tokens)
|
|
text = template.(template.data(parsed_tokens))
|
|
|
|
[full ? "#{messages.rule(keys.last, msg_opts)} #{text}" : text, meta]
|
|
end
|
|
# rubocop:enable Metrics/AbcSize
|
|
|
|
private
|
|
|
|
def parse_tokens(tokens)
|
|
Hash[
|
|
tokens.map do |key, token|
|
|
[key, parse_token(token)]
|
|
end
|
|
]
|
|
end
|
|
|
|
def parse_token(token)
|
|
case token
|
|
when Array
|
|
token.join(", ")
|
|
else
|
|
token
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|