dry-validation 0.9.5 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
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