Class: Dry::Validation::Schema

Inherits:
Object
  • Object
show all
Extended by:
Configurable, TypeSpecs
Defined in:
lib/dry/validation/schema.rb,
lib/dry/validation/schema/dsl.rb,
lib/dry/validation/schema/key.rb,
lib/dry/validation/schema/rule.rb,
lib/dry/validation/schema/check.rb,
lib/dry/validation/schema/value.rb,
lib/dry/validation/schema/deprecated.rb,
lib/dry/validation/schema/class_interface.rb

Direct Known Subclasses

Form, JSON

Defined Under Namespace

Classes: Check, DSL, Form, JSON, Key, Rule, Value

Constant Summary collapse

NOOP_INPUT_PROCESSOR =
-> input { input }

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from TypeSpecs

build_array_type, build_hash_type, build_sum_type, build_type_map, extended, lookup_type, resolve_spec

Constructor Details

#initialize(rules, options) ⇒ Schema

Returns a new instance of Schema.



47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/dry/validation/schema.rb', line 47

def initialize(rules, options)
  @type_map = self.class.type_map
  @config = self.class.config
  @predicates = options.fetch(:predicate_registry).bind(self)
  @rule_compiler = SchemaCompiler.new(predicates, options)
  @error_compiler = options.fetch(:error_compiler)
  @hint_compiler = options.fetch(:hint_compiler)
  @input_processor = options[:input_processor]
  @input_rule = rule_compiler.visit(config.input_rule.to_ast) if config.input_rule

  initialize_options(options)
  initialize_rules(rules)
  initialize_checks(options.fetch(:checks, []))

  @executor = Executor.new(config.path) do |steps|
    steps << ProcessInput.new(input_processor) if input_processor
    steps << ApplyInputRule.new(input_rule) if input_rule
    steps << ApplyRules.new(@rules)
    steps << ApplyChecks.new(@checks) if @checks.any?
  end

  freeze
end

Instance Attribute Details

#checksObject (readonly)

Returns the value of attribute checks.



29
30
31
# File 'lib/dry/validation/schema.rb', line 29

def checks
  @checks
end

#configObject (readonly)

Returns the value of attribute config.



23
24
25
# File 'lib/dry/validation/schema.rb', line 23

def config
  @config
end

#error_compilerObject (readonly)

Returns the value of attribute error_compiler.



37
38
39
# File 'lib/dry/validation/schema.rb', line 37

def error_compiler
  @error_compiler
end

#executorObject (readonly)

Returns the value of attribute executor.



45
46
47
# File 'lib/dry/validation/schema.rb', line 45

def executor
  @executor
end

#hint_compilerObject (readonly)

Returns the value of attribute hint_compiler.



39
40
41
# File 'lib/dry/validation/schema.rb', line 39

def hint_compiler
  @hint_compiler
end

#input_processorObject (readonly)

Returns the value of attribute input_processor.



33
34
35
# File 'lib/dry/validation/schema.rb', line 33

def input_processor
  @input_processor
end

#input_ruleObject (readonly)

Returns the value of attribute input_rule.



25
26
27
# File 'lib/dry/validation/schema.rb', line 25

def input_rule
  @input_rule
end

#optionsObject (readonly)

Returns the value of attribute options.



41
42
43
# File 'lib/dry/validation/schema.rb', line 41

def options
  @options
end

#predicatesObject (readonly)

Returns the value of attribute predicates.



31
32
33
# File 'lib/dry/validation/schema.rb', line 31

def predicates
  @predicates
end

#rule_compilerObject (readonly)

Returns the value of attribute rule_compiler.



35
36
37
# File 'lib/dry/validation/schema.rb', line 35

def rule_compiler
  @rule_compiler
end

#rulesObject (readonly)

Returns the value of attribute rules.



27
28
29
# File 'lib/dry/validation/schema.rb', line 27

def rules
  @rules
end

#type_mapObject (readonly)

Returns the value of attribute type_map.



43
44
45
# File 'lib/dry/validation/schema.rb', line 43

