lib/dry/validation/schema/value.rb in dry-validation-0.7.4 vs lib/dry/validation/schema/value.rb in dry-validation-0.8.0

- old
+ new

@@ -2,78 +2,98 @@ module Dry module Validation class Schema class Value < DSL - attr_reader :type, :schema_class + attr_reader :type, :schema_class, :schema, :type_map def initialize(options = {}) super @type = options.fetch(:type, :key) @schema_class = options.fetch(:schema_class, ::Class.new(Schema)) + @options = options.merge(type: @type, schema_class: @schema_class) + @type_map = parent && parent.root? ? parent.type_map : {} end - def configure(&block) - klass = ::Class.new(schema_class, &block) - @schema_class = klass + def predicates(mod) + @registry = options[:registry] = schema_class.predicates(mod) + end + + def input(type) + schema_class.config.input = type self end - def root? - name.nil? + def key(name, &block) + warn 'key is deprecated - use required instead.' + + required(name, &block) end - def class - Value + def required(name, type_spec = nil, &block) + rule = define(name, Key, &block) + + if type_spec + type_map[name] = type_spec + end + + rule end def schema(other = nil, &block) - schema = Schema.create_class(self, other, &block) - hash?.and(schema) + @schema = Schema.create_class(self, other, &block) + type_map.update(@schema.type_map) + hash?.and(@schema) end def each(*predicates, &block) left = array? right = if predicates.size > 0 - inferred = predicates - .reduce(Value.new) { |a, e| a.__send__(*::Kernel.Array(e)) } - - create_rule([:each, inferred.to_ast]) + create_rule([:each, infer_predicates(predicates, new).to_ast]) else - val = Value[name].instance_eval(&block) + val = Value[ + name, registry: registry, schema_class: schema_class.clone + ].instance_eval(&block) - create_rule([:each, [:set, val.rule_ast]]) + if val.type_map? + if root? + @type_map = [val.type_map] + else + type_map[name] = [val.type_map] + end + end + + create_rule([:each, val.to_ast]) end rule = left.and(right) add_rule(rule) if root? rule end def when(*predicates, &block) - left = predicates - .reduce(Check[path, type: type]) { |a, e| a.__send__(*::Kernel.Array(e)) } + left = infer_predicates(predicates, Check[path, type: type, registry: registry]) - right = Value.new(type: type) + right = Value.new(type: type, registry: registry) right.instance_eval(&block) add_check(left.then(create_rule(right.to_ast))) self end def rule(id = nil, **options, &block) if id - val = Value[id] + val = Value[id, registry: registry] res = val.instance_exec(&block) else id, deps = options.to_a.first - val = Value[id] + val = Value[id, registry: registry] res = val.instance_exec(*deps.map { |name| val.value(name) }, &block) end add_check(val.with(rules: [res.with(deps: deps || [])])) end @@ -85,23 +105,88 @@ rule(conf => [conf, name]) { |left, right| left.eql?(right) } end def value(name) - check(name, rules: rules) + check(name, registry: registry, rules: rules) end def check(name, options = {}) Check[name, options.merge(type: type)] end + def configure(&block) + klass = ::Class.new(schema_class, &block) + @schema_class = klass + @registry = klass.registry + self + end + + def root? + name.nil? + end + + def type_map? + ! type_map.empty? + end + + def schema? + ! @schema.nil? + end + + def class + Value + end + + def new + self.class.new(registry: registry, schema_class: schema_class.clone) + end + + def key?(name) + create_rule([:val, registry[:key?].curry(name).to_ast]) + end + + def predicate(name, *args) + registry.ensure_valid_predicate(name, args) + registry[name].curry(*args) + end + + def node(input, *args) + if input.is_a?(::Symbol) + [type, [name, predicate(input, *args).to_ast]] + elsif input.respond_to?(:rule) + [type, [name, [:type, input]]] + elsif input.is_a?(::Class) && input < ::Dry::Types::Struct + [type, [name, [:schema, Schema.create_class(self, input)]]] + elsif input.is_a?(Schema) + [type, [name, schema(input).to_ast]] + else + [type, [name, input.to_ast]] + end + end + private + def infer_predicates(predicates, infer_on) + predicates.map { |predicate| + name, *args = ::Kernel.Array(predicate).first + + if name.is_a?(Schema) + infer_on.schema(name) + else + infer_on.__send__(name, *args) + end + }.reduce(:and) + end + def method_missing(meth, *args, &block) - val_rule = create_rule([:val, [:predicate, [meth, args]]]) + val_rule = create_rule([:val, predicate(meth, *args).to_ast]) if block - val = Value.new.instance_eval(&block) + val = new.instance_eval(&block) + + type_map.update(val.type_map) if val.type_map? + new_rule = create_rule([:and, [val_rule.to_ast, val.to_ast]]) add_rule(new_rule) else val_rule