dry-validation 0.12.0 → 1.6.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 (204) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +696 -239
  3. data/LICENSE +1 -1
  4. data/README.md +15 -12
  5. data/config/errors.yml +3 -88
  6. data/dry-validation.gemspec +31 -17
  7. data/lib/dry-validation.rb +3 -1
  8. data/lib/dry/validation.rb +45 -28
  9. data/lib/dry/validation/config.rb +24 -0
  10. data/lib/dry/validation/constants.rb +43 -0
  11. data/lib/dry/validation/contract.rb +171 -0
  12. data/lib/dry/validation/contract/class_interface.rb +230 -0
  13. data/lib/dry/validation/evaluator.rb +224 -0
  14. data/lib/dry/validation/extensions/hints.rb +67 -0
  15. data/lib/dry/validation/extensions/monads.rb +24 -8
  16. data/lib/dry/validation/extensions/predicates_as_macros.rb +75 -0
  17. data/lib/dry/validation/failures.rb +70 -0
  18. data/lib/dry/validation/function.rb +44 -0
  19. data/lib/dry/validation/macro.rb +38 -0
  20. data/lib/dry/validation/macros.rb +104 -0
  21. data/lib/dry/validation/message.rb +80 -80
  22. data/lib/dry/validation/message_set.rb +80 -105
  23. data/lib/dry/validation/messages/resolver.rb +131 -0
  24. data/lib/dry/validation/result.rb +183 -41
  25. data/lib/dry/validation/rule.rb +135 -0
  26. data/lib/dry/validation/schema_ext.rb +19 -0
  27. data/lib/dry/validation/values.rb +104 -0
  28. data/lib/dry/validation/version.rb +3 -1
  29. metadata +47 -336
  30. data/.codeclimate.yml +0 -17
  31. data/.gitignore +0 -9
  32. data/.rspec +0 -3
  33. data/.travis.yml +0 -26
  34. data/CONTRIBUTING.md +0 -31
  35. data/Gemfile +0 -33
  36. data/Rakefile +0 -22
  37. data/benchmarks/benchmark_form_invalid.rb +0 -64
  38. data/benchmarks/benchmark_form_valid.rb +0 -64
  39. data/benchmarks/benchmark_schema_invalid_huge.rb +0 -52
  40. data/benchmarks/profile_schema_call_invalid.rb +0 -20
  41. data/benchmarks/profile_schema_call_valid.rb +0 -20
  42. data/benchmarks/profile_schema_definition.rb +0 -14
  43. data/benchmarks/profile_schema_huge_invalid.rb +0 -30
  44. data/benchmarks/profile_schema_messages_invalid.rb +0 -20
  45. data/benchmarks/suite.rb +0 -5
  46. data/examples/basic.rb +0 -15
  47. data/examples/each.rb +0 -14
  48. data/examples/json.rb +0 -12
  49. data/examples/multiple.rb +0 -27
  50. data/examples/nested.rb +0 -22
  51. data/examples/params.rb +0 -11
  52. data/lib/dry/validation/compat/form.rb +0 -67
  53. data/lib/dry/validation/deprecations.rb +0 -24
  54. data/lib/dry/validation/executor.rb +0 -91
  55. data/lib/dry/validation/extensions.rb +0 -7
  56. data/lib/dry/validation/extensions/struct.rb +0 -32
  57. data/lib/dry/validation/input_processor_compiler.rb +0 -135
  58. data/lib/dry/validation/input_processor_compiler/json.rb +0 -45
  59. data/lib/dry/validation/input_processor_compiler/params.rb +0 -49
  60. data/lib/dry/validation/input_processor_compiler/sanitizer.rb +0 -47
  61. data/lib/dry/validation/message_compiler.rb +0 -192
  62. data/lib/dry/validation/message_compiler/visitor_opts.rb +0 -37
  63. data/lib/dry/validation/messages.rb +0 -14
  64. data/lib/dry/validation/messages/abstract.rb +0 -112
  65. data/lib/dry/validation/messages/i18n.rb +0 -35
  66. data/lib/dry/validation/messages/namespaced.rb +0 -32
  67. data/lib/dry/validation/messages/yaml.rb +0 -54
  68. data/lib/dry/validation/predicate_registry.rb +0 -115
  69. data/lib/dry/validation/schema.rb +0 -126
  70. data/lib/dry/validation/schema/check.rb +0 -37
  71. data/lib/dry/validation/schema/class_interface.rb +0 -189
  72. data/lib/dry/validation/schema/deprecated.rb +0 -30
  73. data/lib/dry/validation/schema/dsl.rb +0 -118
  74. data/lib/dry/validation/schema/form.rb +0 -9
  75. data/lib/dry/validation/schema/json.rb +0 -21
  76. data/lib/dry/validation/schema/key.rb +0 -71
  77. data/lib/dry/validation/schema/params.rb +0 -22
  78. data/lib/dry/validation/schema/rule.rb +0 -202
  79. data/lib/dry/validation/schema/value.rb +0 -211
  80. data/lib/dry/validation/schema_compiler.rb +0 -81
  81. data/lib/dry/validation/type_specs.rb +0 -70
  82. data/spec/extensions/monads/result_spec.rb +0 -40
  83. data/spec/extensions/struct/schema_spec.rb +0 -32
  84. data/spec/fixtures/locales/en.yml +0 -6
  85. data/spec/fixtures/locales/pl.yml +0 -18
  86. data/spec/integration/custom_error_messages_spec.rb +0 -48
  87. data/spec/integration/custom_predicates_spec.rb +0 -228
  88. data/spec/integration/hints_spec.rb +0 -170
  89. data/spec/integration/injecting_rules_spec.rb +0 -30
  90. data/spec/integration/json/defining_base_schema_spec.rb +0 -41
  91. data/spec/integration/localized_error_messages_spec.rb +0 -72
  92. data/spec/integration/message_compiler_spec.rb +0 -405
  93. data/spec/integration/messages/i18n_spec.rb +0 -94
  94. data/spec/integration/optional_keys_spec.rb +0 -28
  95. data/spec/integration/params/predicates/array_spec.rb +0 -287
  96. data/spec/integration/params/predicates/empty_spec.rb +0 -263
  97. data/spec/integration/params/predicates/eql_spec.rb +0 -327
  98. data/spec/integration/params/predicates/even_spec.rb +0 -455
  99. data/spec/integration/params/predicates/excluded_from_spec.rb +0 -455
  100. data/spec/integration/params/predicates/excludes_spec.rb +0 -391
  101. data/spec/integration/params/predicates/false_spec.rb +0 -455
  102. data/spec/integration/params/predicates/filled_spec.rb +0 -467
  103. data/spec/integration/params/predicates/format_spec.rb +0 -454
  104. data/spec/integration/params/predicates/gt_spec.rb +0 -519
  105. data/spec/integration/params/predicates/gteq_spec.rb +0 -519
  106. data/spec/integration/params/predicates/included_in_spec.rb +0 -455
  107. data/spec/integration/params/predicates/includes_spec.rb +0 -391
  108. data/spec/integration/params/predicates/key_spec.rb +0 -67
  109. data/spec/integration/params/predicates/lt_spec.rb +0 -519
  110. data/spec/integration/params/predicates/lteq_spec.rb +0 -519
  111. data/spec/integration/params/predicates/max_size_spec.rb +0 -391
  112. data/spec/integration/params/predicates/min_size_spec.rb +0 -391
  113. data/spec/integration/params/predicates/none_spec.rb +0 -265
  114. data/spec/integration/params/predicates/not_eql_spec.rb +0 -327
  115. data/spec/integration/params/predicates/odd_spec.rb +0 -455
  116. data/spec/integration/params/predicates/size/fixed_spec.rb +0 -393
  117. data/spec/integration/params/predicates/size/range_spec.rb +0 -396
  118. data/spec/integration/params/predicates/true_spec.rb +0 -455
  119. data/spec/integration/params/predicates/type_spec.rb +0 -391
  120. data/spec/integration/result_spec.rb +0 -81
  121. data/spec/integration/schema/array_schema_spec.rb +0 -59
  122. data/spec/integration/schema/check_rules_spec.rb +0 -119
  123. data/spec/integration/schema/check_with_nested_el_spec.rb +0 -37
  124. data/spec/integration/schema/check_with_nth_el_spec.rb +0 -25
  125. data/spec/integration/schema/default_settings_spec.rb +0 -11
  126. data/spec/integration/schema/defining_base_schema_spec.rb +0 -41
  127. data/spec/integration/schema/dynamic_predicate_args_spec.rb +0 -43
  128. data/spec/integration/schema/each_with_set_spec.rb +0 -70
  129. data/spec/integration/schema/extending_dsl_spec.rb +0 -27
  130. data/spec/integration/schema/form_spec.rb +0 -236
  131. data/spec/integration/schema/hash_schema_spec.rb +0 -47
  132. data/spec/integration/schema/inheriting_schema_spec.rb +0 -31
  133. data/spec/integration/schema/input_processor_spec.rb +0 -46
  134. data/spec/integration/schema/json/explicit_types_spec.rb +0 -157
  135. data/spec/integration/schema/json_spec.rb +0 -163
  136. data/spec/integration/schema/macros/confirmation_spec.rb +0 -35
  137. data/spec/integration/schema/macros/each_spec.rb +0 -268
  138. data/spec/integration/schema/macros/filled_spec.rb +0 -87
  139. data/spec/integration/schema/macros/input_spec.rb +0 -139
  140. data/spec/integration/schema/macros/maybe_spec.rb +0 -99
  141. data/spec/integration/schema/macros/rule_spec.rb +0 -75
  142. data/spec/integration/schema/macros/value_spec.rb +0 -119
  143. data/spec/integration/schema/macros/when_spec.rb +0 -62
  144. data/spec/integration/schema/nested_schemas_spec.rb +0 -236
  145. data/spec/integration/schema/nested_values_spec.rb +0 -46
  146. data/spec/integration/schema/not_spec.rb +0 -34
  147. data/spec/integration/schema/numbers_spec.rb +0 -19
  148. data/spec/integration/schema/option_with_default_spec.rb +0 -64
  149. data/spec/integration/schema/or_spec.rb +0 -87
  150. data/spec/integration/schema/params/defining_base_schema_spec.rb +0 -41
  151. data/spec/integration/schema/params/explicit_types_spec.rb +0 -195
  152. data/spec/integration/schema/params_spec.rb +0 -234
  153. data/spec/integration/schema/predicate_verification_spec.rb +0 -9
  154. data/spec/integration/schema/predicates/array_spec.rb +0 -295
  155. data/spec/integration/schema/predicates/custom_spec.rb +0 -103
  156. data/spec/integration/schema/predicates/empty_spec.rb +0 -263
  157. data/spec/integration/schema/predicates/eql_spec.rb +0 -327
  158. data/spec/integration/schema/predicates/even_spec.rb +0 -455
  159. data/spec/integration/schema/predicates/excluded_from/array_spec.rb +0 -459
  160. data/spec/integration/schema/predicates/excluded_from/range_spec.rb +0 -459
  161. data/spec/integration/schema/predicates/excludes_spec.rb +0 -391
  162. data/spec/integration/schema/predicates/filled_spec.rb +0 -467
  163. data/spec/integration/schema/predicates/format_spec.rb +0 -455
  164. data/spec/integration/schema/predicates/gt_spec.rb +0 -519
  165. data/spec/integration/schema/predicates/gteq_spec.rb +0 -519
  166. data/spec/integration/schema/predicates/hash_spec.rb +0 -69
  167. data/spec/integration/schema/predicates/included_in/array_spec.rb +0 -459
  168. data/spec/integration/schema/predicates/included_in/range_spec.rb +0 -459
  169. data/spec/integration/schema/predicates/includes_spec.rb +0 -391
  170. data/spec/integration/schema/predicates/key_spec.rb +0 -88
  171. data/spec/integration/schema/predicates/lt_spec.rb +0 -520
  172. data/spec/integration/schema/predicates/lteq_spec.rb +0 -519
  173. data/spec/integration/schema/predicates/max_size_spec.rb +0 -391
  174. data/spec/integration/schema/predicates/min_size_spec.rb +0 -391
  175. data/spec/integration/schema/predicates/none_spec.rb +0 -265
  176. data/spec/integration/schema/predicates/not_eql_spec.rb +0 -391
  177. data/spec/integration/schema/predicates/odd_spec.rb +0 -455
  178. data/spec/integration/schema/predicates/size/fixed_spec.rb +0 -398
  179. data/spec/integration/schema/predicates/size/range_spec.rb +0 -395
  180. data/spec/integration/schema/predicates/type_spec.rb +0 -413
  181. data/spec/integration/schema/reusing_schema_spec.rb +0 -33
  182. data/spec/integration/schema/using_types_spec.rb +0 -135
  183. data/spec/integration/schema/validate_spec.rb +0 -120
  184. data/spec/integration/schema/xor_spec.rb +0 -35
  185. data/spec/integration/schema_builders_spec.rb +0 -17
  186. data/spec/integration/schema_spec.rb +0 -173
  187. data/spec/shared/message_compiler.rb +0 -11
  188. data/spec/shared/predicate_helper.rb +0 -15
  189. data/spec/shared/rule_compiler.rb +0 -8
  190. data/spec/spec_helper.rb +0 -58
  191. data/spec/support/define_struct.rb +0 -25
  192. data/spec/support/matchers.rb +0 -38
  193. data/spec/support/mutant.rb +0 -9
  194. data/spec/support/predicates_integration.rb +0 -7
  195. data/spec/unit/input_processor_compiler/json_spec.rb +0 -283
  196. data/spec/unit/input_processor_compiler/params_spec.rb +0 -328
  197. data/spec/unit/message_compiler/visit_failure_spec.rb +0 -38
  198. data/spec/unit/message_compiler/visit_spec.rb +0 -16
  199. data/spec/unit/message_compiler_spec.rb +0 -7
  200. data/spec/unit/predicate_registry_spec.rb +0 -34
  201. data/spec/unit/schema/key_spec.rb +0 -38
  202. data/spec/unit/schema/rule_spec.rb +0 -42
  203. data/spec/unit/schema/value_spec.rb +0 -131
  204. data/spec/unit/schema_spec.rb +0 -35
