dry-validation 0.9.5 → 0.10.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 (79) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +1 -8
  3. data/CHANGELOG.md +34 -1
  4. data/Gemfile +2 -0
  5. data/Rakefile +12 -3
  6. data/config/errors.yml +1 -0
  7. data/dry-validation.gemspec +3 -2
  8. data/lib/dry/validation/executor.rb +3 -27
  9. data/lib/dry/validation/extensions/monads.rb +17 -0
  10. data/lib/dry/validation/extensions/struct.rb +32 -0
  11. data/lib/dry/validation/extensions.rb +7 -0
  12. data/lib/dry/validation/input_processor_compiler.rb +19 -3
  13. data/lib/dry/validation/message.rb +43 -30
  14. data/lib/dry/validation/message_compiler/visitor_opts.rb +39 -0
  15. data/lib/dry/validation/message_compiler.rb +98 -52
  16. data/lib/dry/validation/message_set.rb +59 -30
  17. data/lib/dry/validation/predicate_registry.rb +17 -6
  18. data/lib/dry/validation/result.rb +39 -17
  19. data/lib/dry/validation/schema/check.rb +5 -4
  20. data/lib/dry/validation/schema/class_interface.rb +6 -13
  21. data/lib/dry/validation/schema/dsl.rb +9 -3
  22. data/lib/dry/validation/schema/form.rb +12 -3
  23. data/lib/dry/validation/schema/json.rb +12 -3
  24. data/lib/dry/validation/schema/key.rb +6 -6
  25. data/lib/dry/validation/schema/rule.rb +14 -8
  26. data/lib/dry/validation/schema/value.rb +23 -21
  27. data/lib/dry/validation/schema.rb +9 -12
  28. data/lib/dry/validation/schema_compiler.rb +16 -2
  29. data/lib/dry/validation/version.rb +1 -1
  30. data/lib/dry/validation.rb +11 -23
  31. data/spec/extensions/monads/result_spec.rb +38 -0
  32. data/spec/extensions/struct/schema_spec.rb +32 -0
  33. data/spec/integration/custom_predicates_spec.rb +7 -6
  34. data/spec/integration/form/predicates/size/fixed_spec.rb +0 -2
  35. data/spec/integration/form/predicates/size/range_spec.rb +0 -2
  36. data/spec/integration/hints_spec.rb +2 -6
  37. data/spec/integration/json/defining_base_schema_spec.rb +41 -0
  38. data/spec/integration/{error_compiler_spec.rb → message_compiler_spec.rb} +79 -131
  39. data/spec/integration/result_spec.rb +26 -4
  40. data/spec/integration/schema/check_with_nested_el_spec.rb +1 -1
  41. data/spec/integration/schema/check_with_nth_el_spec.rb +1 -1
  42. data/spec/integration/schema/defining_base_schema_spec.rb +3 -0
  43. data/spec/integration/schema/dynamic_predicate_args_spec.rb +34 -9
  44. data/spec/integration/schema/form/defining_base_schema_spec.rb +41 -0
  45. data/spec/integration/schema/json_spec.rb +1 -0
  46. data/spec/integration/schema/macros/input_spec.rb +26 -0
  47. data/spec/integration/schema/macros/rule_spec.rb +2 -1
  48. data/spec/integration/schema/macros/value_spec.rb +1 -1
  49. data/spec/integration/schema/macros/when_spec.rb +1 -24
  50. data/spec/integration/schema/or_spec.rb +87 -0
  51. data/spec/integration/schema/predicates/custom_spec.rb +4 -4
  52. data/spec/integration/schema/predicates/even_spec.rb +10 -10
  53. data/spec/integration/schema/predicates/odd_spec.rb +10 -10
  54. data/spec/integration/schema/predicates/size/fixed_spec.rb +0 -3
  55. data/spec/integration/schema/predicates/size/range_spec.rb +0 -2
  56. data/spec/integration/schema/predicates/type_spec.rb +22 -0
  57. data/spec/integration/schema/using_types_spec.rb +14 -41
  58. data/spec/integration/schema/validate_spec.rb +83 -0
  59. data/spec/integration/schema/xor_spec.rb +5 -5
  60. data/spec/integration/schema_builders_spec.rb +4 -2
  61. data/spec/integration/schema_spec.rb +8 -0
  62. data/spec/shared/message_compiler.rb +11 -0
  63. data/spec/shared/predicate_helper.rb +5 -3
  64. data/spec/spec_helper.rb +15 -0
  65. data/spec/unit/input_processor_compiler/form_spec.rb +3 -3
  66. data/spec/unit/message_compiler/visit_failure_spec.rb +38 -0
  67. data/spec/unit/message_compiler/visit_spec.rb +16 -0
  68. data/spec/unit/message_compiler_spec.rb +7 -0
  69. data/spec/unit/predicate_registry_spec.rb +2 -2
  70. data/spec/unit/schema/key_spec.rb +19 -12
  71. data/spec/unit/schema/rule_spec.rb +14 -6
  72. data/spec/unit/schema/value_spec.rb +49 -52
  73. metadata +50 -20
  74. data/lib/dry/validation/constants.rb +0 -6
  75. data/lib/dry/validation/error.rb +0 -26
  76. data/lib/dry/validation/error_compiler.rb +0 -81
  77. data/lib/dry/validation/hint_compiler.rb +0 -104
  78. data/spec/unit/error_compiler_spec.rb +0 -7
  79. data/spec/unit/hint_compiler_spec.rb +0 -51
