Class: Dry::Validation::Schema::Value

Inherits:
DSL
  • Object
show all
Includes:
StructNode
Defined in:
lib/dry/validation/schema/value.rb

Direct Known Subclasses

Check

Instance Attribute Summary collapse

Attributes inherited from DSL

#checks, #name, #options, #parent, #registry, #rules

Instance Method Summary collapse

Methods inherited from DSL

[], #add_check, #add_rule, #inspect, #not, #optional, #path, #predicate, #predicate?, #rule_ast, #to_ast, #to_rule, #with

Methods included from Deprecations

format, #logger, #warn

Constructor Details

#initialize(options = {}) ⇒ Value

Returns a new instance of Value.



9
10
11
12
13
14
15
# File 'lib/dry/validation/schema/value.rb', line 9

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

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(meth, *args, &block) ⇒ Object (private)



191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
# File 'lib/dry/validation/schema/value.rb', line 191

def method_missing(meth, *args, &block)
  return schema_class.instance_method(meth) if dyn_arg?(meth)

  val_rule = create_rule(predicate(meth, args))

  if 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
  end
end

Instance Attribute Details

#schema(other = nil, &block) ⇒ Object (readonly)

Returns the value of attribute schema.



7
8
9
# File 'lib/dry/validation/schema/value.rb', line 7

def schema
  @schema
end

#schema_classObject (readonly)

Returns the value of attribute schema_class.



7
8
9
# File 'lib/dry/validation/schema/value.rb', line 7

def schema_class
  @schema_class
end

#typeObject (readonly)

Returns the value of attribute type.



7
8
9
# File 'lib/dry/validation/schema/value.rb', line 7

def type
  @type
end

#type_mapObject (readonly)

Returns the value of attribute type_map.



7
8
9
# File 'lib/dry/validation/schema/value.rb', line 7

def type_map
  @type_map
end

Instance Method Details

#check(name, options = {}) ⇒ Object



113
114
115
# File 'lib/dry/validation/schema/value.rb', line 113

def check(name, options = {})
  Check[name, options.merge(type: type)]
end

#classObject



142
143
144
# File 'lib/dry/validation/schema/value.rb', line 142

def class
  Value
end

#configure(&block) ⇒ Object



124
125
126
127
128
# File 'lib/dry/validation/schema/value.rb', line 124

def configure(&block)
  schema_class.class_eval(&block)
  @registry = schema_class.registry
  self
end

#confirmationObject



99
100
101
102
103
104
105
106
107
# File 'lib/dry/validation/schema/value.rb', line 99

def confirmation
  conf = :"#{name}_confirmation"

  parent.optional(conf).maybe

  rule(conf => [conf, name]) do |left, right|
    left.eql?(right)
  end
end

#dyn_arg?(name) ⇒ Boolean

Returns:

  • (Boolean)


167
168
169
# File 'lib/dry/validation/schema/value.rb', line 167

def dyn_arg?(name)
  !name.to_s.end_with?('?') && schema_class.instance_methods.include?(name)
end

#each(*predicates, &block) ⇒ Object



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

def each(*predicates, &block)
  left = array?

  right =
    if predicates.size > 0
      create_rule([:each, infer_predicates(predicates, new).to_ast])
    else
      val = Value[
        name, registry: registry, schema_class: schema_class.clone
      ].instance_eval(&block)

      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

#infer_predicates(predicates, infer_on = self) ⇒ Object



175
176
177
178
179
180
181
182
183
184
185
186
187
# File 'lib/dry/validation/schema/value.rb', line 175

def infer_predicates(predicates, infer_on = self)
  predicates.flat_map(&::Kernel.method(:Array)).map { |predicate|
    name, *args = ::Kernel.Array(predicate)

    if name.is_a?(Schema)
      infer_on.schema(name)
    elsif name.respond_to?(:rule)
      create_rule(name.rule.to_ast)
    else
      infer_on.__send__(name, *args)
    end
  }.reduce(:and)
end

#input(*predicates) ⇒ Object



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

