lite-validation 0.0.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 (138) hide show
  1. checksums.yaml +7 -0
  2. data/.rubocop.yml +94 -0
  3. data/Gemfile +18 -0
  4. data/README.md +770 -0
  5. data/bench/calibrational.rb +89 -0
  6. data/bench/comparative.rb +197 -0
  7. data/bench/functional.rb +107 -0
  8. data/bench/profile.rb +45 -0
  9. data/lib/lite/validation/adapters/interfaces/dry.rb +29 -0
  10. data/lib/lite/validation/error.rb +9 -0
  11. data/lib/lite/validation/result/abstract/disputable.rb +17 -0
  12. data/lib/lite/validation/result/abstract/failure.rb +19 -0
  13. data/lib/lite/validation/result/abstract/refutable.rb +21 -0
  14. data/lib/lite/validation/result/abstract/success.rb +25 -0
  15. data/lib/lite/validation/result/abstract.rb +16 -0
  16. data/lib/lite/validation/structured_error/record.rb +36 -0
  17. data/lib/lite/validation/structured_error.rb +23 -0
  18. data/lib/lite/validation/validator/adapters/errors/default.rb +24 -0
  19. data/lib/lite/validation/validator/adapters/interfaces/default.rb +32 -0
  20. data/lib/lite/validation/validator/adapters/interfaces/dry.rb +17 -0
  21. data/lib/lite/validation/validator/adapters/predicates/dry/adapter.rb +50 -0
  22. data/lib/lite/validation/validator/adapters/predicates/dry/builder.rb +46 -0
  23. data/lib/lite/validation/validator/adapters/predicates/dry/engine.rb +32 -0
  24. data/lib/lite/validation/validator/adapters/predicates/dry.rb +3 -0
  25. data/lib/lite/validation/validator/coordinator/builder.rb +92 -0
  26. data/lib/lite/validation/validator/coordinator/default.rb +32 -0
  27. data/lib/lite/validation/validator/coordinator/errors/builder.rb +56 -0
  28. data/lib/lite/validation/validator/coordinator/errors/dry.rb +29 -0
  29. data/lib/lite/validation/validator/coordinator/errors/flat.rb +46 -0
  30. data/lib/lite/validation/validator/coordinator/errors/hierarchical.rb +29 -0
  31. data/lib/lite/validation/validator/coordinator/instance.rb +30 -0
  32. data/lib/lite/validation/validator/coordinator.rb +12 -0
  33. data/lib/lite/validation/validator/helpers/path.rb +49 -0
  34. data/lib/lite/validation/validator/node/abstract/branch.rb +21 -0
  35. data/lib/lite/validation/validator/node/abstract/instance.rb +43 -0
  36. data/lib/lite/validation/validator/node/abstract/leaf.rb +35 -0
  37. data/lib/lite/validation/validator/node/abstract.rb +25 -0
  38. data/lib/lite/validation/validator/node/child.rb +44 -0
  39. data/lib/lite/validation/validator/node/implementation/apply_ruling.rb +44 -0
  40. data/lib/lite/validation/validator/node/implementation/dig.rb +38 -0
  41. data/lib/lite/validation/validator/node/implementation/helpers/call_foreign.rb +31 -0
  42. data/lib/lite/validation/validator/node/implementation/helpers/with_result.rb +23 -0
  43. data/lib/lite/validation/validator/node/implementation/helpers/yield_strategy.rb +83 -0
  44. data/lib/lite/validation/validator/node/implementation/helpers/yield_validator.rb +49 -0
  45. data/lib/lite/validation/validator/node/implementation/identity.rb +90 -0
  46. data/lib/lite/validation/validator/node/implementation/iteration/iterator.rb +102 -0
  47. data/lib/lite/validation/validator/node/implementation/iteration.rb +46 -0
  48. data/lib/lite/validation/validator/node/implementation/navigation.rb +43 -0
  49. data/lib/lite/validation/validator/node/implementation/predication.rb +61 -0
  50. data/lib/lite/validation/validator/node/implementation/scoping/evaluator.rb +43 -0
  51. data/lib/lite/validation/validator/node/implementation/scoping.rb +43 -0
  52. data/lib/lite/validation/validator/node/implementation/validation.rb +64 -0
  53. data/lib/lite/validation/validator/node/implementation/wrap.rb +26 -0
  54. data/lib/lite/validation/validator/node/root.rb +60 -0
  55. data/lib/lite/validation/validator/node/suspended.rb +33 -0
  56. data/lib/lite/validation/validator/node.rb +12 -0
  57. data/lib/lite/validation/validator/option/none.rb +43 -0
  58. data/lib/lite/validation/validator/option/some/abstract.rb +29 -0
  59. data/lib/lite/validation/validator/option/some/complex/registry/abstract.rb +67 -0
  60. data/lib/lite/validation/validator/option/some/complex/registry/node.rb +47 -0
  61. data/lib/lite/validation/validator/option/some/complex/registry/root.rb +31 -0
  62. data/lib/lite/validation/validator/option/some/complex/registry.rb +32 -0
  63. data/lib/lite/validation/validator/option/some/complex/wrappers/abstract/iterable.rb +31 -0
  64. data/lib/lite/validation/validator/option/some/complex/wrappers/abstract/non_iterable.rb +27 -0
  65. data/lib/lite/validation/validator/option/some/complex/wrappers/abstract.rb +35 -0
  66. data/lib/lite/validation/validator/option/some/complex/wrappers/array.rb +41 -0
  67. data/lib/lite/validation/validator/option/some/complex/wrappers/hash.rb +40 -0
  68. data/lib/lite/validation/validator/option/some/complex/wrappers/object.rb +34 -0
  69. data/lib/lite/validation/validator/option/some/complex/wrappers/tuple.rb +47 -0
  70. data/lib/lite/validation/validator/option/some/complex/wrappers.rb +5 -0
  71. data/lib/lite/validation/validator/option/some/complex.rb +24 -0
  72. data/lib/lite/validation/validator/option/some/dig.rb +34 -0
  73. data/lib/lite/validation/validator/option/some/simple.rb +23 -0
  74. data/lib/lite/validation/validator/option/some/singular.rb +29 -0
  75. data/lib/lite/validation/validator/option/some.rb +20 -0
  76. data/lib/lite/validation/validator/option.rb +20 -0
  77. data/lib/lite/validation/validator/predicate/abstract/variants.rb +23 -0
  78. data/lib/lite/validation/validator/predicate/foreign/adapter/input/single.rb +21 -0
  79. data/lib/lite/validation/validator/predicate/foreign/adapter/input/tuple.rb +21 -0
  80. data/lib/lite/validation/validator/predicate/foreign/adapter/input.rb +28 -0
  81. data/lib/lite/validation/validator/predicate/foreign/adapter/ruling/instance.rb +37 -0
  82. data/lib/lite/validation/validator/predicate/foreign/adapter/ruling.rb +26 -0
  83. data/lib/lite/validation/validator/predicate/foreign/engine.rb +27 -0
  84. data/lib/lite/validation/validator/predicate/foreign/variant.rb +33 -0
  85. data/lib/lite/validation/validator/predicate/foreign/variants.rb +46 -0
  86. data/lib/lite/validation/validator/predicate/native/builder.rb +72 -0
  87. data/lib/lite/validation/validator/predicate/native/definite.rb +19 -0
  88. data/lib/lite/validation/validator/predicate/native/instance.rb +41 -0
  89. data/lib/lite/validation/validator/predicate/native/optional.rb +34 -0
  90. data/lib/lite/validation/validator/predicate/registry.rb +47 -0
  91. data/lib/lite/validation/validator/predicate.rb +17 -0
  92. data/lib/lite/validation/validator/result/abstract/failure.rb +21 -0
  93. data/lib/lite/validation/validator/result/abstract/instance.rb +18 -0
  94. data/lib/lite/validation/validator/result/abstract/success.rb +17 -0
  95. data/lib/lite/validation/validator/result/abstract.rb +29 -0
  96. data/lib/lite/validation/validator/result/committed.rb +75 -0
  97. data/lib/lite/validation/validator/result/disputable/hash.rb +17 -0
  98. data/lib/lite/validation/validator/result/disputable/instance.rb +43 -0
  99. data/lib/lite/validation/validator/result/disputable/iterable/array.rb +23 -0
  100. data/lib/lite/validation/validator/result/disputable/iterable.rb +17 -0
  101. data/lib/lite/validation/validator/result/disputable/navigable.rb +35 -0
  102. data/lib/lite/validation/validator/result/disputable.rb +14 -0
  103. data/lib/lite/validation/validator/result/disputed/abstract/hash.rb +32 -0
  104. data/lib/lite/validation/validator/result/disputed/abstract/instance.rb +26 -0
  105. data/lib/lite/validation/validator/result/disputed/iterable/array.rb +42 -0
  106. data/lib/lite/validation/validator/result/disputed/iterable/hash.rb +38 -0
  107. data/lib/lite/validation/validator/result/disputed/iterable.rb +20 -0
  108. data/lib/lite/validation/validator/result/disputed/navigable.rb +59 -0
  109. data/lib/lite/validation/validator/result/disputed.rb +17 -0
  110. data/lib/lite/validation/validator/result/refuted.rb +78 -0
  111. data/lib/lite/validation/validator/result/valid/abstract/collect.rb +42 -0
  112. data/lib/lite/validation/validator/result/valid/abstract/commit.rb +25 -0
  113. data/lib/lite/validation/validator/result/valid/abstract/instance.rb +23 -0
  114. data/lib/lite/validation/validator/result/valid/iterable/array/abstract.rb +24 -0
  115. data/lib/lite/validation/validator/result/valid/iterable/array/tuples.rb +64 -0
  116. data/lib/lite/validation/validator/result/valid/iterable/array/values.rb +42 -0
  117. data/lib/lite/validation/validator/result/valid/iterable/hash.rb +46 -0
  118. data/lib/lite/validation/validator/result/valid/iterable.rb +33 -0
  119. data/lib/lite/validation/validator/result/valid/navigable.rb +68 -0
  120. data/lib/lite/validation/validator/result/valid.rb +21 -0
  121. data/lib/lite/validation/validator/result.rb +15 -0
  122. data/lib/lite/validation/validator/ruling/abstract/invalid.rb +59 -0
  123. data/lib/lite/validation/validator/ruling/abstract/valid.rb +23 -0
  124. data/lib/lite/validation/validator/ruling/abstract.rb +12 -0
  125. data/lib/lite/validation/validator/ruling/commit.rb +17 -0
  126. data/lib/lite/validation/validator/ruling/dispute.rb +21 -0
  127. data/lib/lite/validation/validator/ruling/invalidate.rb +32 -0
  128. data/lib/lite/validation/validator/ruling/pass.rb +19 -0
  129. data/lib/lite/validation/validator/ruling/refute.rb +21 -0
  130. data/lib/lite/validation/validator/ruling.rb +53 -0
  131. data/lib/lite/validation/validator/state/instance.rb +46 -0
  132. data/lib/lite/validation/validator/state/merge_strategy.rb +50 -0
  133. data/lib/lite/validation/validator/state/unwrap_strategy.rb +31 -0
  134. data/lib/lite/validation/validator/state.rb +21 -0
  135. data/lib/lite/validation/validator.rb +15 -0
  136. data/lib/lite/validation/version.rb +9 -0
  137. data/lib/lite/validation.rb +8 -0
  138. metadata +196 -0
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'abstract/iterable'
4
+ require_relative '../../singular'
5
+
6
+ module Lite
7
+ module Validation
8
+ module Validator
9
+ module Option
10
+ module Some
11
+ module Complex
12
+ module Wrappers
13
+ class Hash < Abstract::Iterable
14
+ include Singular
15
+
16
+ def fetch(key)
17
+ return Option.none unless value.key? key
18
+
19
+ Option.some(value[key])
20
+ end
21
+
22
+ def reduce(initial_state, &block)
23
+ value.lazy
24
+ .map { |key, value| [value, key] }
25
+ .reduce(initial_state, &block)
26
+ end
27
+
28
+ def inspect
29
+ "#<Option::Some::Hash length=#{value.length}>"
30
+ end
31
+
32
+ Registry.register(::Hash, self)
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'abstract/non_iterable'
4
+ require_relative '../../singular'
5
+
6
+ module Lite
7
+ module Validation
8
+ module Validator
9
+ module Option
10
+ module Some
11
+ module Complex
12
+ module Wrappers
13
+ class Object < Abstract::NonIterable
14
+ include Singular
15
+
16
+ def fetch(key)
17
+ Option.some(value.send(key))
18
+ rescue StandardError => e
19
+ raise InvalidAccess, e.message
20
+ end
21
+
22
+ def inspect
23
+ "#<Option::Some::Object class=#{value.class.name}>"
24
+ end
25
+
26
+ Registry.register(::Object, self)
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'abstract/non_iterable'
4
+
5
+ module Lite
6
+ module Validation
7
+ module Validator
8
+ module Option
9
+ module Some
10
+ module Complex
11
+ module Wrappers
12
+ class Tuple < Abstract::NonIterable
13
+ def some_or_nil
14
+ return self if some?
15
+
16
+ self.class.new(value.map(&:some_or_nil))
17
+ end
18
+
19
+ def to_option(coordinator)
20
+ value.map { _1.to_option(coordinator) }
21
+ end
22
+
23
+ def unwrap
24
+ transpose.unwrap
25
+ end
26
+
27
+ def transpose
28
+ return Option.none unless some?
29
+
30
+ Option.some(value.map(&:value))
31
+ end
32
+
33
+ def some?
34
+ value.all?(&:some?)
35
+ end
36
+
37
+ def inspect
38
+ "#<Option::Some::Tuple (#{value.map(&:inspect).join(', ')})>"
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'wrappers/array'
4
+ require_relative 'wrappers/hash'
5
+ require_relative 'wrappers/object'
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'complex/wrappers'
4
+
5
+ module Lite
6
+ module Validation
7
+ module Validator
8
+ module Option
9
+ module Some
10
+ module Complex
11
+ def self.instance(object)
12
+ return object if object.is_a?(Complex)
13
+
14
+ wrapper = Registry.wrapper_for(object.class)
15
+ raise Error::Fatal, "No wrapper for: #{object.class}" unless wrapper
16
+
17
+ wrapper.new(object)
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'complex/wrappers/tuple'
4
+
5
+ module Lite
6
+ module Validation
7
+ module Validator
8
+ module Option
9
+ module Some
10
+ module Dig
11
+ def dig(paths)
12
+ if paths.length == 1
13
+ follow_path(paths.first)
14
+ else
15
+ tuple = paths.map { follow_path(_1) }
16
+ Complex::Wrappers::Tuple.new(tuple)
17
+ end
18
+ end
19
+
20
+ private
21
+
22
+ def follow_path(path)
23
+ path.reduce(self) do |option, key|
24
+ break option if option.none?
25
+
26
+ option.to_complex.fetch(key)
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'abstract'
4
+ require_relative 'complex'
5
+ require_relative 'singular'
6
+
7
+ module Lite
8
+ module Validation
9
+ module Validator
10
+ module Option
11
+ module Some
12
+ class Simple < Abstract
13
+ include Singular
14
+
15
+ def to_complex
16
+ Complex.instance(value)
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'dig'
4
+
5
+ module Lite
6
+ module Validation
7
+ module Validator
8
+ module Option
9
+ module Some
10
+ module Singular
11
+ include Dig
12
+
13
+ def some_or_nil
14
+ self
15
+ end
16
+
17
+ def to_option(coordinator)
18
+ coordinator.some(value)
19
+ end
20
+
21
+ def unwrap
22
+ value
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'lite/data'
4
+
5
+ require_relative 'some/simple'
6
+ require_relative 'some/complex'
7
+
8
+ module Lite
9
+ module Validation
10
+ module Validator
11
+ module Option
12
+ module Some
13
+ def self.instance(value)
14
+ Simple.new(value)
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'option/some'
4
+ require_relative 'option/none'
5
+
6
+ module Lite
7
+ module Validation
8
+ module Validator
9
+ module Option
10
+ def self.some(value)
11
+ Some.instance(value)
12
+ end
13
+
14
+ def self.none
15
+ None
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../../error'
4
+
5
+ module Lite
6
+ module Validation
7
+ module Validator
8
+ module Predicate
9
+ module Abstract
10
+ module Variants
11
+ def definite
12
+ raise Error::Fatal, 'Definite variant not available'
13
+ end
14
+
15
+ def optional
16
+ raise Error::Fatal, 'Optional variant not available'
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lite
4
+ module Validation
5
+ module Validator
6
+ module Predicate
7
+ module Foreign
8
+ module Adapter
9
+ module Input
10
+ module Single
11
+ def self.pass_in(value, block)
12
+ block.call(value)
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lite
4
+ module Validation
5
+ module Validator
6
+ module Predicate
7
+ module Foreign
8
+ module Adapter
9
+ module Input
10
+ module Tuple
11
+ def self.pass_in(value, block)
12
+ block.call(*value)
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../../../error'
4
+ require_relative 'input/single'
5
+ require_relative 'input/tuple'
6
+
7
+ module Lite
8
+ module Validation
9
+ module Validator
10
+ module Predicate
11
+ module Foreign
12
+ module Adapter
13
+ module Input
14
+ def self.instance(arity)
15
+ raise Error::Fatal, "Arity must be positive integer, got: #{arity}" unless arity.positive?
16
+
17
+ case arity
18
+ when 1 then Single
19
+ else Tuple
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'lite/data'
4
+
5
+ module Lite
6
+ module Validation
7
+ module Validator
8
+ module Predicate
9
+ module Foreign
10
+ module Adapter
11
+ module Ruling
12
+ class Instance
13
+ Lite::Data.define(self, args: %i[severity ruling_class])
14
+
15
+ def dispute
16
+ severity == :dispute ? self : Ruling.instance(:dispute)
17
+ end
18
+
19
+ def refute
20
+ severity == :refute ? self : Ruling.instance(:refute)
21
+ end
22
+
23
+ def to_ruling(error)
24
+ ruling_class.instance(error)
25
+ end
26
+
27
+ private_class_method :new
28
+
29
+ private :with
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../../ruling'
4
+ require_relative 'ruling/instance'
5
+
6
+ module Lite
7
+ module Validation
8
+ module Validator
9
+ module Predicate
10
+ module Foreign
11
+ module Adapter
12
+ module Ruling
13
+ def self.instance(severity)
14
+ case severity
15
+ when :dispute then @dispute ||= Instance.send(:new, :dispute, Validator::Ruling::Dispute)
16
+ when :refute then @refute ||= Instance.send(:new, :refute, Validator::Ruling::Refute)
17
+ else raise Validation::Error::Fatal, 'Unexpected severity'
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'variants'
4
+ require_relative '../registry'
5
+ require_relative '../../ruling'
6
+
7
+ module Lite
8
+ module Validation
9
+ module Validator
10
+ module Predicate
11
+ module Foreign
12
+ class Engine
13
+ Lite::Data.define(self, args: [:error_adapter])
14
+
15
+ def build(_keys, &_block)
16
+ raise NotImplementedError, "#{self.class.name}##{__method__} unimplemented"
17
+ end
18
+
19
+ def build_contextual(_keys, _context, &_block)
20
+ raise NotImplementedError, "#{self.class.name}##{__method__} unimplemented"
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'lite/data'
4
+
5
+ module Lite
6
+ module Validation
7
+ module Validator
8
+ module Predicate
9
+ module Foreign
10
+ class Variant
11
+ Lite::Data.define(self, args: %i[callable adapter])
12
+
13
+ def call(value, _context)
14
+ adapter.to_ruling(adapter.pass_in(value, callable), callable, value)
15
+ end
16
+
17
+ def severity
18
+ adapter.severity
19
+ end
20
+
21
+ def dispute
22
+ severity == :dispute ? self : with(adapter: adapter.dispute)
23
+ end
24
+
25
+ def refute
26
+ severity == :refute ? self : with(adapter: adapter.refute)
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../abstract/variants'
4
+ require_relative 'variant'
5
+
6
+ module Lite
7
+ module Validation
8
+ module Validator
9
+ module Predicate
10
+ module Foreign
11
+ class Variants
12
+ include Abstract::Variants
13
+
14
+ Lite::Data.define(self, kwargs: %i[definite optional])
15
+
16
+ def initialize(definite: nil, optional: nil)
17
+ super
18
+ end
19
+
20
+ def definite
21
+ @definite || super
22
+ end
23
+
24
+ def optional
25
+ @optional || super
26
+ end
27
+
28
+ def dispute
29
+ with definite: definite&.dispute, optional: optional&.dispute
30
+ end
31
+
32
+ def refute
33
+ with definite: definite&.refute, optional: optional&.refute
34
+ end
35
+
36
+ def with(definite: self.definite, optional: self.optional)
37
+ return self if definite == self.definite && optional == self.optional
38
+
39
+ super
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'definite'
4
+ require_relative 'optional'
5
+
6
+ require_relative '../../coordinator/default'
7
+ require_relative '../../node/root'
8
+ require_relative '../../coordinator/errors/flat'
9
+
10
+ module Lite
11
+ module Validation
12
+ module Validator
13
+ module Predicate
14
+ module Native
15
+ class Builder
16
+ include Ruling::Constructors
17
+
18
+ def initialize
19
+ @validate_value = nil
20
+ @validate_option = nil
21
+ end
22
+
23
+ def self.define(&block)
24
+ new.tap { _1.instance_eval(&block) }.build
25
+ end
26
+
27
+ def validate_value(&block)
28
+ if block
29
+ raise(Error, 'Test value already set') unless @validate_value.nil?
30
+
31
+ @validate_value = block
32
+
33
+ else
34
+ @validate_value
35
+ end
36
+ end
37
+
38
+ def validate_option(&block)
39
+ if block
40
+ raise(Error, 'Test option already set') unless @validate_option.nil?
41
+
42
+ @validate_option = block
43
+ else
44
+ @validate_option
45
+ end
46
+ end
47
+
48
+ def build
49
+ result = validate
50
+ raise Error, "Builder invalid: #{result.error.message}" unless result.success?
51
+
52
+ definite = validate_value ? Native::Definite.new(validate_value) : nil
53
+ return definite if validate_option.nil?
54
+
55
+ Native::Optional.new(validate_option, definite: definite)
56
+ end
57
+
58
+ def validate
59
+ coordinator = Coordinator::Default.instance(Coordinator::Errors::Flat)
60
+
61
+ Validator::Node::Root.initial(self, coordinator).at do |builder|
62
+ builder.validate(%i[validate_option validate_value]) do |tuple|
63
+ Refute(coordinator.internal_error(:value_missing)) if tuple.all?(&:nil?)
64
+ end
65
+ end.to_result
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'instance'
4
+
5
+ module Lite
6
+ module Validation
7
+ module Validator
8
+ module Predicate
9
+ module Native
10
+ class Definite < Instance
11
+ def definite
12
+ self
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'lite/data'
4
+
5
+ require_relative '../abstract/variants'
6
+
7
+ module Lite
8
+ module Validation
9
+ module Validator
10
+ module Predicate
11
+ module Native
12
+ class Instance
13
+ Lite::Data.define(self, args: [:proc], kwargs: [:severity])
14
+ include Ruling::Constructors
15
+ include Abstract::Variants
16
+
17
+ def initialize(proc, severity: nil)
18
+ super
19
+ end
20
+
21
+ def dispute
22
+ with(severity: :dispute)
23
+ end
24
+
25
+ def refute
26
+ with(severity: :refute)
27
+ end
28
+
29
+ def call(*args, **opts)
30
+ raise Error::Fatal, 'Level not set' unless severity
31
+
32
+ ruling = instance_exec(*args, **opts, &proc)
33
+ ruling = Pass() if ruling.nil?
34
+ ruling.invalid { |invalid| invalid.send(severity) }
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end