dry-validation 0.3.1 → 0.4.0
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/CHANGELOG.md +16 -0
- data/README.md +35 -499
- data/lib/dry/validation/error_compiler.rb +9 -4
- data/lib/dry/validation/hint_compiler.rb +69 -0
- data/lib/dry/validation/predicate.rb +0 -4
- data/lib/dry/validation/result.rb +8 -0
- data/lib/dry/validation/rule.rb +44 -0
- data/lib/dry/validation/rule/check.rb +15 -0
- data/lib/dry/validation/rule/composite.rb +20 -7
- data/lib/dry/validation/rule/result.rb +46 -0
- data/lib/dry/validation/rule_compiler.rb +14 -0
- data/lib/dry/validation/schema.rb +33 -3
- data/lib/dry/validation/schema/definition.rb +25 -4
- data/lib/dry/validation/schema/key.rb +8 -8
- data/lib/dry/validation/schema/result.rb +15 -2
- data/lib/dry/validation/schema/rule.rb +32 -5
- data/lib/dry/validation/schema/value.rb +15 -6
- data/lib/dry/validation/version.rb +1 -1
- data/spec/integration/custom_error_messages_spec.rb +1 -1
- data/spec/integration/error_compiler_spec.rb +30 -56
- data/spec/integration/hints_spec.rb +39 -0
- data/spec/integration/localized_error_messages_spec.rb +2 -2
- data/spec/integration/schema/check_rules_spec.rb +28 -0
- data/spec/integration/schema/each_with_set_spec.rb +71 -0
- data/spec/integration/schema/nested_spec.rb +31 -0
- data/spec/integration/schema/not_spec.rb +34 -0
- data/spec/integration/schema/xor_spec.rb +32 -0
- data/spec/integration/schema_form_spec.rb +2 -2
- data/spec/integration/schema_spec.rb +1 -1
- data/spec/shared/predicates.rb +2 -0
- data/spec/spec_helper.rb +2 -2
- data/spec/unit/hint_compiler_spec.rb +32 -0
- data/spec/unit/predicate_spec.rb +0 -10
- data/spec/unit/rule/check_spec.rb +29 -0
- data/spec/unit/rule_compiler_spec.rb +44 -7
- data/spec/unit/schema/rule_spec.rb +31 -0
- data/spec/unit/schema/value_spec.rb +84 -0
- metadata +24 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8bb5ae409a8e2f6c8aca26fd536cd36acf079d47
|
4
|
+
data.tar.gz: e75a4be1f0dc512db4b4e60b8b3651ee9b1ab480
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6c186c20423a18a808289dc9823f80e77d5b10239d42918bdbde1c2b2ebb0cd70591f6450edf96a9b7adc526fc98c722ceb553b59fca5d5eba602977015d8459
|
7
|
+
data.tar.gz: 30d0e0faaebcdd2fa25ea687f6e07023a8eb9a39094a6feb32a36c6e52d69ff28dbe6bb3d48be2f0077f0d1df9b8df8379e544e3937f84b2a5c78bc8fc755c85
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,19 @@
|
|
1
|
+
# v0.4.0 2015-12-21
|
2
|
+
|
3
|
+
### Added
|
4
|
+
|
5
|
+
* Support for high-level rule composition via `rule` interface (solnic)
|
6
|
+
* Support for exclusive disjunction (aka xor/^ operator) (solnic)
|
7
|
+
* Support for nested schemas within a schema class (solnic)
|
8
|
+
* Support for negating rules via `rule(name).not` (solnic)
|
9
|
+
* Support for `validation hints` that are included in the error messages (solnic)
|
10
|
+
|
11
|
+
### Fixed
|
12
|
+
|
13
|
+
* Error messages hash has now consistent structure `rule_name => [msgs_array, input_value]` (solnic)
|
14
|
+
|
15
|
+
[Compare v0.3.1...v0.4.0](https://github.com/dryrb/dry-validation/compare/v0.3.1...v0.4.0)
|
16
|
+
|
1
17
|
# v0.3.1 2015-12-08
|
2
18
|
|
3
19
|
### Added
|
data/README.md
CHANGED
@@ -23,537 +23,73 @@ a different approach and focuses a lot on explicitness, clarity and preciseness
|
|
23
23
|
of validation logic. It is designed to work with any data input, whether it's a
|
24
24
|
simple hash, an array or a complex object with deeply nested data.
|
25
25
|
|
26
|
-
It is based on
|
26
|
+
It is based on an idea that each validation is encapsulated by a simple,
|
27
27
|
stateless predicate, that receives some input and returns either `true` or `false`.
|
28
28
|
|
29
29
|
Those predicates are encapsulated by `rules` which can be composed together using
|
30
30
|
`predicate logic`. This means you can use the common logic operators to build up
|
31
31
|
a validation `schema`.
|
32
32
|
|
33
|
-
It's very explicit, powerful and extendible.
|
34
|
-
|
35
33
|
Validations can be described with great precision, `dry-validation` eliminates
|
36
34
|
ambigious concepts like `presence` validation where we can't really say whether
|
37
35
|
some attribute or key is *missing* or it's just that the value is `nil`.
|
38
36
|
|
39
|
-
|
40
|
-
libraries,
|
41
|
-
that does rely on the type of a given value. In
|
42
|
-
each element of an array when it turns out to
|
37
|
+
In `dry-validation` type-safety is a first-class feature, something that's completely
|
38
|
+
missing in other validation libraries, and it's an important and useful feature. It
|
39
|
+
means you can compose a validation that does rely on the type of a given value. In
|
40
|
+
example it makes no sense to validate each element of an array when it turns out to
|
41
|
+
be an empty string.
|
43
42
|
|
44
43
|
## The DSL
|
45
44
|
|
46
|
-
The core of `dry-validation` is
|
45
|
+
The core of `dry-validation` is rule composition and predicate logic. The DSL
|
47
46
|
is a simple front-end for that. It only allows you to define the rules by using
|
48
47
|
predicate identifiers. There are no magical options, conditionals and custom
|
49
48
|
validation blocks known from other libraries. The focus is on pure validation
|
50
|
-
logic.
|
51
|
-
|
52
|
-
## Examples
|
53
|
-
|
54
|
-
### Basic
|
55
|
-
|
56
|
-
Here's a basic example where we validate following things:
|
57
|
-
|
58
|
-
* The input *must have a key* called `:email`
|
59
|
-
* Provided the email key is present, its value *must be filled*
|
60
|
-
* The input *must have a key* called `:age`
|
61
|
-
* Provided the age key is present, its value *must be an integer* and it *must be greater than 18*
|
62
|
-
|
63
|
-
This can be easily expressed through the DSL:
|
49
|
+
logic expressed in a concise way.
|
64
50
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
class Schema < Dry::Validation::Schema
|
69
|
-
key(:email) { |email| email.filled? }
|
70
|
-
|
71
|
-
key(:age) do |age|
|
72
|
-
age.int? & age.gt?(18)
|
73
|
-
end
|
74
|
-
end
|
51
|
+
The DSL is very abstract, it builds [a rule AST](https://github.com/dryrb/dry-validation/wiki/Rule-AST)
|
52
|
+
which is compiled into an array of rule objects. This means alternative interfaces could
|
53
|
+
be easily build.
|
75
54
|
|
76
|
-
|
55
|
+
## When To Use?
|
77
56
|
|
78
|
-
|
57
|
+
Always and everywhere. This is a general-purpose validation library that can be used for many things and **it's multiple times faster** than `ActiveRecord`/`ActiveModel::Validations` *and* `strong-parameters`.
|
79
58
|
|
80
|
-
|
81
|
-
# []
|
59
|
+
Possible use-cases include validation of:
|
82
60
|
|
83
|
-
|
61
|
+
* Form params
|
62
|
+
* "GET" params
|
63
|
+
* JSON documents
|
64
|
+
* YAML documents
|
65
|
+
* Application configuration (ie stored in ENV)
|
66
|
+
* Replacement for `ActiveRecord`/`ActiveModel::Validations`
|
67
|
+
* Replacement for `strong-parameters`
|
68
|
+
* etc.
|
84
69
|
|
85
|
-
|
86
|
-
# { :email => [["email must be filled", nil]] }
|
87
|
-
```
|
70
|
+
## Synopsis
|
88
71
|
|
89
|
-
|
90
|
-
|
91
|
-
* `key` assumes that we want to use the `:key?` predicate to check the existance of that key
|
92
|
-
* `age.gt?(18)` translates to calling a predicate like this: `schema[:gt?].(18, age)`
|
93
|
-
* `age.int? & age.gt?(18)` is a conjunction, so we don't bother about `gt?` unless `int?` returns `true`
|
94
|
-
* You can also use `|` for disjunction
|
95
|
-
* Schema object does not carry the input as its state, nor does it know how to access the input values, we
|
96
|
-
pass the input to `call` and get error set as the response
|
97
|
-
|
98
|
-
### Optional Keys
|
99
|
-
|
100
|
-
You can define which keys are optional and define rules for their values:
|
72
|
+
Please refer to [the wiki](https://github.com/dryrb/dry-validation/wiki) for full usage documentation.
|
101
73
|
|
102
74
|
``` ruby
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
key(:email) { |email| email.filled? }
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
end
|
111
|
-
end
|
112
|
-
|
113
|
-
schema = Schema.new
|
114
|
-
|
115
|
-
errors = schema.call(email: 'jane@doe.org').messages
|
116
|
-
|
117
|
-
puts errors.inspect
|
118
|
-
# []
|
119
|
-
|
120
|
-
errors = schema.call(email: 'jane@doe.org', age: 17).messages
|
121
|
-
|
122
|
-
puts errors.inspect
|
123
|
-
# { :age => [["age must be greater than 18"], 17] }
|
124
|
-
```
|
125
|
-
|
126
|
-
### Optional Values
|
127
|
-
|
128
|
-
When it is valid for a given value to be `nil` you can use `none?` predicate:
|
129
|
-
|
130
|
-
``` ruby
|
131
|
-
require 'dry-validation'
|
132
|
-
|
133
|
-
class Schema < Dry::Validation::Schema
|
134
|
-
key(:email) { |email| email.filled? }
|
135
|
-
|
136
|
-
key(:age) do |age|
|
137
|
-
age.none? | (age.int? & age.gt?(18))
|
138
|
-
end
|
139
|
-
end
|
140
|
-
|
141
|
-
schema = Schema.new
|
142
|
-
|
143
|
-
errors = schema.call(email: 'jane@doe.org', age: nil).messages
|
144
|
-
|
145
|
-
puts errors.inspect
|
146
|
-
# []
|
147
|
-
|
148
|
-
errors = schema.call(email: 'jane@doe.org', age: 19).messages
|
149
|
-
|
150
|
-
puts errors.inspect
|
151
|
-
# []
|
152
|
-
|
153
|
-
errors = schema.call(email: 'jane@doe.org', age: 17).messages
|
154
|
-
|
155
|
-
puts errors.inspect
|
156
|
-
# { :age => [["age must be greater than 18"], 17] }
|
157
|
-
```
|
158
|
-
|
159
|
-
### Optional Key vs Value
|
160
|
-
|
161
|
-
We make a clear distinction between specifying an optional `key` and an optional
|
162
|
-
`value`. This gives you a way of being very specific about validation rules. You
|
163
|
-
can define a schema which can give you precise errors when a key was missing or
|
164
|
-
key was present but the value was nil.
|
165
|
-
|
166
|
-
This also comes with the benefit of being explicit about the type expectation.
|
167
|
-
In the example above we explicitly state that `:age` *can be nil* or it *can be an integer*
|
168
|
-
and when it *is an integer* we specify that it *must be greater than 18*.
|
169
|
-
|
170
|
-
Another benefit is that we can infer specific coercion rules when types are specified.
|
171
|
-
In example [`Schema::Form`](https://github.com/dryrb/dry-validation#form-validation-with-coercions)
|
172
|
-
will use `form.nil` type from dry-data to coerce empty strings into `nil` for you
|
173
|
-
whenever you specify `value.none? | value.int?`. Furthermore it will try to coerce
|
174
|
-
to `int` since that is our type expectation.
|
175
|
-
|
176
|
-
### Nested Hash
|
177
|
-
|
178
|
-
We are free to define validations for anything, including deeply nested structures:
|
179
|
-
|
180
|
-
``` ruby
|
181
|
-
require 'dry-validation'
|
182
|
-
|
183
|
-
class Schema < Dry::Validation::Schema
|
75
|
+
class UserSchema < Dry::Validation::Schema
|
76
|
+
key(:name) { |name| name.filled? }
|
77
|
+
|
78
|
+
key(:email) { |email| email.filled? & email.format?(EMAIL_REGEX) }
|
79
|
+
|
80
|
+
key(:age) { |age| age.none? | age.int? }
|
81
|
+
|
184
82
|
key(:address) do |address|
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
end
|
189
|
-
|
190
|
-
address.key(:street) do |street|
|
191
|
-
street.filled?
|
192
|
-
end
|
193
|
-
|
194
|
-
address.key(:country) do |country|
|
195
|
-
country.key(:name, &:filled?)
|
196
|
-
country.key(:code, &:filled?)
|
197
|
-
end
|
198
|
-
end
|
199
|
-
end
|
200
|
-
end
|
201
|
-
|
202
|
-
schema = Schema.new
|
203
|
-
|
204
|
-
errors = schema.call({}).messages
|
205
|
-
|
206
|
-
puts errors.inspect
|
207
|
-
# { :address => ["address is missing"] }
|
208
|
-
|
209
|
-
errors = schema.call(address: { city: 'NYC' }).messages
|
210
|
-
|
211
|
-
puts errors.to_h.inspect
|
212
|
-
# {
|
213
|
-
# :address => [
|
214
|
-
# { :street => ["street is missing"] },
|
215
|
-
# { :country => ["country is missing"] }
|
216
|
-
# ]
|
217
|
-
# }
|
218
|
-
```
|
219
|
-
|
220
|
-
### Array Elements
|
221
|
-
|
222
|
-
You can use `each` rule for validating each element in an array:
|
223
|
-
|
224
|
-
``` ruby
|
225
|
-
class Schema < Dry::Validation::Schema
|
226
|
-
key(:phone_numbers) do |phone_numbers|
|
227
|
-
phone_numbers.array? do
|
228
|
-
phone_numbers.each(&:str?)
|
229
|
-
end
|
230
|
-
end
|
231
|
-
end
|
232
|
-
|
233
|
-
schema = Schema.new
|
234
|
-
|
235
|
-
errors = schema.call(phone_numbers: '').messages
|
236
|
-
|
237
|
-
puts errors.inspect
|
238
|
-
# { :phone_numbers => [["phone_numbers must be an array", ""]] }
|
239
|
-
|
240
|
-
errors = schema.call(phone_numbers: ['123456789', 123456789]).messages
|
241
|
-
|
242
|
-
puts errors.inspect
|
243
|
-
# {
|
244
|
-
# :phone_numbers => [
|
245
|
-
# {
|
246
|
-
# :phone_numbers => [
|
247
|
-
# ["phone_numbers must be a string", 123456789]
|
248
|
-
# ]
|
249
|
-
# }
|
250
|
-
# ]
|
251
|
-
# }
|
252
|
-
```
|
253
|
-
|
254
|
-
### Rules Depending On Other Rules
|
255
|
-
|
256
|
-
When a rule needs input from other rules and depends on their results you can
|
257
|
-
define it using `rule` DSL. A common example of this is "confirmation validation":
|
258
|
-
|
259
|
-
``` ruby
|
260
|
-
class Schema < Dry::Validation::Schema
|
261
|
-
key(:password, &:filled?)
|
262
|
-
key(:password_confirmation, &:filled?)
|
263
|
-
|
264
|
-
rule(:password_confirmation, eql?: [:password, :password_confirmation])
|
265
|
-
end
|
266
|
-
```
|
267
|
-
|
268
|
-
A short version of the same thing:
|
269
|
-
|
270
|
-
``` ruby
|
271
|
-
class Schema < Dry::Validation::Schema
|
272
|
-
confirmation(:password)
|
273
|
-
end
|
274
|
-
```
|
275
|
-
|
276
|
-
Notice that you must add `:password_confirmation` error message configuration if
|
277
|
-
you want to have the error converted to a message.
|
278
|
-
|
279
|
-
### Form Validation With Coercions
|
280
|
-
|
281
|
-
Probably the most common use case is to validate form params. This is a special
|
282
|
-
kind of a validation for a couple of reasons:
|
283
|
-
|
284
|
-
* The input is a hash with stringified keys
|
285
|
-
* The input include values that are strings, hashes or arrays
|
286
|
-
* Prior validation, we need to coerce values and symbolize keys based on the
|
287
|
-
information from rules
|
288
|
-
|
289
|
-
For that reason, `dry-validation` ships with `Schema::Form` class:
|
290
|
-
|
291
|
-
``` ruby
|
292
|
-
require 'dry-validation'
|
293
|
-
require 'dry/validation/schema/form'
|
294
|
-
|
295
|
-
class UserFormSchema < Dry::Validation::Schema::Form
|
296
|
-
key(:email) { |value| value.str? & value.filled? }
|
297
|
-
|
298
|
-
key(:age) { |value| value.int? & value.gt?(18) }
|
299
|
-
end
|
300
|
-
|
301
|
-
schema = UserFormSchema.new
|
302
|
-
|
303
|
-
errors = schema.call('email' => '', 'age' => '18').messages
|
304
|
-
|
305
|
-
puts errors.inspect
|
306
|
-
# {
|
307
|
-
# :email => [["email must be filled", nil]],
|
308
|
-
# :age => [["age must be greater than 18 (18 was given)", 18]]
|
309
|
-
# }
|
310
|
-
```
|
311
|
-
|
312
|
-
There are few major differences between how it works here and in `ActiveModel`:
|
313
|
-
|
314
|
-
* We have type checking as predicates, ie `gt?(18)` will not be applied if the value
|
315
|
-
is not an integer
|
316
|
-
* Thus, error messages are provided *only for the rules that failed*
|
317
|
-
* There's a planned feature for generating "validation hints" which lists information
|
318
|
-
about all possible rules
|
319
|
-
* Coercion is handled by `dry-data` coercible hash using its `form.*` types that
|
320
|
-
are dedicated for this type of coercions
|
321
|
-
* It's very easy to add your own types and coercions (more info/docs coming soon)
|
322
|
-
|
323
|
-
### Defining Custom Predicates
|
324
|
-
|
325
|
-
You can simply define predicate methods on your schema object:
|
326
|
-
|
327
|
-
``` ruby
|
328
|
-
class Schema < Dry::Validation::Schema
|
329
|
-
key(:email) { |value| value.str? & value.email? }
|
330
|
-
|
331
|
-
def email?(value)
|
332
|
-
! /magical-regex-that-matches-emails/.match(value).nil?
|
83
|
+
address.key(:street, &:filled?)
|
84
|
+
address.key(:city, &:filled?)
|
85
|
+
address.key(:zipcode, &:filled?)
|
333
86
|
end
|
334
87
|
end
|
335
88
|
```
|
336
89
|
|
337
|
-
You can also re-use a predicate container across multiple schemas:
|
338
|
-
|
339
|
-
``` ruby
|
340
|
-
module MyPredicates
|
341
|
-
include Dry::Validation::Predicates
|
342
|
-
|
343
|
-
predicate(:email?) do |input|
|
344
|
-
! /magical-regex-that-matches-emails/.match(value).nil?
|
345
|
-
end
|
346
|
-
end
|
347
|
-
|
348
|
-
class Schema < Dry::Validation::Schema
|
349
|
-
configure do |config|
|
350
|
-
config.predicates = MyPredicates
|
351
|
-
end
|
352
|
-
|
353
|
-
key(:email) { |value| value.str? & value.email? }
|
354
|
-
end
|
355
|
-
```
|
356
|
-
|
357
|
-
You need to provide error messages for your custom predicates if you want them
|
358
|
-
to work with `Schem#messages` interface.
|
359
|
-
|
360
|
-
You can learn how to do that in the [Error Messages](https://github.com/dryrb/dry-validation#error-messages) section.
|
361
|
-
|
362
|
-
## List of Built-In Predicates
|
363
|
-
|
364
|
-
### Basic
|
365
|
-
|
366
|
-
* `none?`
|
367
|
-
* `eql?`
|
368
|
-
* `key?`
|
369
|
-
|
370
|
-
### Types
|
371
|
-
|
372
|
-
* `str?`
|
373
|
-
* `int?`
|
374
|
-
* `float?`
|
375
|
-
* `decimal?`
|
376
|
-
* `bool?`
|
377
|
-
* `date?`
|
378
|
-
* `date_time?`
|
379
|
-
* `time?`
|
380
|
-
* `array?`
|
381
|
-
* `hash?`
|
382
|
-
|
383
|
-
### Number, String, Collection
|
384
|
-
|
385
|
-
* `empty?`
|
386
|
-
* `filled?`
|
387
|
-
* `gt?`
|
388
|
-
* `gteq?`
|
389
|
-
* `lt?`
|
390
|
-
* `lteq?`
|
391
|
-
* `max_size?`
|
392
|
-
* `min_size?`
|
393
|
-
* `size?(int)`
|
394
|
-
* `size?(range)`
|
395
|
-
* `format?`
|
396
|
-
* `inclusion?`
|
397
|
-
* `exclusion?`
|
398
|
-
|
399
|
-
## Error Messages
|
400
|
-
|
401
|
-
By default `dry-validation` comes with a set of pre-defined error messages for
|
402
|
-
every built-in predicate. They are defined in [a yaml file](https://github.com/dryrb/dry-validation/blob/master/config/errors.yml)
|
403
|
-
which is shipped with the gem. This file is compatible with `I18n` format.
|
404
|
-
|
405
|
-
You can provide your own messages and configure your schemas to use it like that:
|
406
|
-
|
407
|
-
``` ruby
|
408
|
-
class Schema < Dry::Validation::Schema
|
409
|
-
configure { |config| config.messages_file = '/path/to/my/errors.yml' }
|
410
|
-
end
|
411
|
-
```
|
412
|
-
|
413
|
-
You can also provide a namespace per-schema that will be used by default:
|
414
|
-
|
415
|
-
``` ruby
|
416
|
-
class Schema < Dry::Validation::Schema
|
417
|
-
configure { |config| config.namespace = :user }
|
418
|
-
end
|
419
|
-
```
|
420
|
-
|
421
|
-
Lookup rules:
|
422
|
-
|
423
|
-
``` yaml
|
424
|
-
en:
|
425
|
-
errors:
|
426
|
-
size?:
|
427
|
-
arg:
|
428
|
-
default: "%{name} size must be %{num}"
|
429
|
-
range: "%{name} size must be within %{left} - %{right}"
|
430
|
-
|
431
|
-
value:
|
432
|
-
string:
|
433
|
-
arg:
|
434
|
-
default: "%{name} length must be %{num}"
|
435
|
-
range: "%{name} length must be within %{left} - %{right}"
|
436
|
-
|
437
|
-
filled?: "%{name} must be filled"
|
438
|
-
|
439
|
-
rules:
|
440
|
-
email:
|
441
|
-
filled?: "the email is missing"
|
442
|
-
|
443
|
-
user:
|
444
|
-
filled?: "%{name} name cannot be blank"
|
445
|
-
|
446
|
-
rules:
|
447
|
-
address:
|
448
|
-
filled?: "You gotta tell us where you live"
|
449
|
-
```
|
450
|
-
|
451
|
-
Given the yaml file above, messages lookup works as follows:
|
452
|
-
|
453
|
-
``` ruby
|
454
|
-
messages = Dry::Validation::Messages.load('/path/to/our/errors.yml')
|
455
|
-
|
456
|
-
# matching arg type for size? predicate
|
457
|
-
messages[:size?, rule: :name, arg_type: Fixnum] # => "%{name} size must be %{num}"
|
458
|
-
messages[:size?, rule: :name, arg_type: Range] # => "%{name} size must within %{left} - %{right}"
|
459
|
-
|
460
|
-
# matching val type for size? predicate
|
461
|
-
messages[:size?, rule: :name, val_type: String] # => "%{name} length must be %{num}"
|
462
|
-
|
463
|
-
# matching predicate
|
464
|
-
messages[:filled?, rule: :age] # => "%{name} must be filled"
|
465
|
-
messages[:filled?, rule: :address] # => "%{name} must be filled"
|
466
|
-
|
467
|
-
# matching predicate for a specific rule
|
468
|
-
messages[:filled?, rule: :email] # => "the email is missing"
|
469
|
-
|
470
|
-
# with namespaced messages
|
471
|
-
user_messages = messages.namespaced(:user)
|
472
|
-
|
473
|
-
user_messages[:filled?, rule: :age] # "%{name} cannot be blank"
|
474
|
-
user_messages[:filled?, rule: :address] # "You gotta tell us where you live"
|
475
|
-
```
|
476
|
-
|
477
|
-
By configuring `messages_file` and/or `namespace` in a schema, default messages
|
478
|
-
are going to be automatically merged with your overrides and/or namespaced.
|
479
|
-
|
480
|
-
## I18n Integration
|
481
|
-
|
482
|
-
If you are using `i18n` gem and load it before `dry-validation` then you'll be
|
483
|
-
able to configure a schema to use `i18n` messages:
|
484
|
-
|
485
|
-
``` ruby
|
486
|
-
require 'i18n'
|
487
|
-
require 'dry-validation'
|
488
|
-
|
489
|
-
class Schema < Dry::Validation::Schema
|
490
|
-
configure { config.messages = :i18n }
|
491
|
-
|
492
|
-
key(:email, &:filled?)
|
493
|
-
end
|
494
|
-
|
495
|
-
schema = Schema.new
|
496
|
-
|
497
|
-
# return default translations
|
498
|
-
puts schema.call(email: '').messages
|
499
|
-
{ :email => ["email must be filled"] }
|
500
|
-
|
501
|
-
# return other translations (assuming you have it :))
|
502
|
-
puts schema.call(email: '').messages(locale: :pl)
|
503
|
-
{ :email => ["email musi być wypełniony"] }
|
504
|
-
```
|
505
|
-
|
506
|
-
Important: I18n must be initialized before using schema, `dry-validation` does
|
507
|
-
not try to do it for you, it only sets its default error translations automatically.
|
508
|
-
|
509
|
-
## Rule AST
|
510
|
-
|
511
|
-
Internally, `dry-validation` uses a simple AST representation of rules and errors
|
512
|
-
to produce rule objects and error messages. If you would like to programatically
|
513
|
-
generate rules, it is a very simple process:
|
514
|
-
|
515
|
-
``` ruby
|
516
|
-
ast = [
|
517
|
-
[
|
518
|
-
:and,
|
519
|
-
[
|
520
|
-
[:key, [:age, [:predicate, [:key?, []]]]],
|
521
|
-
[
|
522
|
-
:and,
|
523
|
-
[
|
524
|
-
[:val, [:age, [:predicate, [:filled?, []]]]],
|
525
|
-
[:val, [:age, [:predicate, [:gt?, [18]]]]]
|
526
|
-
]
|
527
|
-
]
|
528
|
-
]
|
529
|
-
]
|
530
|
-
]
|
531
|
-
|
532
|
-
compiler = Dry::Validation::RuleCompiler.new(Dry::Validation::Predicates)
|
533
|
-
|
534
|
-
# compile an array of rule objects
|
535
|
-
rules = compiler.call(ast)
|
536
|
-
|
537
|
-
puts rules.inspect
|
538
|
-
# [
|
539
|
-
# #<Dry::Validation::Rule::Conjunction
|
540
|
-
# left=#<Dry::Validation::Rule::Key name=:age predicate=#<Dry::Validation::Predicate id=:key?>>
|
541
|
-
# right=#<Dry::Validation::Rule::Conjunction
|
542
|
-
# left=#<Dry::Validation::Rule::Value name=:age predicate=#<Dry::Validation::Predicate id=:filled?>>
|
543
|
-
# right=#<Dry::Validation::Rule::Value name=:age predicate=#<Dry::Validation::Predicate id=:gt?>>>>
|
544
|
-
# ]
|
545
|
-
|
546
|
-
# dump it back to ast
|
547
|
-
puts rules.map(&:to_ary).inspect
|
548
|
-
# [[:and, [:key, [:age, [:predicate, [:key?, [:age]]]]], [[:and, [:val, [:age, [:predicate, [:filled?, []]]]], [[:val, [:age, [:predicate, [:gt?, [18]]]]]]]]]]
|
549
|
-
```
|
550
|
-
|
551
|
-
Complete docs for the AST format are coming soon, for now please refer to
|
552
|
-
[this spec](https://github.com/dryrb/dry-validation/blob/master/spec/unit/rule_compiler_spec.rb).
|
553
|
-
|
554
90
|
## Status and Roadmap
|
555
91
|
|
556
|
-
This library is in
|
92
|
+
This library is in an early stage of development but you are encauraged to
|
557
93
|
try it out and provide feedback.
|
558
94
|
|
559
95
|
For planned features check out [the issues](https://github.com/dryrb/dry-validation/labels/feature).
|