@@ -1,59 +0,0 @@
1
- RSpec.describe Dry::Validation::Schema, 'for an array' do
2
- context 'without type specs' do
3
- subject(:schema) do
4
- Dry::Validation.Schema do
5
- each do
6
- schema do
7
- required(:prefix).filled
8
- required(:value).filled
9
- end
10
- end
11
- end
12
- end
13
-
14
- it 'applies its rules to array input' do
15
- result = schema.([{ prefix: 1, value: 123 }, { prefix: 2, value: 456 }])
16
-
17
- expect(result).to be_success
18
-
19
- result = schema.([{ prefix: 1, value: nil }, { prefix: nil, value: 456 }])
20
-
21
- expect(result.messages).to eql(
22
- 0 => { value: ["must be filled"] },
23
- 1 => { prefix: ["must be filled"] }
24
- )
25
- end
26
- end
27
-
28
- context 'with type specs' do
29
- subject(:schema) do
30
- Dry::Validation.Params do
31
- configure { config.type_specs = true }
32
-
33
- each do
34
- schema do
35
- required(:prefix, :integer).filled
36
- required(:value, :integer).filled
37
- end
38
- end
39
- end
40
- end
41
-
42
- it 'applies its rules to coerced array input' do
43
- result = schema.([{ prefix: 1, value: '123' }, { prefix: 2, value: 456 }])
44
-
45
- expect(result).to be_success
46
-
47
- expect(result.output).to eql(
48
- [{ prefix: 1, value: 123 }, { prefix: 2, value: 456 }]
49
- )
50
-
51
- result = schema.([{ prefix: 1, value: nil }, { prefix: nil, value: 456 }])
52
-
53
- expect(result.messages).to eql(
54
- 0 => { value: ["must be filled"] },
55
- 1 => { prefix: ["must be filled"] }
56
- )
57
- end
58
- end
59
- end
@@ -1,119 +0,0 @@
1
- RSpec.describe Schema, 'using high-level rules' do
2
- context 'composing rules' do
3
- subject(:schema) do
4
- Dry::Validation.Schema do
5
- configure do
6
- def self.messages
7
- Messages.default.merge(
8
- en: { errors: { destiny: 'you must select either red or blue' } }
9
- )
10
- end
11
- end
12
-
13
- optional(:red).maybe
14
- optional(:blue).maybe
15
-
16
- rule(destiny: [:red, :blue]) do |red, blue|
17
- red.filled? | blue.filled?
18
- end
19
- end
20
- end
21
-
22
- it 'passes when only red is filled' do
23
- expect(schema.(red: '1')).to be_success
24
- end
25
-
26
- it 'fails when keys are missing' do
27
- expect(schema.({})).to be_failure
28
- end
29
-
30
- it 'fails when red and blue are not filled ' do
31
- expect(schema.(red: nil, blue: nil).messages).to eql(
32
- destiny: ['you must select either red or blue']
33
- )
34
- end
35
- end
36
-
37
- context 'composing specific predicates' do
38
- let(:schema) do
39
- Dry::Validation.Schema do
40
- configure do
41
- def self.messages
42
- Messages.default.merge(
43
- en: {
44
- errors: {
45
- email_presence: 'must be present when login is set to true',
46
- email_absence: 'must not be present when login is set to false'
47
- }
48
- }
49
- )
50
- end
51
- end
52
-
53
- required(:login).filled(:bool?)
54
- required(:email).maybe
55
-
56
- rule(:email_presence) { value(:login).true?.then(value(:email).filled?) }
57
-
58
- rule(:email_absence) { value(:login).false?.then(value(:email).none?) }
59
- end
60
- end
61
-
62
- it 'passes when login is false and email is nil' do
63
- expect(schema.(login: false, email: nil)).to be_success
64
- end
65
-
66
- it 'fails when login is false and email is present' do
67
- expect(schema.(login: false, email: 'jane@doe').messages).to eql(
68
- email_absence: ['must not be present when login is set to false']
69
- )
70
- end
71
-
72
- it 'passes when login is true and email is present' do
73
- expect(schema.(login: true, email: 'jane@doe')).to be_success
74
- end
75
-
76
- it 'fails when login is true and email is not present' do
77
- expect(schema.(login: true, email: nil).messages).to eql(
78
- email_presence: ['must be present when login is set to true']
79
- )
80
- end
81
- end
82
-
83
- describe 'with nested schemas' do
84
- subject(:schema) do
85
- Dry::Validation.Schema do
86
- required(:command).filled(:str?, included_in?: %w(First Second))
87
-
88
- required(:args).filled(:hash?)
89
-
90
- rule(first_args: [:command, :args]) do |command, args|
91
- command.eql?('First')
92
- .then(args.schema { required(:first).filled(:bool?) })
93
- end
94
-
95
- rule(second_args: [:command, :args]) do |command, args|
96
- command.eql?('Second')
97
- .then(args.schema { required(:second).filled(:bool?) })
98
- end
99
- end
100
- end
101
-
102
- it 'generates check rule matching on value' do
103
- expect(schema.(command: 'First', args: { first: true })).to be_success
104
- expect(schema.(command: 'Second', args: { second: true })).to be_success
105
-
106
- expect(schema.(command: 'oops', args: { such: 'validation' }).messages).to eql(
107
- command: ['must be one of: First, Second']
108
- )
109
-
110
- expect(schema.(command: 'First', args: { second: true }).messages).to eql(
111
- args: { first: ['is missing'] }
112
- )
113
-
114
- expect(schema.(command: 'Second', args: { first: true }).messages).to eql(
115
- args: { second: ['is missing'] }
116
- )
117
- end
118
- end
119
- end
@@ -1,37 +0,0 @@
1
- RSpec.describe 'Check depending on a nested value from a hash' do
2
- subject(:schema) do
3
- Dry::Validation.Schema do
4
- required(:tag).schema do
5
- required(:color).schema do
6
- required(:value).filled(:str?)
7
- end
8
- end
9
-
10
- rule(tag: [[:tag, :color, :value]]) do |value|
11
- value.eql?('red')
12
- end
13
- end
14
- end
15
-
16
- it 'passes when check passes' do
17
- expect(schema.(tag: { color: { value: 'red' }})).to be_success
18
- end
19
-
20
- it 'skips check when parent of the dependency failed' do
21
- expect(schema.(tag: { color: :oops }).messages).to eql(
22
- tag: { color: ['must be a hash'] }
23
- )
24
- end
25
-
26
- it 'skips check when dependency failed' do
27
- expect(schema.(tag: { color: { value: :oops }}).messages).to eql(
28
- tag: { color: { value: ['must be a string'] } }
29
- )
30
- end
31
-
32
- it 'fails when check fails' do
33
- expect(schema.(tag: { color: { value: 'blue' }}).messages).to eql(
34
- tag: { color: { value: ['must be equal to red'] } }
35
- )
36
- end
37
- end
@@ -1,25 +0,0 @@
1
- RSpec.describe 'Check depending on nth element in an array' do
2
- subject(:schema) do
3
- Dry::Validation.Schema do
4
- required(:tags).each(:str?)
5
-
6
- rule(tags: [[:tags, 0]]) do |value|
7
- value.eql?('red')
8
- end
9
- end
10
- end
11
-
12
- it 'skips check when dependency failed' do
13
- expect(schema.(tags: 'oops')).to be_failure
14
- end
15
-
16
- it 'passes when check passes' do
17
- expect(schema.(tags: %w(red green blue))).to be_success
18
- end
19
-
20
- it 'fails when check fails' do
21
- expect(schema.(tags: %w(blue green red)).messages).to eql(
22
- tags: { 0 => ["must be equal to red"] }
23
- )
24
- end
25
- end
@@ -1,11 +0,0 @@
1
- RSpec.describe Dry::Validation::Schema, 'default settings' do
2
- subject(:schema) do
3
- Dry::Validation.Schema(build: false) do
4
- required(:name).filled
5
- end
6
- end
7
-
8
- it 'uses :yaml messages by default' do
9
- expect(schema.config.messages).to be(:yaml)
10
- end
11
- end
@@ -1,41 +0,0 @@
1
- require 'dry/validation/messages/i18n'
2
- require 'i18n'
3
-
4
- RSpec.describe 'Defining base schema class' do
5
- subject(:schema) do
6
- Dry::Validation.Schema(BaseSchema) do
7
- required(:email).filled(:email?)
8
- end
9
- end
10
-
11
- before do
12
- class BaseSchema < Dry::Validation::Schema
13
- configure do |config|
14
- config.messages_file = SPEC_ROOT.join('fixtures/locales/en.yml')
15
- config.messages = :i18n
16
- end
17
-
18
- def email?(value)
19
- true
20
- end
21
-
22
- define! do
23
- required(:name).filled
24
- end
25
- end
26
- end
27
-
28
- after do
29
- Object.send(:remove_const, :BaseSchema)
30
- end
31
-
32
- it 'inherits predicates' do
33
- expect(schema).to respond_to(:email?)
34
- end
35
-
36
- it 'inherits rules' do
37
- expect(schema.(name: nil).messages).to eql(
38
- name: ['must be filled'], email: ['is missing', 'must be an email']
39
- )
40
- end
41
- end
@@ -1,43 +0,0 @@
1
- RSpec.describe Dry::Validation::Schema, 'dynamic predicate args' do
2
- context 'with base rules' do
3
- subject(:schema) do
4
- Dry::Validation.Schema do
5
- configure do
6
- def data
7
- %w(a b c)
8
- end
9
- end
10
-
11
- required(:letter).filled(included_in?: data)
12
- end
13
- end
14
-
15
- it 'evaluates predicate arguments' do
16
- expect(schema.(letter: 'a')).to be_success
17
- expect(schema.(letter: 'f')).to be_failure
18
- end
19
- end
20
-
21
- context 'with high-level rules' do
22
- subject(:schema) do
23
- Dry::Validation.Schema do
24
- configure do
25
- def data
26
- %w(a b c)
27
- end
28
- end
29
-
30
- required(:letter).filled(:str?)
31
-
32
- rule(valid_letter: [:letter]) do |letter|
33
- letter.included_in?(data)
34
- end
35
- end
36
- end
37
-
38
- it 'evaluates predicate arguments' do
39
- expect(schema.(letter: 'a')).to be_success
40
- expect(schema.(letter: 'f')).to be_failure
41
- end
42
- end
43
- end
@@ -1,70 +0,0 @@
1
- RSpec.describe 'Schema with each and set rules' do
2
- subject(:schema) do
3
- Dry::Validation.Schema do
4
- required(:payments).each do
5
- required(:method).filled(:str?)
6
- required(:amount).filled(:float?)
7
- end
8
- end
9
- end
10
-
11
- describe '#messages' do
12
- it 'validates using all rules' do
13
- expect(schema.(payments: [{}]).messages).to eql(
14
- { payments: {
15
- 0 => { method: ['is missing'], amount: ['is missing'] }
16
- }}
17
- )
18
- end
19
-
20
- it 'validates each payment against its set of rules' do
21
- input = {
22
- payments: [
23
- { method: 'cc', amount: 1.23 },
24
- { method: 'wire', amount: 4.56 }
25
- ]
26
- }
27
-
28
- expect(schema.(input).messages).to eql({})
29
- end
30
-
31
- it 'validates presence of the method key for each payment' do
32
- input = {
33
- payments: [
34
- { method: 'cc', amount: 1.23 },
35
- { amount: 4.56 }
36
- ]
37
- }
38
-
39
- expect(schema.(input).messages).to eql(
40
- payments: { 1 => { method: ['is missing'] } }
41
- )
42
- end
43
-
44
- it 'validates type of the method value for each payment' do
45
- input = {
46
- payments: [
47
- { method: 'cc', amount: 1.23 },
48
- { method: 12, amount: 4.56 }
49
- ]
50
- }
51
-
52
- expect(schema.(input).messages).to eql(
53
- payments: { 1 => { method: ['must be a string'] } }
54
- )
55
- end
56
-
57
- it 'validates type of the amount value for each payment' do
58
- input = {
59
- payments: [
60
- { method: 'cc', amount: 1.23 },
61
- { method: 'wire', amount: '4.56' }
62
- ]
63
- }
64
-
65
- expect(schema.(input).messages).to eql(
66
- payments: { 1 => { amount: ['must be a float'] } }
67
- )
68
- end
69
- end
70
- end
@@ -1,27 +0,0 @@
1
- RSpec.describe 'Extending DSL' do
2
- it 'allows configuring custom DSL methods' do
3
- dsl_ext = Module.new do
4
- def maybe_int(name, *predicates, &block)
5
- required(name, [:nil, :integer]).maybe(:int?, *predicates, &block)
6
- end
7
- end
8
-
9
- Dry::Validation::Schema.configure do |config|
10
- config.dsl_extensions = dsl_ext
11
- end
12
-
13
- schema = Dry::Validation.Schema do
14
- configure do
15
- config.input_processor = :params
16
- config.type_specs = true
17
- end
18
-
19
- maybe_int(:age)
20
- end
21
-
22
- expect(schema.(age: nil)).to be_success
23
- expect(schema.(age: 1)).to be_success
24
- expect(schema.(age: '1')).to be_success
25
- expect(schema.(age: 'foo').messages).to eql(age: ['must be an integer'])
26
- end
27
- end
@@ -1,236 +0,0 @@
1
- RSpec.describe 'Dry::Validation::Schema::Form', 'defining a schema' do
2
- before(:all) { require 'dry/validation/compat/form' }
3
-
4
- subject(:schema) do
5
- Dry::Validation.Form do
6
- configure do
7
- def email?(value)
8
- true
9
- end
10
- end
11
-
12
- required(:email).filled
13
-
14
- required(:age).maybe(:int?, gt?: 18)
15
-
16
- required(:address).schema do
17
- required(:city).filled
18
- required(:street).filled
19
-
20
- required(:loc).schema do
21
- required(:lat).filled(:float?)
22
- required(:lng).filled(:float?)
23
- end
24
- end
25
-
26
- optional(:password).maybe.confirmation
27
-
28
- optional(:phone_number).maybe(:int?, gt?: 0)
29
-
30
- rule(:email_valid) { value(:email).email? }
31
- end
32
- end
33
-
34
- describe '#messages' do
35
- it 'returns compiled error messages' do
36
- result = schema.('email' => '', 'age' => '19')
37
-
38
- expect(result.messages).to eql(
39
- email: ['must be filled'],
40
- address: ['is missing']
41
- )
42
-
43
- expect(result.output).to eql(email: '', age: 19)
44
- end
45
-
46
- it 'returns hints for nested data' do
47
- result = schema.(
48
- 'email' => 'jane@doe.org',
49
- 'age' => '19',
50
- 'address' => {
51
- 'city' => '',
52
- 'street' => 'Street 1/2',
53
- 'loc' => { 'lat' => '123.456', 'lng' => '' }
54
- }
55
- )
56
-
57
- expect(result.messages).to eql(
58
- address: {
59
- loc: { lng: ['must be filled'] },
60
- city: ['must be filled']
61
- }
62
- )
63
- end
64
- end
65
-
66
- describe '#call' do
67
- it 'passes when attributes are valid' do
68
- result = schema.(
69
- 'email' => 'jane@doe.org',
70
- 'age' => '19',
71
- 'address' => {
72
- 'city' => 'NYC',
73
- 'street' => 'Street 1/2',
74
- 'loc' => { 'lat' => '123.456', 'lng' => '456.123' }
75
- }
76
- )
77
-
78
- expect(result).to be_success
79
-
80
- expect(result.output).to eql(
81
- email: 'jane@doe.org', age: 19,
82
- address: {
83
- city: 'NYC', street: 'Street 1/2',
84
- loc: { lat: 123.456, lng: 456.123 }
85
- }
86
- )
87
- end
88
-
89
- it 'validates presence of an email and min age value' do
90
- result = schema.('email' => '', 'age' => '18')
91
-
92
- expect(result.messages).to eql(
93
- address: ['is missing'],
94
- age: ['must be greater than 18'],
95
- email: ['must be filled']
96
- )
97
- end
98
-
99
- it 'handles optionals' do
100
- result = schema.(
101
- 'email' => 'jane@doe.org',
102
- 'age' => '19',
103
- 'phone_number' => '12',
104
- 'address' => {
105
- 'city' => 'NYC',
106
- 'street' => 'Street 1/2',
107
- 'loc' => { 'lat' => '123.456', 'lng' => '456.123' }
108
- }
109
- )
110
-
111
- expect(result).to be_success
112
-
113
- expect(result.output).to eql(
114
- email: 'jane@doe.org', age: 19, phone_number: 12,
115
- address: {
116
- city: 'NYC', street: 'Street 1/2',
117
- loc: { lat: 123.456, lng: 456.123 }
118
- }
119
- )
120
- end
121
- end
122
-
123
- describe 'with an each and nested schema' do
124
- subject(:schema) do
125
- Dry::Validation.Form do
126
- required(:items).each do
127
- schema do
128
- required(:title).filled(:str?)
129
- end
130
- end
131
- end
132
- end
133
-
134
- it 'passes when each element passes schema check' do
135
- expect(schema.(items: [{ title: 'Foo' }])).to be_success
136
- end
137
-
138
- it 'fails when one or more elements did not pass schema check' do
139
- expect(schema.(items: [{ title: 'Foo' }, { title: :Foo }]).messages).to eql(
140
- items: { 1 => { title: ['must be a string'] } }
141
- )
142
- end
143
- end
144
-
145
- describe 'symbolizing keys when coercion fails' do
146
- subject(:schema) do
147
- Dry::Validation.Form do
148
- required(:email).value(size?: 8..60)
149
- required(:birthdate).value(:date?)
150
- required(:age).value(:int?, gt?: 23)
151
- required(:tags).maybe(max_size?: 3)
152
- end
153
- end
154
-
155
- let(:tags) { %(al b c) }
156
-
157
- it 'symbolizes keys and coerces values' do
158
- result = schema.(
159
- 'email' => 'jane@doe.org',
160
- 'birthdate' => '2001-02-03',
161
- 'age' => '24',
162
- 'tags' => tags
163
- ).to_h
164
-
165
- expect(result.to_h).to eql(
166
- email: 'jane@doe.org',
167
- birthdate: Date.new(2001, 2, 3),
168
- age: 24,
169
- tags: tags
170
- )
171
- end
172
-
173
- it 'symbolizes keys even when coercion fails' do
174
- result = schema.(
175
- 'email' => 'jane@doe.org',
176
- 'birthdate' => '2001-sutin-03',
177
- 'age' => ['oops'],
178
- 'tags' => nil
179
- )
180
-
181
- expect(result.to_h).to eql(
182
- email: 'jane@doe.org',
183
- birthdate: '2001-sutin-03',
184
- age: ['oops'],
185
- tags: nil
186
- )
187
-
188
- expect(result.messages).to eql(
189
- birthdate: ['must be a date'],
190
- age: ['must be an integer', 'must be greater than 23']
191
- )
192
- end
193
- end
194
-
195
- describe 'with nested schema in a high-level rule' do
196
- subject(:schema) do
197
- Dry::Validation.Form do
198
- required(:address).maybe(:hash?)
199
-
200
- required(:delivery).filled(:bool?)
201
-
202
- rule(address: [:delivery, :address]) do |delivery, address|
203
- delivery.true?.then(address.schema(AddressSchema))
204
- end
205
- end
206
- end
207
-
208
- before do
209
- AddressSchema = Dry::Validation.Form do
210
- required(:city).filled
211
- required(:zipcode).filled(:int?)
212
- end
213
- end
214
-
215
- after do
216
- Object.send(:remove_const, :AddressSchema)
217
- end
218
-
219
- it 'succeeds when nested form schema succeeds' do
220
- result = schema.(delivery: '1', address: { city: 'NYC', zipcode: '123' })
221
- expect(result).to be_success
222
- end
223
-
224
- it 'does not apply schema when there is no match' do
225
- result = schema.(delivery: '0', address: nil)
226
- expect(result).to be_success
227
- end
228
-
229
- it 'fails when nested schema fails' do
230
- result = schema.(delivery: '1', address: { city: 'NYC', zipcode: 'foo' })
231
- expect(result.messages).to eql(
232
- address: { zipcode: ['must be an integer'] }
233
- )
234
- end
235
- end
236
- end