@@ -1,6 +0,0 @@
1
- module Dry
2
- module Validation
3
- EMPTY_ARRAY = [].freeze
4
- EMPTY_HASH = {}.freeze
5
- end
6
- end
@@ -1,26 +0,0 @@
1
- module Dry
2
- module Validation
3
- class Error
4
- include Dry::Equalizer(:name, :result)
5
-
6
- attr_reader :name, :result
7
-
8
- def initialize(name, result)
9
- @name = name
10
- @result = result
11
- end
12
-
13
- def schema?
14
- result.response.is_a?(Validation::Result)
15
- end
16
-
17
- def to_ast
18
- if schema?
19
- [:schema, [name, result.response.to_ast]]
20
- else
21
- [:error, [name, result.to_ast]]
22
- end
23
- end
24
- end
25
- end
26
- end
@@ -1,81 +0,0 @@
1
- require 'dry/validation/message_compiler'
2
-
3
- module Dry
4
- module Validation
5
- class ErrorCompiler < MessageCompiler
6
- def message_type
7
- :failure
8
- end
9
-
10
- def message_class
11
- Message
12
- end
13
-
14
- def visit_error(node, opts = EMPTY_HASH)
15
- rule, error = node
16
- node_path = Array(opts.fetch(:path, rule))
17
-
18
- path = if rule.is_a?(Array) && rule.size > node_path.size
19
- rule
20
- else
21
- node_path
22
- end
23
-
24
- path.compact!
25
-
26
- template = messages[rule.is_a?(Array) ? rule.last : rule, default_lookup_options]
27
-
28
- if template
29
- predicate, args, tokens = visit(error, opts.merge(path: path, message: false))
30
- message_class[predicate, path, template % tokens, rule: rule, args: args]
31
- else
32
- visit(error, opts.merge(rule: rule, path: path))
33
- end
34
- end
35
-
36
- def visit_input(node, opts = EMPTY_HASH)
37
- rule, result = node
38
- opt_rule = opts[:rule]
39
-
40
- if opts[:each] && opt_rule.is_a?(Array)
41
- visit(result, opts.merge(rule: rule, path: opts[:path] + [opt_rule.last]))
42
- else
43
- visit(result, opts.merge(rule: rule))
44
- end
45
- end
46
-
47
- def visit_result(node, opts = EMPTY_HASH)
48
- input, other = node
49
- visit(other, opts.merge(input: input))
50
- end
51
-
52
- def visit_each(node, opts = EMPTY_HASH)
53
- node.map { |el| visit(el, opts.merge(each: true)) }
54
- end
55
-
56
- def visit_schema(node, opts = EMPTY_HASH)
57
- path, other = node
58
-
59
- if opts[:path]
60
- visit(other, opts.merge(path: opts[:path] + [path.last]))
61
- else
62
- visit(other, opts.merge(path: [path], schema: true))
63
- end
64
- end
65
-
66
- def visit_check(node, opts = EMPTY_HASH)
67
- name, other = node
68
-
69
- if opts[:schema]
70
- visit(other, opts)
71
- else
72
- visit(other, opts.merge(path: Array(name)))
73
- end
74
- end
75
-
76
- def lookup_options(opts, arg_vals = [])
77
- super.update(val_type: opts[:input].class)
78
- end
79
- end
80
- end
81
- end
@@ -1,104 +0,0 @@
1
- require 'dry/validation/message_compiler'
2
-
3
- module Dry
4
- module Validation
5
- class HintCompiler < MessageCompiler
6
- include Dry::Equalizer(:messages, :rules, :options)
7
-
8
- attr_reader :rules, :excluded, :cache
9
-
10
- TYPES = {
11
- none?: NilClass,
12
- bool?: TrueClass,
13
- str?: String,
14
- int?: Fixnum,
15
- float?: Float,
16
- decimal?: BigDecimal,
17
- date?: Date,
18
- date_time?: DateTime,
19
- time?: Time,
20
- hash?: Hash,
21
- array?: Array
22
- }.freeze
23
-
24
- EXCLUDED = (%i(key? none? filled?) + TYPES.keys).freeze
25
-
26
- def self.cache
27
- @cache ||= Concurrent::Map.new
28
- end
29
-
30
- def initialize(messages, options = {})
31
- super(messages, options)
32
- @rules = options.fetch(:rules, EMPTY_ARRAY)
33
- @excluded = options.fetch(:excluded, EXCLUDED)
34
- @cache = self.class.cache
35
- end
36
-
37
- def message_type
38
- :hint
39
- end
40
-
41
- def message_class
42
- Hint
43
- end
44
-
45
- def hash
46
- @hash ||= [messages, rules, options].hash
47
- end
48
-
49
- def call
50
- cache.fetch_or_store(hash) { super(rules) }
51
- end
52
-
53
- def visit_predicate(node, opts = EMPTY_HASH)
54
- predicate, args = node
55
- return EMPTY_ARRAY if excluded.include?(predicate) || dyn_args?(args)
56
- super(node, opts.merge(val_type: TYPES[predicate]))
57
- end
58
-
59
- def visit_each(node, opts = EMPTY_HASH)
60
- visit(node, opts.merge(each: true))
61
- end
62
-
63
- def visit_or(node, *args)
64
- left, right = node
65
- [Array[visit(left, *args)], Array[visit(right, *args)]].flatten
66
- end
67
-
68
- def visit_and(node, *args)
69
- _, right = node
70
- visit(right, *args)
71
- end
72
-
73
- def visit_schema(node, opts = EMPTY_HASH)
74
- path = node.config.path
75
- rules = node.rule_ast
76
- schema_opts = opts.merge(path: [path])
77
-
78
- rules.map { |rule| visit(rule, schema_opts) }
79
- end
80
-
81
- def visit_check(node)
82
- EMPTY_ARRAY
83
- end
84
-
85
- def visit_xor(node)
86
- EMPTY_ARRAY
87
- end
88
-
89
- def visit_not(node)
90
- EMPTY_ARRAY
91
- end
92
-
93
- def visit_type(node, *args)
94
- visit(node.rule.to_ast, *args)
95
- end
96
-
97
- private
98
-
99
- def dyn_args?(args)
100
- args.map(&:last).any? { |a| a.is_a?(UnboundMethod) }
101
- end
102
- end
103
- end
104
- end
@@ -1,7 +0,0 @@
1
- RSpec.describe ErrorCompiler, '#call' do
2
- subject(:error_compiler) { ErrorCompiler.new( Messages.default ) }
3
-
4
- it 'returns an empty hash when there are no errors' do
5
- expect(error_compiler.([])).to be_empty
6
- end
7
- end
@@ -1,51 +0,0 @@
1
- require 'dry/validation/hint_compiler'
2
-
3
- RSpec.describe HintCompiler, '#call' do
4
- subject(:compiler) { HintCompiler.new(Messages.default, rules: rules) }
5
-
6
- include_context 'predicate helper'
7
-
8
- let(:rules) do
9
- [
10
- [
11
- :and, [
12
- [:val, p(:key?, :age)],
13
- [
14
- :or, [
15
- [:key, [:age, p(:none?)]],
16
- [
17
- :and, [
18
- [:key, [:age, p(:int?)]],
19
- [:key, [:age, p(:gt?, 18)]]
20
- ]
21
- ]
22
- ]
23
- ]
24
- ],
25
- ],
26
- [
27
- :and, [
28
- [:val, p(:key?, :height)],
29
- [
30
- :or, [
31
- [:key, [:height, p(:none?)]],
32
- [
33
- :and, [
34
- [:key, [:height, p(:int?)]],
35
- [:key, [:height, p(:gt?, 180)]]
36
- ]
37
- ]
38
- ]
39
- ]
40
- ]
41
- ]
42
- ]
43
- end
44
-
45
- it 'returns hint messages for given rules' do
46
- expect(compiler.call.to_h).to eql(
47
- age: ['must be greater than 18'],
48
- height: ['must be greater than 180'],
49
- )
50
- end
51
- end