dry-validation 0.13.3 → 1.0.0.alpha1

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