lib/dry/validation/hint_compiler.rb in dry-validation-0.6.0 vs lib/dry/validation/hint_compiler.rb in dry-validation-0.7.0
- old
+ new
@@ -1,74 +1,124 @@
-require 'dry/validation/error_compiler'
+require 'dry/validation/error_compiler/input'
module Dry
module Validation
- class HintCompiler < ErrorCompiler
- attr_reader :messages, :rules, :options
+ class HintCompiler < ErrorCompiler::Input
+ include Dry::Equalizer(:messages, :rules, :options)
+ attr_reader :rules, :excluded
+
+ TYPES = {
+ none?: NilClass,
+ bool?: TrueClass,
+ str?: String,
+ int?: Fixnum,
+ float?: Float,
+ decimal?: BigDecimal,
+ date?: Date,
+ date_time?: DateTime,
+ time?: Time,
+ hash?: Hash,
+ array?: Array
+ }.freeze
+
+ EXCLUDED = [:none?, :filled?, :key?].freeze
+
+ def self.cache
+ @cache ||= ThreadSafe::Cache.new
+ end
+
def initialize(messages, options = {})
- @messages = messages
- @options = Hash[options]
+ super(messages, { name: nil, input: nil }.merge(options))
@rules = @options.delete(:rules)
+ @excluded = @options.fetch(:excluded, EXCLUDED)
+ @val_type = options[:val_type]
end
def with(new_options)
super(new_options.merge(rules: rules))
end
def call
- messages = Hash.new { |h, k| h[k] = [] }
+ self.class.cache.fetch_or_store(hash) do
+ super(rules)
+ end
+ end
- rules.map { |node| visit(node) }.compact.each do |hints|
- name, msgs = hints
- messages[name].concat(msgs)
+ def visit_predicate(node)
+ predicate, _ = node
+
+ val_type = TYPES[predicate]
+
+ return with(val_type: val_type) if val_type
+ return {} if excluded.include?(predicate)
+
+ super
+ end
+
+ def visit_set(node)
+ result = node.map do |el|
+ visit(el)
end
+ merge(result)
+ end
- messages
+ def visit_each(node)
+ visit(node)
end
def visit_or(node)
left, right = node
- [visit(left), Array(visit(right)).flatten.compact].compact
+ merge([visit(left), visit(right)])
end
def visit_and(node)
left, right = node
- [visit(left), Array(visit(right)).flatten.compact].compact
+
+ result = visit(left)
+
+ if result.is_a?(self.class)
+ result.visit(right)
+ else
+ visit(right)
+ end
end
- def visit_val(node)
+ def visit_implication(node)
+ _, right = node
+ visit(right)
+ end
+
+ def visit_key(node)
name, predicate = node
- visit(predicate, name)
+ with(name: Array([*self.name, name])).visit(predicate)
end
+ alias_method :visit_attr, :visit_key
- def visit_predicate(node, name)
- predicate_name, args = node
+ def visit_val(node)
+ visit(node)
+ end
- lookup_options = options.merge(rule: name, arg_type: args[0].class)
+ def visit_schema(node)
+ DEFAULT_RESULT
+ end
- template = messages[predicate_name, lookup_options]
- predicate_opts = visit(node, args)
-
- return unless predicate_opts
-
- tokens = predicate_opts.merge(name: name)
-
- template % tokens
+ def visit_check(node)
+ DEFAULT_RESULT
end
- def visit_key(node)
- name, _ = node
- name
+ def visit_xor(node)
+ DEFAULT_RESULT
end
- def visit_attr(node)
- name, _ = node
- name
+ def visit_not(node)
+ DEFAULT_RESULT
end
- def method_missing(name, *args)
- nil
+ private
+
+ def merge(result)
+ super(result.reject { |el| el.is_a?(self.class) })
end
end
end
end