def input(*predicates)
  schema_class.config.input = predicates
  self
end

#key(name, &block) ⇒ Object



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

def key(name, &block)
  warn 'key is deprecated - use required instead.'

  required(name, &block)
end

#key?(name) ⇒ Boolean

Returns:

  • (Boolean)


150
151
152
# File 'lib/dry/validation/schema/value.rb', line 150

def key?(name)
  create_rule(predicate(:key?, name))
end

#newObject



146
147
148
# File 'lib/dry/validation/schema/value.rb', line 146

def new
  self.class.new(registry: registry, schema_class: schema_class.clone)
end

#node(input, *args) ⇒ Object



154
155
156
157
158
159
160
161
162
163
164
165
# File 'lib/dry/validation/schema/value.rb', line 154

def node(input, *args)
  if input.is_a?(::Symbol)
    registry.ensure_valid_predicate(input, args, schema_class)
    [type, [name, predicate(input, args)]]
  elsif input.respond_to?(:rule)
    [type, [name, [:type, input]]]
  elsif input.is_a?(Schema)
    [type, [name, schema(input).to_ast]]
  else
    [type, [name, input.to_ast]]
  end
end

#predicates(mod) ⇒ Object



17
18
19
# File 'lib/dry/validation/schema/value.rb', line 17

def predicates(mod)
  @registry = options[:registry] = schema_class.predicates(mod)
end

#required(name, type_spec = nil, &block) ⇒ Object



32
33
34
35
36
37
38
39
40
# File 'lib/dry/validation/schema/value.rb', line 32

def required(name, type_spec = nil, &block)
  rule = define(name, Key, &block)

  if type_spec
    type_map[name] = type_spec
  end

  rule
end

#respond_to?(name) ⇒ Boolean

Returns:

  • (Boolean)


171
172
173
# File 'lib/dry/validation/schema/value.rb', line 171

def respond_to?(name)
  self.class.public_methods.include?(name)
end

#root?Boolean

Returns:

  • (Boolean)


130
131
132
# File 'lib/dry/validation/schema/value.rb', line 130

def root?
  name.nil?
end

#rule(id = nil, **options, &block) ⇒ Object



86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/dry/validation/schema/value.rb', line 86

def rule(id = nil, **options, &block)
  if id
    val = Value[id, registry: registry, schema_class: schema_class]
    res = val.instance_exec(&block)
  else
    id, deps = options.to_a.first
    val = Value[id, registry: registry, schema_class: schema_class]
    res = val.instance_exec(*deps.map { |path| val.value(id, path: path) }, &block)
  end

  add_check(val.with(rules: [res.with(name: id, deps: deps || [])]))
end

#schema?Boolean

Returns:

  • (Boolean)


138
139
140
# File 'lib/dry/validation/schema/value.rb', line 138

def schema?
  ! @schema.nil?
end

#type_map?Boolean

Returns:

  • (Boolean)


134
135
136
# File 'lib/dry/validation/schema/value.rb', line 134

def type_map?
  ! type_map.empty?
end

#validate(**opts, &block) ⇒ Object



117
118
119
120
121
122
# File 'lib/dry/validation/schema/value.rb', line 117

def validate(**opts, &block)
  id, *deps = opts.to_a.flatten
  name = deps.size > 1 ? id : deps.first
  rule = create_rule([:check, [deps, [:custom, [id, block]]]], name).with(deps: deps)
  add_check(rule)
end

#value(path, opts = {}) ⇒ Object



109
110
111
# File 'lib/dry/validation/schema/value.rb', line 109

def value(path, opts = {})
  check(name || path, { registry: registry, rules: rules, path: path }.merge(opts))
end

#when(*predicates, &block) ⇒ Object



77
78
79
80
81
82
83
84
# File 'lib/dry/validation/schema/value.rb', line 77

def when(*predicates, &block)
  left = infer_predicates(predicates, Check[path, type: type, registry: registry])
  right = Value.new(type: type, registry: registry).instance_eval(&block)

  add_check(left.then(right.to_rule))

  self
end