validate-rb 0.1.0.alpha.1 → 0.1.0.pre
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +12 -0
- data/.rspec +3 -0
- data/.ruby-version +1 -0
- data/.travis.yml +6 -0
- data/Gemfile +7 -0
- data/README.md +4 -4
- data/Rakefile +6 -0
- data/bin/console +7 -0
- data/bin/setup +6 -0
- data/lib/validate/version.rb +1 -1
- data/lib/validate-rb.rb +3 -0
- data/lib/validate.rb +1 -75
- data/validate-rb.gemspec +30 -0
- metadata +21 -122
- data/LICENSE +0 -21
- data/lib/validate/arguments.rb +0 -93
- data/lib/validate/assertions.rb +0 -27
- data/lib/validate/ast.rb +0 -381
- data/lib/validate/compare.rb +0 -34
- data/lib/validate/constraint.rb +0 -217
- data/lib/validate/constraints/validation_context.rb +0 -167
- data/lib/validate/constraints.rb +0 -337
- data/lib/validate/errors.rb +0 -40
- data/lib/validate/helpers.rb +0 -11
- data/lib/validate/scope.rb +0 -48
- data/lib/validate/validators/dsl.rb +0 -44
- data/lib/validate/validators.rb +0 -7
@@ -1,167 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Validate
|
4
|
-
module Constraints
|
5
|
-
class ValidationContext
|
6
|
-
def self.none
|
7
|
-
@none ||= None.new
|
8
|
-
end
|
9
|
-
|
10
|
-
def self.root(value, violations = [])
|
11
|
-
new(value, Path.new, violations)
|
12
|
-
end
|
13
|
-
|
14
|
-
attr_reader :value
|
15
|
-
|
16
|
-
def initialize(value, path = Path.new, violations = [])
|
17
|
-
@value = value
|
18
|
-
@path = path
|
19
|
-
@violations = violations
|
20
|
-
@keys = Hash.new do |hash, key|
|
21
|
-
unless @value.respond_to?(:[]) || @value.respond_to_missing?(:[])
|
22
|
-
raise Error::KeyError,
|
23
|
-
"#{key.inspect}: value doesn't respond to :[]"
|
24
|
-
end
|
25
|
-
begin
|
26
|
-
hash[key] = child_context(@value[key], KeyPath.new(key))
|
27
|
-
rescue => e
|
28
|
-
raise Error::KeyError,
|
29
|
-
"#{key.inspect}: #{e.message}",
|
30
|
-
cause: e
|
31
|
-
end
|
32
|
-
end
|
33
|
-
@attrs = Hash.new do |hash, attr|
|
34
|
-
unless @value.respond_to?(attr) || @value.respond_to_missing?(attr)
|
35
|
-
raise Error::NameError,
|
36
|
-
"#{attr.inspect}: value doesn't respond to #{attr.inspect}"
|
37
|
-
end
|
38
|
-
hash[attr] = child_context(@value.send(attr), AttrPath.new(attr))
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
def [](key)
|
43
|
-
@keys[key]
|
44
|
-
end
|
45
|
-
|
46
|
-
def attr(name)
|
47
|
-
@attrs[name]
|
48
|
-
end
|
49
|
-
|
50
|
-
def add_violation(constraint)
|
51
|
-
@violations << create_violation(constraint)
|
52
|
-
self
|
53
|
-
end
|
54
|
-
|
55
|
-
def clear_violations
|
56
|
-
@violations.clear
|
57
|
-
self
|
58
|
-
end
|
59
|
-
|
60
|
-
def has_violations?
|
61
|
-
!@violations.empty?
|
62
|
-
end
|
63
|
-
|
64
|
-
def to_err
|
65
|
-
Error::ConstraintViolationError.new(@violations.freeze)
|
66
|
-
end
|
67
|
-
|
68
|
-
private
|
69
|
-
|
70
|
-
def create_violation(constraint)
|
71
|
-
Constraint::Violation.new(@value, @path, constraint)
|
72
|
-
end
|
73
|
-
|
74
|
-
def child_context(value, path)
|
75
|
-
ValidationContext.new(value, @path.child(path), @violations)
|
76
|
-
end
|
77
|
-
|
78
|
-
class Path
|
79
|
-
extend Forwardable
|
80
|
-
|
81
|
-
def_delegators(:@paths, :empty?, :length, :size, :each)
|
82
|
-
|
83
|
-
include Enumerable
|
84
|
-
|
85
|
-
def initialize(paths = [])
|
86
|
-
@paths = paths
|
87
|
-
end
|
88
|
-
|
89
|
-
def child(path)
|
90
|
-
Path.new(@paths.dup << path)
|
91
|
-
end
|
92
|
-
|
93
|
-
def to_s
|
94
|
-
return '.' if @paths.empty?
|
95
|
-
|
96
|
-
@paths.join
|
97
|
-
end
|
98
|
-
|
99
|
-
def at(index)
|
100
|
-
raise Error::IndexError if index.negative?
|
101
|
-
|
102
|
-
return nil if index.zero?
|
103
|
-
@paths.fetch(index - 1)
|
104
|
-
end
|
105
|
-
|
106
|
-
def inspect
|
107
|
-
return "#<#{self.class.name} <root>>" if @paths.empty?
|
108
|
-
|
109
|
-
"#<#{self.class.name} #{to_s}>"
|
110
|
-
end
|
111
|
-
end
|
112
|
-
|
113
|
-
class KeyPath
|
114
|
-
def initialize(key)
|
115
|
-
@key = key
|
116
|
-
end
|
117
|
-
|
118
|
-
def to_s
|
119
|
-
"[#{@key.inspect}]"
|
120
|
-
end
|
121
|
-
|
122
|
-
def inspect
|
123
|
-
"#<#{self.class.name} #{@key.inspect}>"
|
124
|
-
end
|
125
|
-
end
|
126
|
-
|
127
|
-
class AttrPath
|
128
|
-
def initialize(attr)
|
129
|
-
@attr = attr
|
130
|
-
end
|
131
|
-
|
132
|
-
def to_s
|
133
|
-
".#{@attr}"
|
134
|
-
end
|
135
|
-
|
136
|
-
def inspect
|
137
|
-
"#<#{self.class.name} #{@attr.inspect}>"
|
138
|
-
end
|
139
|
-
end
|
140
|
-
|
141
|
-
class None < ValidationContext
|
142
|
-
def initialize
|
143
|
-
end
|
144
|
-
|
145
|
-
def [](_)
|
146
|
-
self
|
147
|
-
end
|
148
|
-
|
149
|
-
def attr(_)
|
150
|
-
self
|
151
|
-
end
|
152
|
-
|
153
|
-
def add_violation(_)
|
154
|
-
self
|
155
|
-
end
|
156
|
-
|
157
|
-
def clear_violations
|
158
|
-
self
|
159
|
-
end
|
160
|
-
|
161
|
-
def has_violations?
|
162
|
-
false
|
163
|
-
end
|
164
|
-
end
|
165
|
-
end
|
166
|
-
end
|
167
|
-
end
|
data/lib/validate/constraints.rb
DELETED
@@ -1,337 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Validate
|
4
|
-
module Constraints
|
5
|
-
include Validate::Arguments
|
6
|
-
|
7
|
-
@reserved_names = Hash[%i[define validation_context].map { |n| [n, n] }]
|
8
|
-
|
9
|
-
arg(:name) do
|
10
|
-
not_blank(message: 'constraint name must not be blank')
|
11
|
-
is_a(Symbol, message: 'constraint name must be a Symbol')
|
12
|
-
end
|
13
|
-
arg(:body) do
|
14
|
-
not_nil(message: 'constraint body is required')
|
15
|
-
end
|
16
|
-
def self.define(name, **defaults, &body)
|
17
|
-
if @reserved_names.include?(name)
|
18
|
-
raise Error::ArgumentError,
|
19
|
-
"#{name} is already defined"
|
20
|
-
end
|
21
|
-
|
22
|
-
@reserved_names[name] = name
|
23
|
-
constraint_class = Constraint.create_class(name, defaults, &body)
|
24
|
-
Constraints.const_set(Helpers.camelize(name), constraint_class)
|
25
|
-
define_method(name, &constraint_class.method(:new))
|
26
|
-
module_function(name)
|
27
|
-
end
|
28
|
-
|
29
|
-
define(:not_nil, message: 'not be nil') do
|
30
|
-
evaluate { |value| fail if value.nil? }
|
31
|
-
end
|
32
|
-
|
33
|
-
define(:not_blank, message: 'not be blank') do
|
34
|
-
evaluate do |value|
|
35
|
-
fail if value.nil? || !value.respond_to?(:empty?) || value.empty?
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
define(:not_empty, message: 'not be empty') do
|
40
|
-
evaluate { |value| fail if value&.empty? }
|
41
|
-
end
|
42
|
-
|
43
|
-
define(:is_a, message: 'be a %{constraint.klass}') do
|
44
|
-
option(:klass) do
|
45
|
-
not_nil(message: 'klass is required')
|
46
|
-
end
|
47
|
-
|
48
|
-
initialize { |klass| { klass: klass } }
|
49
|
-
evaluate do |value|
|
50
|
-
pass if value.nil?
|
51
|
-
|
52
|
-
klass = options[:klass]
|
53
|
-
fail unless klass === value
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
define(:respond_to, message: 'respond to %{constraint.method_name.inspect}') do
|
58
|
-
option(:method_name) do
|
59
|
-
not_blank(message: 'method_name is required')
|
60
|
-
is_a(Symbol, message: 'method_name must be a Symbol')
|
61
|
-
end
|
62
|
-
|
63
|
-
initialize do |method_name|
|
64
|
-
method_name.nil? ? {} : { method_name: method_name }
|
65
|
-
end
|
66
|
-
evaluate do |instance|
|
67
|
-
pass if instance.nil?
|
68
|
-
fail unless instance.respond_to?(options[:method_name])
|
69
|
-
end
|
70
|
-
key { "respond_to_#{options[:method_name]}" }
|
71
|
-
end
|
72
|
-
|
73
|
-
define(:length, message: 'have length of %{constraint.describe_length}') do
|
74
|
-
option(:min) { respond_to(:>, message: 'min must respond to :>') }
|
75
|
-
option(:max) { respond_to(:<, message: 'max must respond to :<') }
|
76
|
-
|
77
|
-
initialize do |range = nil|
|
78
|
-
case range
|
79
|
-
when ::Range
|
80
|
-
{ min: range.min, max: range.max }
|
81
|
-
else
|
82
|
-
{ min: range, max: range }
|
83
|
-
end
|
84
|
-
end
|
85
|
-
evaluate do |value|
|
86
|
-
pass if value.nil?
|
87
|
-
fail unless value.respond_to?(:length)
|
88
|
-
|
89
|
-
length = value.length
|
90
|
-
fail if (options[:min]&.> length) || (options[:max]&.< length)
|
91
|
-
end
|
92
|
-
|
93
|
-
def describe_length
|
94
|
-
if options[:max] == options[:min]
|
95
|
-
options[:max].to_s
|
96
|
-
elsif options[:max].nil?
|
97
|
-
"at least #{options[:min]}"
|
98
|
-
elsif options[:min].nil?
|
99
|
-
"at most #{options[:max]}"
|
100
|
-
else
|
101
|
-
"at least #{options[:min]} and at most #{options[:max]}"
|
102
|
-
end
|
103
|
-
end
|
104
|
-
key { "length_over_#{options[:min]}_under_#{options[:max]}" }
|
105
|
-
end
|
106
|
-
|
107
|
-
define(:one_of, message: 'be %{constraint.describe_presence}') do
|
108
|
-
option(:values) do
|
109
|
-
respond_to(:include?, message: 'values must respond to :include?')
|
110
|
-
end
|
111
|
-
|
112
|
-
initialize do |*values|
|
113
|
-
if values.one? && values.first.respond_to?(:include?)
|
114
|
-
{ values: values.first }
|
115
|
-
else
|
116
|
-
{ values: values }
|
117
|
-
end
|
118
|
-
end
|
119
|
-
evaluate do |value|
|
120
|
-
pass if value.nil?
|
121
|
-
|
122
|
-
values = options[:values]
|
123
|
-
pass if values.respond_to?(:cover?) && values.cover?(value)
|
124
|
-
fail unless values.include?(value)
|
125
|
-
end
|
126
|
-
|
127
|
-
def describe_presence
|
128
|
-
case options[:values]
|
129
|
-
when ::Hash
|
130
|
-
"one of #{options[:values].keys}"
|
131
|
-
when ::Range
|
132
|
-
"covered by #{options[:values]}"
|
133
|
-
else
|
134
|
-
"one of #{options[:values]}"
|
135
|
-
end
|
136
|
-
end
|
137
|
-
end
|
138
|
-
|
139
|
-
define(:validate, message: 'pass validation') do
|
140
|
-
option(:using) do
|
141
|
-
not_nil(message: 'using is required')
|
142
|
-
is_a(Proc, message: 'using must be a Proc')
|
143
|
-
end
|
144
|
-
|
145
|
-
initialize { |&validate_block| { using: validate_block } }
|
146
|
-
evaluate do |value|
|
147
|
-
pass if value.nil?
|
148
|
-
fail unless instance_exec(value, &options[:using])
|
149
|
-
end
|
150
|
-
end
|
151
|
-
|
152
|
-
define(:attr, message: 'have attribute %{constraint.attribute}') do
|
153
|
-
option(:attribute) do
|
154
|
-
not_nil(message: 'attribute is required')
|
155
|
-
is_a(Symbol, message: 'attribute must be a Symbol')
|
156
|
-
end
|
157
|
-
option(:constraints) do
|
158
|
-
is_a(AST::DefinitionContext, message: 'constraints must be a DefinitionContext')
|
159
|
-
end
|
160
|
-
|
161
|
-
initialize do |attribute, &block|
|
162
|
-
{ attribute: attribute,
|
163
|
-
constraints: block && AST::DefinitionContext.create(&block) }
|
164
|
-
end
|
165
|
-
evaluate do |value, ctx|
|
166
|
-
pass if value.nil?
|
167
|
-
|
168
|
-
attribute = options[:attribute]
|
169
|
-
begin
|
170
|
-
options[:constraints].evaluate(ctx.attr(attribute))
|
171
|
-
rescue NameError
|
172
|
-
fail
|
173
|
-
end
|
174
|
-
end
|
175
|
-
key { "attr_#{options[:attribute]}" }
|
176
|
-
end
|
177
|
-
|
178
|
-
define(:key, message: 'have key %{constraint.key.inspect}') do
|
179
|
-
option(:key) do
|
180
|
-
not_nil(message: 'key is required')
|
181
|
-
end
|
182
|
-
option(:constraints) do
|
183
|
-
is_a(AST::DefinitionContext, message: 'constraints must be a DefinitionContext')
|
184
|
-
end
|
185
|
-
|
186
|
-
initialize do |key, &block|
|
187
|
-
{ key: key,
|
188
|
-
constraints: block && AST::DefinitionContext.create(&block) }
|
189
|
-
end
|
190
|
-
|
191
|
-
evaluate do |instance, ctx|
|
192
|
-
pass if instance.nil?
|
193
|
-
fail unless instance.respond_to?(:[])
|
194
|
-
|
195
|
-
key = options[:key]
|
196
|
-
begin
|
197
|
-
options[:constraints]&.evaluate(ctx[key])
|
198
|
-
rescue KeyError
|
199
|
-
fail
|
200
|
-
end
|
201
|
-
end
|
202
|
-
key { "key_#{options[:key]}" }
|
203
|
-
end
|
204
|
-
|
205
|
-
define(:min, message: 'be at least %{constraint.min}') do
|
206
|
-
option(:min) do
|
207
|
-
not_nil(message: 'min is required')
|
208
|
-
respond_to(:>, message: 'min must respond to :>')
|
209
|
-
end
|
210
|
-
|
211
|
-
initialize do |min = nil|
|
212
|
-
min.nil? ? {} : { min: min }
|
213
|
-
end
|
214
|
-
evaluate do |value|
|
215
|
-
pass if value.nil?
|
216
|
-
fail if options[:min] > value
|
217
|
-
end
|
218
|
-
end
|
219
|
-
|
220
|
-
define(:max, message: 'be at most %{constraint.max}') do
|
221
|
-
option(:max) do
|
222
|
-
not_nil(message: 'max is required')
|
223
|
-
respond_to(:<, message: 'max must respond to :<')
|
224
|
-
end
|
225
|
-
|
226
|
-
initialize do |max = nil|
|
227
|
-
max.nil? ? {} : { max: max }
|
228
|
-
end
|
229
|
-
evaluate do |value|
|
230
|
-
pass if value.nil?
|
231
|
-
fail if options[:max] < value
|
232
|
-
end
|
233
|
-
end
|
234
|
-
|
235
|
-
define(:equal, message: 'be equal to %{constraint.equal}') do
|
236
|
-
option(:equal) do
|
237
|
-
not_nil(message: 'equal is required')
|
238
|
-
respond_to(:==, message: 'equal must respond to :==')
|
239
|
-
end
|
240
|
-
|
241
|
-
initialize do |equal = nil|
|
242
|
-
equal.nil? ? {} : { equal: equal }
|
243
|
-
end
|
244
|
-
evaluate do |value|
|
245
|
-
pass if value.nil?
|
246
|
-
fail unless options[:equal] == value
|
247
|
-
end
|
248
|
-
end
|
249
|
-
|
250
|
-
define(:match, message: 'match %{constraint.regexp}') do
|
251
|
-
option(:regexp) do
|
252
|
-
not_nil(message: 'regexp is required')
|
253
|
-
respond_to(:=~, message: 'regexp must respond to :=~')
|
254
|
-
end
|
255
|
-
|
256
|
-
initialize do |regexp = nil|
|
257
|
-
regexp.nil? ? {} : { regexp: regexp }
|
258
|
-
end
|
259
|
-
evaluate do |value|
|
260
|
-
pass if value.nil?
|
261
|
-
fail unless value.is_a?(String) && options[:regexp] =~ value
|
262
|
-
end
|
263
|
-
end
|
264
|
-
|
265
|
-
define(:valid, message: 'be valid %{constraint.validator || value.class}') do
|
266
|
-
option(:validator, default: nil)
|
267
|
-
|
268
|
-
initialize do |validator = nil|
|
269
|
-
validator.nil? ? {} : { validator: validator }
|
270
|
-
end
|
271
|
-
evaluate do |value, ctx|
|
272
|
-
pass if value.nil?
|
273
|
-
|
274
|
-
Scope.current
|
275
|
-
.validator(options[:validator] || value.class)
|
276
|
-
.validate(ctx)
|
277
|
-
end
|
278
|
-
key { options[:validator] && "valid_#{options[:validator]}" || 'valid' }
|
279
|
-
end
|
280
|
-
|
281
|
-
define(:each_value, message: 'have values') do
|
282
|
-
option(:constraints) do
|
283
|
-
not_nil(message: 'constraints are required')
|
284
|
-
is_a(AST::DefinitionContext, message: 'constraints must be a DefinitionContext')
|
285
|
-
end
|
286
|
-
|
287
|
-
initialize do |&block|
|
288
|
-
return {} if block.nil?
|
289
|
-
|
290
|
-
{ constraints: AST::DefinitionContext.create(&block) }
|
291
|
-
end
|
292
|
-
evaluate do |collection, ctx|
|
293
|
-
pass if collection.nil?
|
294
|
-
fail unless collection.respond_to?(:each)
|
295
|
-
|
296
|
-
constraints = options[:constraints]
|
297
|
-
case collection
|
298
|
-
when ::Hash
|
299
|
-
collection.each do |key, value|
|
300
|
-
constraints.evaluate(ctx[key])
|
301
|
-
end
|
302
|
-
else
|
303
|
-
i = 0
|
304
|
-
collection.each do |value|
|
305
|
-
constraints.evaluate(ctx[i])
|
306
|
-
i += 1
|
307
|
-
end
|
308
|
-
end
|
309
|
-
end
|
310
|
-
end
|
311
|
-
|
312
|
-
define(
|
313
|
-
:unique,
|
314
|
-
message: 'have unique %{constraint.describe_unique_attribute}'
|
315
|
-
) do
|
316
|
-
option(:attribute, default: nil) do
|
317
|
-
is_a(Symbol, message: 'attribute %{value.inspect} must be a Symbol')
|
318
|
-
end
|
319
|
-
|
320
|
-
initialize do |attribute = nil|
|
321
|
-
attribute.nil? ? {} : { attribute: attribute }
|
322
|
-
end
|
323
|
-
evaluate do |value|
|
324
|
-
pass if value.nil?
|
325
|
-
fail unless value.respond_to?(:uniq) && value.respond_to?(:size)
|
326
|
-
fail unless value.size == value.uniq(&options[:attribute]).size
|
327
|
-
end
|
328
|
-
key do
|
329
|
-
options[:attribute] && "unique_#{options[:attribute]}" || 'unique'
|
330
|
-
end
|
331
|
-
|
332
|
-
def describe_unique_attribute
|
333
|
-
options[:attribute] || 'values'
|
334
|
-
end
|
335
|
-
end
|
336
|
-
end
|
337
|
-
end
|
data/lib/validate/errors.rb
DELETED
@@ -1,40 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Validate
|
4
|
-
module Error
|
5
|
-
class StandardError < ::StandardError
|
6
|
-
include Error
|
7
|
-
end
|
8
|
-
|
9
|
-
class ArgumentError < ::ArgumentError
|
10
|
-
include Error
|
11
|
-
end
|
12
|
-
|
13
|
-
class KeyError < ::KeyError
|
14
|
-
include Error
|
15
|
-
end
|
16
|
-
|
17
|
-
class IndexError < ::IndexError
|
18
|
-
include Error
|
19
|
-
end
|
20
|
-
|
21
|
-
class ValidationRuleError < StandardError
|
22
|
-
end
|
23
|
-
|
24
|
-
class ConstraintViolationError < StandardError
|
25
|
-
attr_reader :violations
|
26
|
-
|
27
|
-
def initialize(violations)
|
28
|
-
@violations = violations
|
29
|
-
super()
|
30
|
-
end
|
31
|
-
|
32
|
-
def message
|
33
|
-
@violations.group_by(&:path)
|
34
|
-
.transform_values { |violations| violations.map(&:message) }
|
35
|
-
.map { |path, messages| "#{path}: #{messages.join(' ')}" }
|
36
|
-
.join("\n")
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
data/lib/validate/helpers.rb
DELETED
data/lib/validate/scope.rb
DELETED
@@ -1,48 +0,0 @@
|
|
1
|
-
# typed: strict
|
2
|
-
# frozen_string_literal: true
|
3
|
-
|
4
|
-
module Validate
|
5
|
-
class Scope
|
6
|
-
def self.current
|
7
|
-
@current ||= Scope.new
|
8
|
-
end
|
9
|
-
|
10
|
-
def initialize
|
11
|
-
@constraints = {}
|
12
|
-
@validators = {}
|
13
|
-
end
|
14
|
-
|
15
|
-
def register_validator(name, validator)
|
16
|
-
if @validators.include?(name)
|
17
|
-
raise Error::ArgumentError,
|
18
|
-
"duplicate validator :#{name}"
|
19
|
-
end
|
20
|
-
|
21
|
-
@validators[name] = validator
|
22
|
-
end
|
23
|
-
|
24
|
-
def validator?(name)
|
25
|
-
@validators.include?(name)
|
26
|
-
end
|
27
|
-
|
28
|
-
def validator(name)
|
29
|
-
validator_name.assert(name,
|
30
|
-
message: "invalid validator #{name.inspect}",
|
31
|
-
error_class: KeyError)
|
32
|
-
|
33
|
-
@validators.fetch(name) { name.validator }
|
34
|
-
end
|
35
|
-
|
36
|
-
private
|
37
|
-
|
38
|
-
def validator_name
|
39
|
-
@validator_name ||= Assertions.create(@validators) do |validators|
|
40
|
-
not_nil(message: 'name must not be nil')
|
41
|
-
(one_of(values: validators,
|
42
|
-
message: '%{value.inspect} must be an existing validator name') |
|
43
|
-
respond_to(:validator,
|
44
|
-
message: '%{value.inspect} must respond to :validator'))
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
@@ -1,44 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Validate
|
4
|
-
module Validators
|
5
|
-
module DSL
|
6
|
-
include Arguments
|
7
|
-
|
8
|
-
arg(:name) { is_a(Module) | (is_a(Symbol) & not_blank) }
|
9
|
-
def define(name, &body)
|
10
|
-
Scope.current.register_validator(name, create(&body))
|
11
|
-
end
|
12
|
-
|
13
|
-
def create(&block)
|
14
|
-
Validator.new(&block)
|
15
|
-
end
|
16
|
-
|
17
|
-
def none
|
18
|
-
@none ||= Validator::None.new
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
class Validator
|
23
|
-
def initialize(&block)
|
24
|
-
@constraints = AST::DefinitionContext.create(&block)
|
25
|
-
end
|
26
|
-
|
27
|
-
def validate(ctx)
|
28
|
-
@constraints.evaluate(ctx)
|
29
|
-
end
|
30
|
-
|
31
|
-
private
|
32
|
-
|
33
|
-
class None < Validator
|
34
|
-
NO_VIOLATIONS = [].freeze
|
35
|
-
|
36
|
-
def initialize; end
|
37
|
-
|
38
|
-
def validate(*args)
|
39
|
-
NO_VIOLATIONS
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|