def type_map
  @type_map
end

Class Method Details

.cloneObject



104
105
106
107
108
109
# File 'lib/dry/validation/schema/class_interface.rb', line 104

def self.clone
  klass = Class.new(self)
  klass.config.rules = []
  klass.config.registry = registry
  klass
end

.create_class(target, other = nil, &block) ⇒ Object



84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/dry/validation/schema/class_interface.rb', line 84

def self.create_class(target, other = nil, &block)
  klass =
    if other.is_a?(self)
      Class.new(other.class)
    elsif other.is_a?(Class) && other < Types::Struct
      Validation.Schema(parent: target, build: false) do
        other.schema.each { |attr, type| required(attr).filled(type) }
      end
    elsif other.respond_to?(:schema) && other.schema.is_a?(self)
      Class.new(other.schema.class)
    else
      Validation.Schema(target.schema_class, parent: target, build: false, &block)
    end

  klass.config.path = target.path if other
  klass.config.input_processor = :noop

  klass
end

.default_messagesObject



145
146
147
148
149
150
151
152
# File 'lib/dry/validation/schema/class_interface.rb', line 145

def self.default_messages
  case config.messages
  when :yaml then Messages.default
  when :i18n then Messages::I18n.new
  else
    raise "+#{config.messages}+ is not a valid messages identifier"
  end
end

.default_optionsObject



166
167
168
169
170
171
172
# File 'lib/dry/validation/schema/class_interface.rb', line 166

def self.default_options
  @default_options ||= { predicate_registry: registry,
    error_compiler: error_compiler,
    hint_compiler: hint_compiler,
    input_processor: input_processor,
    checks: config.checks }
end

.define(options = {}, &block) ⇒ Object



37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/dry/validation/schema/class_interface.rb', line 37

def self.define(options = {}, &block)
  source = options.fetch(:schema_class)
  config = source.config

  dsl_ext = config.dsl_extensions

  dsl = Schema::Value.new(options.merge(registry: source.registry))
  dsl_ext.__send__(:extend_object, dsl) if dsl_ext
  dsl.predicates(options[:predicates]) if options.key?(:predicates)
  dsl.instance_exec(&block) if block

  target = dsl.schema_class

  if config.input
    config.input_rule = dsl.infer_predicates(Array(target.config.input))
  end

  rules = target.config.rules + (options.fetch(:rules, []) + dsl.rules)

  target.configure do |cfg|
    cfg.rules = rules
    cfg.checks = cfg.checks + dsl.checks
    cfg.path = dsl.path
    cfg.type_map = target.build_type_map(dsl.type_map) if cfg.type_specs
  end

  target
end

.define!(options = {}, &block) ⇒ Object



66
67
68
# File 'lib/dry/validation/schema/class_interface.rb', line 66

def self.define!(options = {}, &block)
  define(schema_class: self, &block)
end

.error_compilerObject



154
155
156
# File 'lib/dry/validation/schema/class_interface.rb', line 154

def self.error_compiler
  @error_compiler ||= ErrorCompiler.new(messages)
end

.hint_compilerObject



158
159
160
# File 'lib/dry/validation/schema/class_interface.rb', line 158

def self.hint_compiler
  @hint_compiler ||= HintCompiler.new(messages, rules: rule_ast)
end

.inherited(klass) ⇒ Object



174
175
176
177
178
179
180
181
182
183
184
# File 'lib/dry/validation/schema/class_interface.rb', line 174

def self.inherited(klass)
  super

  klass.config.options = klass.config.options.dup

  if registry && self != Schema
    klass.config.registry = registry.new(self)
  else
    klass.set_registry!
  end
end

.input_processorObject



6
7
8
9
10
11
12
13
14
15
16
17
18
19
# File 'lib/dry/validation/schema/deprecated.rb', line 6

