dry-validation 0.13.3 → 1.3.1

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 (206) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +233 -12
  3. data/LICENSE +1 -1
  4. data/README.md +13 -9
  5. data/config/errors.yml +3 -88
  6. data/lib/dry-validation.rb +2 -0
  7. data/lib/dry/validation.rb +47 -28
  8. data/lib/dry/validation/config.rb +24 -0
  9. data/lib/dry/validation/constants.rb +43 -0
  10. data/lib/dry/validation/contract.rb +160 -0
  11. data/lib/dry/validation/contract/class_interface.rb +223 -0
  12. data/lib/dry/validation/evaluator.rb +197 -0
  13. data/lib/dry/validation/extensions/hints.rb +69 -0
  14. data/lib/dry/validation/extensions/monads.rb +23 -7
  15. data/lib/dry/validation/extensions/predicates_as_macros.rb +75 -0
  16. data/lib/dry/validation/failures.rb +58 -0
  17. data/lib/dry/validation/function.rb +44 -0
  18. data/lib/dry/validation/macro.rb +38 -0
  19. data/lib/dry/validation/macros.rb +104 -0
  20. data/lib/dry/validation/message.rb +79 -79
  21. data/lib/dry/validation/message_set.rb +108 -88
  22. data/lib/dry/validation/messages/resolver.rb +79 -0
  23. data/lib/dry/validation/result.rb +154 -42
  24. data/lib/dry/validation/rule.rb +129 -0
  25. data/lib/dry/validation/schema_ext.rb +46 -0
  26. data/lib/dry/validation/values.rb +94 -0
  27. data/lib/dry/validation/version.rb +3 -1
  28. metadata +41 -336
  29. data/.codeclimate.yml +0 -17
  30. data/.gitignore +0 -9
  31. data/.rspec +0 -3
  32. data/.travis.yml +0 -29
  33. data/CONTRIBUTING.md +0 -31
  34. data/Gemfile +0 -25
  35. data/Rakefile +0 -22
  36. data/benchmarks/benchmark_form_invalid.rb +0 -64
  37. data/benchmarks/benchmark_form_valid.rb +0 -64
  38. data/benchmarks/benchmark_schema_invalid_huge.rb +0 -52
  39. data/benchmarks/profile_schema_call_invalid.rb +0 -20
  40. data/benchmarks/profile_schema_call_valid.rb +0 -20
  41. data/benchmarks/profile_schema_definition.rb +0 -14
  42. data/benchmarks/profile_schema_huge_invalid.rb +0 -30
  43. data/benchmarks/profile_schema_messages_invalid.rb +0 -20
  44. data/benchmarks/suite.rb +0 -5
  45. data/dry-validation.gemspec +0 -28
  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 -137
  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 -188
  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 -119
  65. data/lib/dry/validation/messages/i18n.rb +0 -47
  66. data/lib/dry/validation/messages/namespaced.rb +0 -39
  67. data/lib/dry/validation/messages/yaml.rb +0 -61
  68. data/lib/dry/validation/predicate_registry.rb +0 -115
  69. data/lib/dry/validation/predicates.rb +0 -19
  70. data/lib/dry/validation/schema.rb +0 -126
  71. data/lib/dry/validation/schema/check.rb +0 -37
  72. data/lib/dry/validation/schema/class_interface.rb +0 -190
  73. data/lib/dry/validation/schema/deprecated.rb +0 -30
  74. data/lib/dry/validation/schema/dsl.rb +0 -118
  75. data/lib/dry/validation/schema/form.rb +0 -9
  76. data/lib/dry/validation/schema/json.rb +0 -21
  77. data/lib/dry/validation/schema/key.rb +0 -71
  78. data/lib/dry/validation/schema/params.rb +0 -22
  79. data/lib/dry/validation/schema/rule.rb +0 -202
  80. data/lib/dry/validation/schema/value.rb +0 -211
  81. data/lib/dry/validation/schema_compiler.rb +0 -81
  82. data/lib/dry/validation/template.rb +0 -66
  83. data/lib/dry/validation/type_specs.rb +0 -70
  84. data/spec/extensions/monads/result_spec.rb +0 -40
  85. data/spec/extensions/struct/schema_spec.rb +0 -32
  86. data/spec/fixtures/locales/en.yml +0 -8
  87. data/spec/fixtures/locales/pl.yml +0 -22
  88. data/spec/integration/custom_error_messages_spec.rb +0 -54
  89. data/spec/integration/custom_predicates_spec.rb +0 -228
  90. data/spec/integration/hints_spec.rb +0 -170
  91. data/spec/integration/injecting_rules_spec.rb +0 -30
  92. data/spec/integration/json/defining_base_schema_spec.rb +0 -41
  93. data/spec/integration/localized_error_messages_spec.rb +0 -72
  94. data/spec/integration/message_compiler_spec.rb +0 -405
  95. data/spec/integration/messages/i18n_spec.rb +0 -104
  96. data/spec/integration/optional_keys_spec.rb +0 -28
  97. data/spec/integration/params/predicates/array_spec.rb +0 -287
  98. data/spec/integration/params/predicates/empty_spec.rb +0 -263
  99. data/spec/integration/params/predicates/eql_spec.rb +0 -327
  100. data/spec/integration/params/predicates/even_spec.rb +0 -455
  101. data/spec/integration/params/predicates/excluded_from_spec.rb +0 -455
  102. data/spec/integration/params/predicates/excludes_spec.rb +0 -391
  103. data/spec/integration/params/predicates/false_spec.rb +0 -455
  104. data/spec/integration/params/predicates/filled_spec.rb +0 -467
  105. data/spec/integration/params/predicates/format_spec.rb +0 -454
  106. data/spec/integration/params/predicates/gt_spec.rb +0 -519
  107. data/spec/integration/params/predicates/gteq_spec.rb +0 -519
  108. data/spec/integration/params/predicates/included_in_spec.rb +0 -455
  109. data/spec/integration/params/predicates/includes_spec.rb +0 -391
  110. data/spec/integration/params/predicates/key_spec.rb +0 -67
  111. data/spec/integration/params/predicates/lt_spec.rb +0 -519
  112. data/spec/integration/params/predicates/lteq_spec.rb +0 -519
  113. data/spec/integration/params/predicates/max_size_spec.rb +0 -391
  114. data/spec/integration/params/predicates/min_size_spec.rb +0 -391
  115. data/spec/integration/params/predicates/none_spec.rb +0 -265
  116. data/spec/integration/params/predicates/not_eql_spec.rb +0 -327
  117. data/spec/integration/params/predicates/odd_spec.rb +0 -455
  118. data/spec/integration/params/predicates/size/fixed_spec.rb +0 -393
  119. data/spec/integration/params/predicates/size/range_spec.rb +0 -396
  120. data/spec/integration/params/predicates/true_spec.rb +0 -455
  121. data/spec/integration/params/predicates/type_spec.rb +0 -391
  122. data/spec/integration/result_spec.rb +0 -81
  123. data/spec/integration/schema/array_schema_spec.rb +0 -59
  124. data/spec/integration/schema/check_rules_spec.rb +0 -119
  125. data/spec/integration/schema/check_with_nested_el_spec.rb +0 -37
  126. data/spec/integration/schema/check_with_nth_el_spec.rb +0 -25
  127. data/spec/integration/schema/default_settings_spec.rb +0 -11
  128. data/spec/integration/schema/defining_base_schema_spec.rb +0 -41
  129. data/spec/integration/schema/dynamic_predicate_args_spec.rb +0 -43
  130. data/spec/integration/schema/each_with_set_spec.rb +0 -70
  131. data/spec/integration/schema/extending_dsl_spec.rb +0 -27
  132. data/spec/integration/schema/form_spec.rb +0 -236
  133. data/spec/integration/schema/hash_schema_spec.rb +0 -47
  134. data/spec/integration/schema/inheriting_schema_spec.rb +0 -31
  135. data/spec/integration/schema/input_processor_spec.rb +0 -46
  136. data/spec/integration/schema/json/explicit_types_spec.rb +0 -157
  137. data/spec/integration/schema/json_spec.rb +0 -163
  138. data/spec/integration/schema/macros/confirmation_spec.rb +0 -35
  139. data/spec/integration/schema/macros/each_spec.rb +0 -268
  140. data/spec/integration/schema/macros/filled_spec.rb +0 -87
  141. data/spec/integration/schema/macros/input_spec.rb +0 -139
  142. data/spec/integration/schema/macros/maybe_spec.rb +0 -99
  143. data/spec/integration/schema/macros/rule_spec.rb +0 -75
  144. data/spec/integration/schema/macros/value_spec.rb +0 -119
  145. data/spec/integration/schema/macros/when_spec.rb +0 -62
  146. data/spec/integration/schema/nested_schemas_spec.rb +0 -236
  147. data/spec/integration/schema/nested_values_spec.rb +0 -46
  148. data/spec/integration/schema/not_spec.rb +0 -34
  149. data/spec/integration/schema/numbers_spec.rb +0 -19
  150. data/spec/integration/schema/option_with_default_spec.rb +0 -64
  151. data/spec/integration/schema/or_spec.rb +0 -87
  152. data/spec/integration/schema/params/defining_base_schema_spec.rb +0 -41
  153. data/spec/integration/schema/params/explicit_types_spec.rb +0 -195
  154. data/spec/integration/schema/params_spec.rb +0 -234
  155. data/spec/integration/schema/predicate_verification_spec.rb +0 -9
  156. data/spec/integration/schema/predicates/array_spec.rb +0 -295
  157. data/spec/integration/schema/predicates/custom_spec.rb +0 -103
  158. data/spec/integration/schema/predicates/empty_spec.rb +0 -263
  159. data/spec/integration/schema/predicates/eql_spec.rb +0 -327
  160. data/spec/integration/schema/predicates/even_spec.rb +0 -455
  161. data/spec/integration/schema/predicates/excluded_from/array_spec.rb +0 -459
  162. data/spec/integration/schema/predicates/excluded_from/range_spec.rb +0 -459
  163. data/spec/integration/schema/predicates/excludes_spec.rb +0 -391
  164. data/spec/integration/schema/predicates/filled_spec.rb +0 -467
  165. data/spec/integration/schema/predicates/format_spec.rb +0 -455
  166. data/spec/integration/schema/predicates/gt_spec.rb +0 -519
  167. data/spec/integration/schema/predicates/gteq_spec.rb +0 -519
  168. data/spec/integration/schema/predicates/hash_spec.rb +0 -69
  169. data/spec/integration/schema/predicates/included_in/array_spec.rb +0 -459
  170. data/spec/integration/schema/predicates/included_in/range_spec.rb +0 -459
  171. data/spec/integration/schema/predicates/includes_spec.rb +0 -391
  172. data/spec/integration/schema/predicates/key_spec.rb +0 -88
  173. data/spec/integration/schema/predicates/lt_spec.rb +0 -520
  174. data/spec/integration/schema/predicates/lteq_spec.rb +0 -519
  175. data/spec/integration/schema/predicates/max_size_spec.rb +0 -391
  176. data/spec/integration/schema/predicates/min_size_spec.rb +0 -391
  177. data/spec/integration/schema/predicates/none_spec.rb +0 -265
  178. data/spec/integration/schema/predicates/not_eql_spec.rb +0 -391
  179. data/spec/integration/schema/predicates/odd_spec.rb +0 -455
  180. data/spec/integration/schema/predicates/size/fixed_spec.rb +0 -398
  181. data/spec/integration/schema/predicates/size/range_spec.rb +0 -395
  182. data/spec/integration/schema/predicates/type_spec.rb +0 -413
  183. data/spec/integration/schema/reusing_schema_spec.rb +0 -33
  184. data/spec/integration/schema/using_types_spec.rb +0 -135
  185. data/spec/integration/schema/validate_spec.rb +0 -120
  186. data/spec/integration/schema/xor_spec.rb +0 -35
  187. data/spec/integration/schema_builders_spec.rb +0 -17
  188. data/spec/integration/schema_spec.rb +0 -173
  189. data/spec/shared/message_compiler.rb +0 -11
  190. data/spec/shared/predicate_helper.rb +0 -15
  191. data/spec/shared/rule_compiler.rb +0 -8
  192. data/spec/spec_helper.rb +0 -62
  193. data/spec/support/define_struct.rb +0 -25
  194. data/spec/support/matchers.rb +0 -38
  195. data/spec/support/mutant.rb +0 -9
  196. data/spec/support/predicates_integration.rb +0 -7
  197. data/spec/unit/input_processor_compiler/json_spec.rb +0 -283
  198. data/spec/unit/input_processor_compiler/params_spec.rb +0 -328
  199. data/spec/unit/message_compiler/visit_failure_spec.rb +0 -38
  200. data/spec/unit/message_compiler/visit_spec.rb +0 -16
  201. data/spec/unit/message_compiler_spec.rb +0 -7
  202. data/spec/unit/predicate_registry_spec.rb +0 -34
  203. data/spec/unit/schema/key_spec.rb +0 -38
  204. data/spec/unit/schema/rule_spec.rb +0 -42
  205. data/spec/unit/schema/value_spec.rb +0 -131
  206. 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