dry-validation 0.7.4 → 0.8.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.
Files changed (143) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.travis.yml +9 -6
  4. data/CHANGELOG.md +58 -0
  5. data/Gemfile +3 -3
  6. data/benchmarks/benchmark_form_invalid.rb +64 -0
  7. data/benchmarks/benchmark_form_valid.rb +64 -0
  8. data/benchmarks/profile_schema_call_invalid.rb +20 -0
  9. data/benchmarks/profile_schema_call_valid.rb +20 -0
  10. data/benchmarks/profile_schema_definition.rb +14 -0
  11. data/benchmarks/profile_schema_messages_invalid.rb +20 -0
  12. data/benchmarks/suite.rb +5 -0
  13. data/config/errors.yml +12 -5
  14. data/dry-validation.gemspec +2 -2
  15. data/examples/basic.rb +2 -2
  16. data/examples/form.rb +2 -2
  17. data/examples/json.rb +2 -2
  18. data/examples/nested.rb +6 -6
  19. data/lib/dry/validation.rb +22 -3
  20. data/lib/dry/validation/deprecations.rb +23 -0
  21. data/lib/dry/validation/error_compiler.rb +31 -11
  22. data/lib/dry/validation/error_compiler/input.rb +44 -57
  23. data/lib/dry/validation/hint_compiler.rb +15 -7
  24. data/lib/dry/validation/input_processor_compiler.rb +13 -6
  25. data/lib/dry/validation/input_processor_compiler/form.rb +2 -0
  26. data/lib/dry/validation/input_processor_compiler/sanitizer.rb +1 -1
  27. data/lib/dry/validation/messages/abstract.rb +9 -1
  28. data/lib/dry/validation/predicate_registry.rb +101 -0
  29. data/lib/dry/validation/result.rb +8 -1
  30. data/lib/dry/validation/schema.rb +110 -44
  31. data/lib/dry/validation/schema/check.rb +4 -2
  32. data/lib/dry/validation/schema/deprecated.rb +31 -0
  33. data/lib/dry/validation/schema/dsl.rb +18 -11
  34. data/lib/dry/validation/schema/form.rb +1 -0
  35. data/lib/dry/validation/schema/json.rb +1 -0
  36. data/lib/dry/validation/schema/key.rb +23 -10
  37. data/lib/dry/validation/schema/rule.rb +81 -20
  38. data/lib/dry/validation/schema/value.rb +110 -25
  39. data/lib/dry/validation/version.rb +1 -1
  40. data/spec/fixtures/locales/en.yml +1 -0
  41. data/spec/fixtures/locales/pl.yml +1 -1
  42. data/spec/integration/custom_error_messages_spec.rb +2 -2
  43. data/spec/integration/custom_predicates_spec.rb +98 -15
  44. data/spec/integration/error_compiler_spec.rb +111 -96
  45. data/spec/integration/form/predicates/array_spec.rb +243 -0
  46. data/spec/integration/form/predicates/empty_spec.rb +263 -0
  47. data/spec/integration/form/predicates/eql_spec.rb +327 -0
  48. data/spec/integration/form/predicates/even_spec.rb +455 -0
  49. data/spec/integration/form/predicates/excluded_from_spec.rb +455 -0
  50. data/spec/integration/form/predicates/excludes_spec.rb +391 -0
  51. data/spec/integration/form/predicates/false_spec.rb +455 -0
  52. data/spec/integration/form/predicates/filled_spec.rb +467 -0
  53. data/spec/integration/form/predicates/format_spec.rb +454 -0
  54. data/spec/integration/form/predicates/gt_spec.rb +519 -0
  55. data/spec/integration/form/predicates/gteq_spec.rb +519 -0
  56. data/spec/integration/form/predicates/included_in_spec.rb +455 -0
  57. data/spec/integration/form/predicates/includes_spec.rb +391 -0
  58. data/spec/integration/form/predicates/key_spec.rb +75 -0
  59. data/spec/integration/form/predicates/lt_spec.rb +519 -0
  60. data/spec/integration/form/predicates/lteq_spec.rb +519 -0
  61. data/spec/integration/form/predicates/max_size_spec.rb +391 -0
  62. data/spec/integration/form/predicates/min_size_spec.rb +391 -0
  63. data/spec/integration/form/predicates/none_spec.rb +265 -0
  64. data/spec/integration/form/predicates/not_eql_spec.rb +327 -0
  65. data/spec/integration/form/predicates/odd_spec.rb +455 -0
  66. data/spec/integration/form/predicates/size/fixed_spec.rb +399 -0
  67. data/spec/integration/form/predicates/size/range_spec.rb +398 -0
  68. data/spec/integration/form/predicates/true_spec.rb +455 -0
  69. data/spec/integration/form/predicates/type_spec.rb +391 -0
  70. data/spec/integration/hints_spec.rb +90 -4
  71. data/spec/integration/injecting_rules_spec.rb +2 -2
  72. data/spec/integration/localized_error_messages_spec.rb +2 -2
  73. data/spec/integration/messages/i18n_spec.rb +3 -3
  74. data/spec/integration/optional_keys_spec.rb +3 -3
  75. data/spec/integration/schema/array_schema_spec.rb +49 -13
  76. data/spec/integration/schema/check_rules_spec.rb +6 -6
  77. data/spec/integration/schema/check_with_nested_el_spec.rb +3 -3
  78. data/spec/integration/schema/check_with_nth_el_spec.rb +1 -1
  79. data/spec/integration/schema/each_with_set_spec.rb +3 -3
  80. data/spec/integration/schema/extending_dsl_spec.rb +27 -0
  81. data/spec/integration/schema/form/explicit_types_spec.rb +182 -0
  82. data/spec/integration/schema/form_spec.rb +90 -18
  83. data/spec/integration/schema/hash_schema_spec.rb +47 -0
  84. data/spec/integration/schema/inheriting_schema_spec.rb +4 -4
  85. data/spec/integration/schema/input_processor_spec.rb +8 -8
  86. data/spec/integration/schema/json/explicit_types_spec.rb +157 -0
  87. data/spec/integration/schema/json_spec.rb +18 -18
  88. data/spec/integration/schema/macros/confirmation_spec.rb +1 -1
  89. data/spec/integration/schema/macros/each_spec.rb +177 -43
  90. data/spec/integration/schema/macros/{required_spec.rb → filled_spec.rb} +34 -6
  91. data/spec/integration/schema/macros/input_spec.rb +21 -0
  92. data/spec/integration/schema/macros/maybe_spec.rb +39 -2
  93. data/spec/integration/schema/macros/value_spec.rb +105 -0
  94. data/spec/integration/schema/macros/when_spec.rb +28 -8
  95. data/spec/integration/schema/nested_values_spec.rb +11 -8
  96. data/spec/integration/schema/not_spec.rb +2 -2
  97. data/spec/integration/schema/numbers_spec.rb +1 -1
  98. data/spec/integration/schema/option_with_default_spec.rb +1 -1
  99. data/spec/integration/schema/predicate_verification_spec.rb +9 -0
  100. data/spec/integration/schema/predicates/array_spec.rb +295 -0
  101. data/spec/integration/schema/predicates/custom_spec.rb +103 -0
  102. data/spec/integration/schema/predicates/empty_spec.rb +263 -0
  103. data/spec/integration/schema/predicates/eql_spec.rb +327 -0
  104. data/spec/integration/schema/predicates/even_spec.rb +455 -0
  105. data/spec/integration/schema/predicates/excluded_from_spec.rb +455 -0
  106. data/spec/integration/schema/predicates/excludes_spec.rb +391 -0
  107. data/spec/integration/schema/predicates/filled_spec.rb +467 -0
  108. data/spec/integration/schema/predicates/format_spec.rb +455 -0
  109. data/spec/integration/schema/predicates/gt_spec.rb +519 -0
  110. data/spec/integration/schema/predicates/gteq_spec.rb +519 -0
  111. data/spec/integration/schema/predicates/hash_spec.rb +69 -0
  112. data/spec/integration/schema/predicates/included_in_spec.rb +455 -0
  113. data/spec/integration/schema/predicates/includes_spec.rb +391 -0
  114. data/spec/integration/schema/predicates/key_spec.rb +88 -0
  115. data/spec/integration/schema/predicates/lt_spec.rb +520 -0
  116. data/spec/integration/schema/predicates/lteq_spec.rb +519 -0
  117. data/spec/integration/schema/predicates/max_size_spec.rb +391 -0
  118. data/spec/integration/schema/predicates/min_size_spec.rb +391 -0
  119. data/spec/integration/schema/predicates/none_spec.rb +265 -0
  120. data/spec/integration/schema/predicates/not_eql_spec.rb +391 -0
  121. data/spec/integration/schema/predicates/odd_spec.rb +455 -0
  122. data/spec/integration/schema/predicates/size/fixed_spec.rb +401 -0
  123. data/spec/integration/schema/predicates/size/range_spec.rb +399 -0
  124. data/spec/integration/schema/predicates/type_spec.rb +391 -0
  125. data/spec/integration/schema/reusing_schema_spec.rb +4 -4
  126. data/spec/integration/schema/using_types_spec.rb +24 -6
  127. data/spec/integration/schema/xor_spec.rb +2 -2
  128. data/spec/integration/schema_builders_spec.rb +15 -0
  129. data/spec/integration/schema_spec.rb +37 -12
  130. data/spec/shared/predicate_helper.rb +13 -0
  131. data/spec/spec_helper.rb +10 -0
  132. data/spec/support/matchers.rb +38 -0
  133. data/spec/support/predicates_integration.rb +7 -0
  134. data/spec/unit/hint_compiler_spec.rb +10 -8
  135. data/spec/unit/input_processor_compiler/form_spec.rb +45 -43
  136. data/spec/unit/input_processor_compiler/json_spec.rb +37 -35
  137. data/spec/unit/predicate_registry_spec.rb +34 -0
  138. data/spec/unit/schema/key_spec.rb +12 -14
  139. data/spec/unit/schema/rule_spec.rb +4 -2
  140. data/spec/unit/schema/value_spec.rb +38 -121
  141. metadata +150 -16
  142. data/lib/dry/validation/schema/attr.rb +0 -15
  143. data/spec/integration/attr_spec.rb +0 -122