def self.input_processor
  @input_processor ||=
    begin
      if type_map.is_a?(Dry::Types::Safe) && config.input_processor != :noop
        type_map
      elsif type_map.size > 0 && config.input_processor != :noop
        build_hash_type(type_map)
      elsif input_processor_compiler
        input_processor_compiler.(rule_ast)
      else
        NOOP_INPUT_PROCESSOR
      end
    end
end

.input_processor_ast(type) ⇒ Object



21
22
23
# File 'lib/dry/validation/schema/deprecated.rb', line 21

def self.input_processor_ast(type)
  config.input_processor_map.fetch(type).schema_ast(rule_ast)
end

.input_processor_compilerObject



25
26
27
# File 'lib/dry/validation/schema/deprecated.rb', line 25

def self.input_processor_compiler
  @input_processor_comp ||= config.input_processor_map[config.input_processor]
end

.messagesObject



131
132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/dry/validation/schema/class_interface.rb', line 131

def self.messages
  default = default_messages

  if config.messages_file && config.namespace
    default.merge(config.messages_file).namespaced(config.namespace)
  elsif config.messages_file
    default.merge(config.messages_file)
  elsif config.namespace
    default.namespaced(config.namespace)
  else
    default
  end
end

.new(rules = config.rules, **options) ⇒ Object



33
34
35
# File 'lib/dry/validation/schema/class_interface.rb', line 33

def self.new(rules = config.rules, **options)
  super(rules, default_options.merge(options))
end

.option(name, default = nil) ⇒ Object



79
80
81
82
# File 'lib/dry/validation/schema/class_interface.rb', line 79

def self.option(name, default = nil)
  attr_reader(*name)
  options.update(name => default)
end

.optionsObject



127
128
129
# File 'lib/dry/validation/schema/class_interface.rb', line 127

def self.options
  config.options
end

.predicates(predicate_set = nil) ⇒ Object



70
71
72
73
74
75
76
77
# File 'lib/dry/validation/schema/class_interface.rb', line 70

def self.predicates(predicate_set = nil)
  if predicate_set
    config.predicates = predicate_set
    set_registry!
  else
    config.predicates
  end
end

.registryObject



115
116
117
# File 'lib/dry/validation/schema/class_interface.rb', line 115

def self.registry
  config.registry
end

.rule_astObject



162
163
164
# File 'lib/dry/validation/schema/class_interface.rb', line 162

def self.rule_ast
  @rule_ast ||= config.rules.map(&:to_ast)
end

.rulesObject



123
124
125
# File 'lib/dry/validation/schema/class_interface.rb', line 123

def self.rules
  config.rules
end

.set_registry!Object



186
187
188
# File 'lib/dry/validation/schema/class_interface.rb', line 186

def self.set_registry!
  config.registry = PredicateRegistry[self, config.predicates]
end

.to_astObject



111
112
113
# File 'lib/dry/validation/schema/class_interface.rb', line 111

def self.to_ast
  [:schema, self]
end

.type_mapObject



119
120
121
# File 'lib/dry/validation/schema/class_interface.rb', line 119

def self.type_map
  config.type_map
end

Instance Method Details

#arityObject



88
89
90
# File 'lib/dry/validation/schema.rb', line 88

def arity
  1
end

#call(input) ⇒ Object



75
76
77
78
# File 'lib/dry/validation/schema.rb', line 75

def call(input)
  output, result = executor.(input)
  Result.new(output, result, error_compiler, hint_compiler)
end

#curry(*curry_args) ⇒ Object



80
81
82
# File 'lib/dry/validation/schema.rb', line 80

def curry(*curry_args)
  -> *args { call(*(curry_args + args)) }
end

#to_astObject



92
93
94
# File 'lib/dry/validation/schema.rb', line 92

def to_ast
  self.class.to_ast
end

#to_procObject



84
85
86
# File 'lib/dry/validation/schema.rb', line 84

def to_proc
  -> input { call(input) }
end

#with(new_options) ⇒ Object



71
72
73
# File 'lib/dry/validation/schema.rb', line 71

def with(new_options)
  self.class.new(self.class.rules, options.merge(new_options))
end