@@ -0,0 +1,243 @@
1
+ RSpec.describe 'Predicates: Array' do
2
+ context 'with required' do
3
+ subject(:schema) do
4
+ Dry::Validation.Form do
5
+ required(:foo) { array? { each { int? } } }
6
+ end
7
+ end
8
+
9
+ context 'with valid input' do
10
+ let(:input) { { 'foo' => ['3'] } }
11
+
12
+ it 'is successful' do
13
+ expect(result).to be_successful
14
+ end
15
+ end
16
+
17
+ context 'with missing input' do
18
+ let(:input) { {} }
19
+
20
+ it 'is not successful' do
21
+ expect(result).to be_failing ['is missing']
22
+ end
23
+ end
24
+
25
+ context 'with nil input' do
26
+ let(:input) { { 'foo' => nil } }
27
+
28
+ it 'is not successful' do
29
+ expect(result).to be_failing ['must be an array']
30
+ end
31
+ end
32
+
33
+ context 'with blank input' do
34
+ let(:input) { { 'foo' => '' } }
35
+
36
+ it 'is successful' do
37
+ expect(result).to be_successful
38
+ end
39
+ end
40
+
41
+ context 'with invalid type' do
42
+ let(:input) { { 'foo' => { 'a' => '1' } } }
43
+
44
+ it 'is not successful' do
45
+ expect(result).to be_failing ['must be an array']
46
+ end
47
+ end
48
+
49
+ context 'with invalid input (integer)' do
50
+ let(:input) { { 'foo' => '4' } }
51
+
52
+ it 'is not successful' do
53
+ expect(result).to be_failing ['must be an array']
54
+ end
55
+ end
56
+
57
+ context 'with invalid input (array with non-integers)' do
58
+ let(:input) { { 'foo' => %w(foo bar) } }
59
+
60
+ it 'is not successful' do
61
+ expect(result).to be_failing 0 => ['must be an integer'], 1 => ['must be an integer']
62
+ end
63
+ end
64
+
65
+ context 'with invalid input (mixed array)' do
66
+ let(:input) { { 'foo' => %w(1 bar) } }
67
+
68
+ it 'is not successful' do
69
+ expect(result).to be_failing 1 => ['must be an integer']
70
+ end
71
+ end
72
+ end
73
+
74
+ context 'with optional' do
75
+ subject(:schema) do
76
+ Dry::Validation.Form do
77
+ optional(:foo) { array? { each { int? } } }
78
+ end
79
+ end
80
+
81
+ context 'with valid input' do
82
+ let(:input) { { 'foo' => ['3'] } }
83
+
84
+ it 'is successful' do
85
+ expect(result).to be_successful
86
+ end
87
+ end
88
+
89
+ context 'with missing input' do
90
+ let(:input) { {} }
91
+
92
+ it 'is successful' do
93
+ expect(result).to be_successful
94
+ end
95
+ end
96
+
97
+ context 'with nil input' do
98
+ let(:input) { { 'foo' => nil } }
99
+
100
+ it 'is not successful' do
101
+ expect(result).to be_failing ['must be an array']
102
+ end
103
+ end
104
+
105
+ context 'with blank input' do
106
+ let(:input) { { 'foo' => '' } }
107
+
108
+ it 'is successful' do
109
+ expect(result).to be_successful
110
+ end
111
+ end
112
+
113
+ context 'with invalid type' do
114
+ let(:input) { { 'foo' => { 'a' => '1' } } }
115
+
116
+ it 'is not successful' do
117
+ expect(result).to be_failing ['must be an array']
118
+ end
119
+ end
120
+
121
+ context 'with invalid input (integer)' do
122
+ let(:input) { { 'foo' => '4' } }
123
+
124
+ it 'is not successful' do
125
+ expect(result).to be_failing ['must be an array']
126
+ end
127
+ end
128
+
129
+ context 'with invalid input (array with non-integers)' do
130
+ let(:input) { { 'foo' => %w(foo bar) } }
131
+
132
+ it 'is not successful' do
133
+ expect(result).to be_failing 0 => ['must be an integer'], 1 => ['must be an integer']
134
+ end
135
+ end
136
+
137
+ context 'with invalid input (mixed array)' do
138
+ let(:input) { { 'foo' => %w(1 bar) } }
139
+
140
+ it 'is not successful' do
141
+ expect(result).to be_failing 1 => ['must be an integer']
142
+ end
143
+ end
144
+ end
145
+
146
+ context 'as macro' do
147
+ context 'with required' do
148
+ subject(:schema) do
149
+ Dry::Validation.Form do
150
+ required(:foo).each(:int?)
151
+ end
152
+ end
153
+
154
+ context 'with missing input' do
155
+ let(:input) { {} }
156
+
157
+ it 'is not successful' do
158
+ expect(result).to be_failing ['is missing']
159
+ end
160
+ end
161
+
162
+ context 'with nil input' do
163
+ let(:input) { { 'foo' => nil } }
164
+
165
+ it 'is not successful' do
166
+ expect(result).to be_failing ['must be an array']
167
+ end
168
+ end
169
+
170
+ context 'with blank input' do
171
+ let(:input) { { 'foo' => '' } }
172
+
173
+ it 'is successful' do
174
+ expect(result).to be_successful
175
+ end
176
+ end
177
+
178
+ context 'with valid input' do
179
+ let(:input) { { 'foo' => ['3'] } }
180
+
181
+ it 'is successful' do
182
+ expect(result).to be_successful
183
+ end
184
+ end
185
+
186
+ context 'with invalid input' do
187
+ let(:input) { { 'foo' => ['bar'] } }
188
+
189
+ it 'is not successful' do
190
+ expect(result).to be_failing 0 => ['must be an integer']
191
+ end
192
+ end
193
+ end
194
+
195
+ context 'with optional' do
196
+ subject(:schema) do
197
+ Dry::Validation.Form do
198
+ optional(:foo).each(:int?)
199
+ end
200
+ end
201
+
202
+ context 'with missing input' do
203
+ let(:input) { {} }
204
+
205
+ it 'is not successful' do
206
+ expect(result).to be_successful
207
+ end
208
+ end
209
+
210
+ context 'with nil input' do
211
+ let(:input) { { 'foo' => nil } }
212
+
213
+ it 'is not successful' do
214
+ expect(result).to be_failing ['must be an array']
215
+ end
216
+ end
217
+
218
+ context 'with blank input' do
219
+ let(:input) { { 'foo' => '' } }
220
+
221
+ it 'is successful' do
222
+ expect(result).to be_successful
223
+ end
224
+ end
225
+
226
+ context 'with valid input' do
227
+ let(:input) { { 'foo' => ['3'] } }
228
+
229
+ it 'is successful' do
230
+ expect(result).to be_successful
231
+ end
232
+ end
233
+
234
+ context 'with invalid input' do
235
+ let(:input) { { 'foo' => ['bar'] } }
236
+
237
+ it 'is not successful' do
238
+ expect(result).to be_failing 0 => ['must be an integer']
239
+ end
240
+ end
241
+ end
242
+ end
243
+ end
@@ -0,0 +1,263 @@
1
+ RSpec.describe 'Predicates: Empty' do
2
+ context 'with required' do
3
+ subject(:schema) do
4
+ Dry::Validation.Form do
5
+ required(:foo) { empty? }
6
+ end
7
+ end
8
+
9
+ context 'with valid input (array)' do
10
+ let(:input) { { 'foo' => [] } }
11
+
12
+ it 'is successful' do
13
+ expect(result).to be_successful
14
+ end
15
+ end
16
+
17
+ context 'with valid input (hash)' do
18
+ let(:input) { { 'foo' => {} } }
19
+
20
+ it 'is successful' do
21
+ expect(result).to be_successful
22
+ end
23
+ end
24
+
25
+ context 'with missing input' do
26
+ let(:input) { {} }
27
+
28
+ it 'is not successful' do
29
+ expect(result).to be_failing ['is missing', 'must be empty']
30
+ end
31
+ end
32
+
33
+ context 'with nil input' do
34
+ let(:input) { { 'foo' => nil } }
35
+
36
+ it 'is successful' do
37
+ expect(result).to be_successful
38
+ end
39
+ end
40
+
41
+ context 'with blank input' do
42
+ let(:input) { { 'foo' => '' } }
43
+
44
+ it 'is successful' do
45
+ expect(result).to be_successful
46
+ end
47
+ end
48
+
49
+ context 'with invalid input' do
50
+ let(:input) { { 'foo' => ['23'] } }
51
+
52
+ it 'is not successful' do
53
+ expect(result).to be_failing ['must be empty']
54
+ end
55
+ end
56
+ end
57
+
58
+ context 'with optional' do
59
+ subject(:schema) do
60
+ Dry::Validation.Form do
61
+ optional(:foo) { empty? }
62
+ end
63
+ end
64
+
65
+ context 'with valid input (array)' do
66
+ let(:input) { { 'foo' => [] } }
67
+
68
+ it 'is successful' do
69
+ expect(result).to be_successful
70
+ end
71
+ end
72
+
73
+ context 'with valid input (hash)' do
74
+ let(:input) { { 'foo' => {} } }
75
+
76
+ it 'is successful' do
77
+ expect(result).to be_successful
78
+ end
79
+ end
80
+
81
+ context 'with missing input' do
82
+ let(:input) { {} }
83
+
84
+ it 'is successful' do
85
+ expect(result).to be_successful
86
+ end
87
+ end
88
+
89
+ context 'with nil input' do
90
+ let(:input) { { 'foo' => nil } }
91
+
92
+ it 'is successful' do
93
+ expect(result).to be_successful
94
+ end
95
+ end
96
+
97
+ context 'with blank input' do
98
+ let(:input) { { 'foo' => '' } }
99
+
100
+ it 'is successful' do
101
+ expect(result).to be_successful
102
+ end
103
+ end
104
+
105
+ context 'with invalid input' do
106
+ let(:input) { { 'foo' => ['23'] } }
107
+
108
+ it 'is not successful' do
109
+ expect(result).to be_failing ['must be empty']
110
+ end
111
+ end
112
+ end
113
+
114
+ context 'as macro' do
115
+ context 'with required' do
116
+ context 'with value' do
117
+ subject(:schema) do
118
+ Dry::Validation.Form do
119
+ required(:foo).value(:empty?)
120
+ end
121
+ end
122
+
123
+ context 'with valid input (array)' do
124
+ let(:input) { { 'foo' => [] } }
125
+
126
+ it 'is successful' do
127
+ expect(result).to be_successful
128
+ end
129
+ end
130
+
131
+ context 'with valid input (hash)' do
132
+ let(:input) { { 'foo' => {} } }
133
+
134
+ it 'is successful' do
135
+ expect(result).to be_successful
136
+ end
137
+ end
138
+
139
+ context 'with missing input' do
140
+ let(:input) { {} }
141
+
142
+ it 'is not successful' do
143
+ expect(result).to be_failing ['is missing', 'must be empty']
144
+ end
145
+ end
146
+
147
+ context 'with nil input' do
148
+ let(:input) { { 'foo' => nil } }
149
+
150
+ it 'is successful' do
151
+ expect(result).to be_successful
152
+ end
153
+ end
154
+
155
+ context 'with blank input' do
156
+ let(:input) { { 'foo' => '' } }
157
+
158
+ it 'is successful' do
159
+ expect(result).to be_successful
160
+ end
161
+ end
162
+
163
+ context 'with invalid input' do
164
+ let(:input) { { 'foo' => ['23'] } }
165
+
166
+ it 'is not successful' do
167
+ expect(result).to be_failing ['must be empty']
168
+ end
169
+ end
170
+ end
171
+
172
+ context 'with filled' do
173
+ it "should raise error" do
174
+ expect { Dry::Validation.Form do
175
+ required(:foo).filled(:empty?)
176
+ end }.to raise_error InvalidSchemaError
177
+ end
178
+ end
179
+
180
+ context 'with maybe' do
181
+ it "should raise error" do
182
+ expect { Dry::Validation.Form do
183
+ required(:foo).maybe(:empty?)
184
+ end }.to raise_error InvalidSchemaError
185
+ end
186
+ end
187
+ end
188
+
189
+ context 'with optional' do
190
+ context 'with value' do
191
+ subject(:schema) do
192
+ Dry::Validation.Form do
193
+ optional(:foo).value(:empty?)
194
+ end
195
+ end
196
+
197
+ context 'with valid input (array)' do
198
+ let(:input) { { 'foo' => [] } }
199
+
200
+ it 'is successful' do
201
+ expect(result).to be_successful
202
+ end
203
+ end
204
+
205
+ context 'with valid input (hash)' do
206
+ let(:input) { { 'foo' => {} } }
207
+
208
+ it 'is successful' do
209
+ expect(result).to be_successful
210
+ end
211
+ end
212
+
213
+ context 'with missing input' do
214
+ let(:input) { {} }
215
+
216
+ it 'is successful' do
217
+ expect(result).to be_successful
218
+ end
219
+ end
220
+
221
+ context 'with nil input' do
222
+ let(:input) { { 'foo' => nil } }
223
+
224
+ it 'is successful' do
225
+ expect(result).to be_successful
226
+ end
227
+ end
228
+
229
+ context 'with blank input' do
230
+ let(:input) { { 'foo' => '' } }
231
+
232
+ it 'is successful' do
233
+ expect(result).to be_successful
234
+ end
235
+ end
236
+
237
+ context 'with invalid input' do
238
+ let(:input) { { 'foo' => ['23'] } }
239
+
240
+ it 'is not successful' do
241
+ expect(result).to be_failing ['must be empty']
242
+ end
243
+ end
244
+ end
245
+
246
+ context 'with filled' do
247
+ it "should raise error" do
248
+ expect { Dry::Validation.Form do
249
+ optional(:foo).filled(:empty?)
250
+ end }.to raise_error InvalidSchemaError
251
+ end
252
+ end
253
+
254
+ context 'with maybe' do
255
+ it "should raise error" do
256
+ expect { Dry::Validation.Form do
257
+ optional(:foo).maybe(:empty?)
258
+ end }.to raise_error InvalidSchemaError
259
+ end
260
+ end
261
+ end
262
+ end
263
+ end