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.
- checksums.yaml +7 -0
- data/.rubocop.yml +94 -0
- data/Gemfile +18 -0
- data/README.md +770 -0
- data/bench/calibrational.rb +89 -0
- data/bench/comparative.rb +197 -0
- data/bench/functional.rb +107 -0
- data/bench/profile.rb +45 -0
- data/lib/lite/validation/adapters/interfaces/dry.rb +29 -0
- data/lib/lite/validation/error.rb +9 -0
- data/lib/lite/validation/result/abstract/disputable.rb +17 -0
- data/lib/lite/validation/result/abstract/failure.rb +19 -0
- data/lib/lite/validation/result/abstract/refutable.rb +21 -0
- data/lib/lite/validation/result/abstract/success.rb +25 -0
- data/lib/lite/validation/result/abstract.rb +16 -0
- data/lib/lite/validation/structured_error/record.rb +36 -0
- data/lib/lite/validation/structured_error.rb +23 -0
- data/lib/lite/validation/validator/adapters/errors/default.rb +24 -0
- data/lib/lite/validation/validator/adapters/interfaces/default.rb +32 -0
- data/lib/lite/validation/validator/adapters/interfaces/dry.rb +17 -0
- data/lib/lite/validation/validator/adapters/predicates/dry/adapter.rb +50 -0
- data/lib/lite/validation/validator/adapters/predicates/dry/builder.rb +46 -0
- data/lib/lite/validation/validator/adapters/predicates/dry/engine.rb +32 -0
- data/lib/lite/validation/validator/adapters/predicates/dry.rb +3 -0
- data/lib/lite/validation/validator/coordinator/builder.rb +92 -0
- data/lib/lite/validation/validator/coordinator/default.rb +32 -0
- data/lib/lite/validation/validator/coordinator/errors/builder.rb +56 -0
- data/lib/lite/validation/validator/coordinator/errors/dry.rb +29 -0
- data/lib/lite/validation/validator/coordinator/errors/flat.rb +46 -0
- data/lib/lite/validation/validator/coordinator/errors/hierarchical.rb +29 -0
- data/lib/lite/validation/validator/coordinator/instance.rb +30 -0
- data/lib/lite/validation/validator/coordinator.rb +12 -0
- data/lib/lite/validation/validator/helpers/path.rb +49 -0
- data/lib/lite/validation/validator/node/abstract/branch.rb +21 -0
- data/lib/lite/validation/validator/node/abstract/instance.rb +43 -0
- data/lib/lite/validation/validator/node/abstract/leaf.rb +35 -0
- data/lib/lite/validation/validator/node/abstract.rb +25 -0
- data/lib/lite/validation/validator/node/child.rb +44 -0
- data/lib/lite/validation/validator/node/implementation/apply_ruling.rb +44 -0
- data/lib/lite/validation/validator/node/implementation/dig.rb +38 -0
- data/lib/lite/validation/validator/node/implementation/helpers/call_foreign.rb +31 -0
- data/lib/lite/validation/validator/node/implementation/helpers/with_result.rb +23 -0
- data/lib/lite/validation/validator/node/implementation/helpers/yield_strategy.rb +83 -0
- data/lib/lite/validation/validator/node/implementation/helpers/yield_validator.rb +49 -0
- data/lib/lite/validation/validator/node/implementation/identity.rb +90 -0
- data/lib/lite/validation/validator/node/implementation/iteration/iterator.rb +102 -0
- data/lib/lite/validation/validator/node/implementation/iteration.rb +46 -0
- data/lib/lite/validation/validator/node/implementation/navigation.rb +43 -0
- data/lib/lite/validation/validator/node/implementation/predication.rb +61 -0
- data/lib/lite/validation/validator/node/implementation/scoping/evaluator.rb +43 -0
- data/lib/lite/validation/validator/node/implementation/scoping.rb +43 -0
- data/lib/lite/validation/validator/node/implementation/validation.rb +64 -0
- data/lib/lite/validation/validator/node/implementation/wrap.rb +26 -0
- data/lib/lite/validation/validator/node/root.rb +60 -0
- data/lib/lite/validation/validator/node/suspended.rb +33 -0
- data/lib/lite/validation/validator/node.rb +12 -0
- data/lib/lite/validation/validator/option/none.rb +43 -0
- data/lib/lite/validation/validator/option/some/abstract.rb +29 -0
- data/lib/lite/validation/validator/option/some/complex/registry/abstract.rb +67 -0
- data/lib/lite/validation/validator/option/some/complex/registry/node.rb +47 -0
- data/lib/lite/validation/validator/option/some/complex/registry/root.rb +31 -0
- data/lib/lite/validation/validator/option/some/complex/registry.rb +32 -0
- data/lib/lite/validation/validator/option/some/complex/wrappers/abstract/iterable.rb +31 -0
- data/lib/lite/validation/validator/option/some/complex/wrappers/abstract/non_iterable.rb +27 -0
- data/lib/lite/validation/validator/option/some/complex/wrappers/abstract.rb +35 -0
- data/lib/lite/validation/validator/option/some/complex/wrappers/array.rb +41 -0
- data/lib/lite/validation/validator/option/some/complex/wrappers/hash.rb +40 -0
- data/lib/lite/validation/validator/option/some/complex/wrappers/object.rb +34 -0
- data/lib/lite/validation/validator/option/some/complex/wrappers/tuple.rb +47 -0
- data/lib/lite/validation/validator/option/some/complex/wrappers.rb +5 -0
- data/lib/lite/validation/validator/option/some/complex.rb +24 -0
- data/lib/lite/validation/validator/option/some/dig.rb +34 -0
- data/lib/lite/validation/validator/option/some/simple.rb +23 -0
- data/lib/lite/validation/validator/option/some/singular.rb +29 -0
- data/lib/lite/validation/validator/option/some.rb +20 -0
- data/lib/lite/validation/validator/option.rb +20 -0
- data/lib/lite/validation/validator/predicate/abstract/variants.rb +23 -0
- data/lib/lite/validation/validator/predicate/foreign/adapter/input/single.rb +21 -0
- data/lib/lite/validation/validator/predicate/foreign/adapter/input/tuple.rb +21 -0
- data/lib/lite/validation/validator/predicate/foreign/adapter/input.rb +28 -0
- data/lib/lite/validation/validator/predicate/foreign/adapter/ruling/instance.rb +37 -0
- data/lib/lite/validation/validator/predicate/foreign/adapter/ruling.rb +26 -0
- data/lib/lite/validation/validator/predicate/foreign/engine.rb +27 -0
- data/lib/lite/validation/validator/predicate/foreign/variant.rb +33 -0
- data/lib/lite/validation/validator/predicate/foreign/variants.rb +46 -0
- data/lib/lite/validation/validator/predicate/native/builder.rb +72 -0
- data/lib/lite/validation/validator/predicate/native/definite.rb +19 -0
- data/lib/lite/validation/validator/predicate/native/instance.rb +41 -0
- data/lib/lite/validation/validator/predicate/native/optional.rb +34 -0
- data/lib/lite/validation/validator/predicate/registry.rb +47 -0
- data/lib/lite/validation/validator/predicate.rb +17 -0
- data/lib/lite/validation/validator/result/abstract/failure.rb +21 -0
- data/lib/lite/validation/validator/result/abstract/instance.rb +18 -0
- data/lib/lite/validation/validator/result/abstract/success.rb +17 -0
- data/lib/lite/validation/validator/result/abstract.rb +29 -0
- data/lib/lite/validation/validator/result/committed.rb +75 -0
- data/lib/lite/validation/validator/result/disputable/hash.rb +17 -0
- data/lib/lite/validation/validator/result/disputable/instance.rb +43 -0
- data/lib/lite/validation/validator/result/disputable/iterable/array.rb +23 -0
- data/lib/lite/validation/validator/result/disputable/iterable.rb +17 -0
- data/lib/lite/validation/validator/result/disputable/navigable.rb +35 -0
- data/lib/lite/validation/validator/result/disputable.rb +14 -0
- data/lib/lite/validation/validator/result/disputed/abstract/hash.rb +32 -0
- data/lib/lite/validation/validator/result/disputed/abstract/instance.rb +26 -0
- data/lib/lite/validation/validator/result/disputed/iterable/array.rb +42 -0
- data/lib/lite/validation/validator/result/disputed/iterable/hash.rb +38 -0
- data/lib/lite/validation/validator/result/disputed/iterable.rb +20 -0
- data/lib/lite/validation/validator/result/disputed/navigable.rb +59 -0
- data/lib/lite/validation/validator/result/disputed.rb +17 -0
- data/lib/lite/validation/validator/result/refuted.rb +78 -0
- data/lib/lite/validation/validator/result/valid/abstract/collect.rb +42 -0
- data/lib/lite/validation/validator/result/valid/abstract/commit.rb +25 -0
- data/lib/lite/validation/validator/result/valid/abstract/instance.rb +23 -0
- data/lib/lite/validation/validator/result/valid/iterable/array/abstract.rb +24 -0
- data/lib/lite/validation/validator/result/valid/iterable/array/tuples.rb +64 -0
- data/lib/lite/validation/validator/result/valid/iterable/array/values.rb +42 -0
- data/lib/lite/validation/validator/result/valid/iterable/hash.rb +46 -0
- data/lib/lite/validation/validator/result/valid/iterable.rb +33 -0
- data/lib/lite/validation/validator/result/valid/navigable.rb +68 -0
- data/lib/lite/validation/validator/result/valid.rb +21 -0
- data/lib/lite/validation/validator/result.rb +15 -0
- data/lib/lite/validation/validator/ruling/abstract/invalid.rb +59 -0
- data/lib/lite/validation/validator/ruling/abstract/valid.rb +23 -0
- data/lib/lite/validation/validator/ruling/abstract.rb +12 -0
- data/lib/lite/validation/validator/ruling/commit.rb +17 -0
- data/lib/lite/validation/validator/ruling/dispute.rb +21 -0
- data/lib/lite/validation/validator/ruling/invalidate.rb +32 -0
- data/lib/lite/validation/validator/ruling/pass.rb +19 -0
- data/lib/lite/validation/validator/ruling/refute.rb +21 -0
- data/lib/lite/validation/validator/ruling.rb +53 -0
- data/lib/lite/validation/validator/state/instance.rb +46 -0
- data/lib/lite/validation/validator/state/merge_strategy.rb +50 -0
- data/lib/lite/validation/validator/state/unwrap_strategy.rb +31 -0
- data/lib/lite/validation/validator/state.rb +21 -0
- data/lib/lite/validation/validator.rb +15 -0
- data/lib/lite/validation/version.rb +9 -0
- data/lib/lite/validation.rb +8 -0
- metadata +196 -0
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'implementation/apply_ruling'
|
|
4
|
+
require_relative 'implementation/navigation'
|
|
5
|
+
require_relative 'implementation/identity'
|
|
6
|
+
require_relative 'implementation/iteration'
|
|
7
|
+
require_relative 'implementation/predication'
|
|
8
|
+
require_relative 'implementation/scoping'
|
|
9
|
+
|
|
10
|
+
module Lite
|
|
11
|
+
module Validation
|
|
12
|
+
module Validator
|
|
13
|
+
module Node
|
|
14
|
+
module Abstract
|
|
15
|
+
include Implementation::Identity
|
|
16
|
+
include Implementation::ApplyRuling
|
|
17
|
+
include Implementation::Navigation
|
|
18
|
+
include Implementation::Iteration
|
|
19
|
+
include Implementation::Predication
|
|
20
|
+
include Implementation::Scoping
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'abstract/instance'
|
|
4
|
+
require_relative 'abstract/leaf'
|
|
5
|
+
require_relative 'abstract/branch'
|
|
6
|
+
require_relative '../result'
|
|
7
|
+
require_relative '../state'
|
|
8
|
+
require_relative '../option'
|
|
9
|
+
|
|
10
|
+
module Lite
|
|
11
|
+
module Validation
|
|
12
|
+
module Validator
|
|
13
|
+
module Node
|
|
14
|
+
module Child
|
|
15
|
+
module Parent
|
|
16
|
+
def child(path, result, option: self.option, state: self.state)
|
|
17
|
+
if path.nil? || path.empty?
|
|
18
|
+
self.class::Leaf.instance(parent, self.path, option, result, state)
|
|
19
|
+
else
|
|
20
|
+
Child::Leaf.instance(self, path, option, result, state)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
include Parent
|
|
26
|
+
|
|
27
|
+
def inspect
|
|
28
|
+
"#<Child::#{super}"
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
class Leaf < Abstract::Instance
|
|
32
|
+
include Abstract::Leaf
|
|
33
|
+
include Child
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
class Branch < Abstract::Instance
|
|
37
|
+
include Abstract::Branch
|
|
38
|
+
include Child
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../../ruling'
|
|
4
|
+
require_relative 'helpers/with_result'
|
|
5
|
+
|
|
6
|
+
module Lite
|
|
7
|
+
module Validation
|
|
8
|
+
module Validator
|
|
9
|
+
module Node
|
|
10
|
+
module Implementation
|
|
11
|
+
module ApplyRuling
|
|
12
|
+
include Ruling::Constructors
|
|
13
|
+
|
|
14
|
+
def commit(value)
|
|
15
|
+
ApplyRuling.apply_ruling(self, Commit(value))
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def auto_commit(as:)
|
|
19
|
+
Helpers::WithResult.with_result(self, result.auto_commit(as: as))
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def dispute(error, at: nil, **opts)
|
|
23
|
+
ApplyRuling.apply_ruling(self, Dispute(error, **opts), path: at)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def refute(error, at: nil, **opts)
|
|
27
|
+
ApplyRuling.apply_ruling(self, Refute(error, **opts), path: at)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def self.apply_ruling(validator, ruling, path: nil)
|
|
31
|
+
return validator if ruling.is_a?(Ruling::Pass)
|
|
32
|
+
|
|
33
|
+
updated, _meta = validator.result.navigate(*path) do |result|
|
|
34
|
+
applied = Ruling.apply(ruling, result, validator.coordinator)
|
|
35
|
+
validator.merge_strategy.transform_result(applied, validator, path)
|
|
36
|
+
end
|
|
37
|
+
Helpers::WithResult.with_result(validator, updated)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../../helpers/path'
|
|
4
|
+
require_relative '../../option/some/complex/wrappers/abstract'
|
|
5
|
+
require_relative 'helpers/with_result'
|
|
6
|
+
|
|
7
|
+
module Lite
|
|
8
|
+
module Validation
|
|
9
|
+
module Validator
|
|
10
|
+
module Node
|
|
11
|
+
module Implementation
|
|
12
|
+
module Dig
|
|
13
|
+
protected
|
|
14
|
+
|
|
15
|
+
def dig(*path, from: nil, &block)
|
|
16
|
+
from = Validator::Helpers::Path.expand_path(from || path, [])
|
|
17
|
+
dig!(path, from, &block)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
def dig!(path, from, &block)
|
|
23
|
+
updated, _meta = result.navigate(*path) do |local|
|
|
24
|
+
option = self.option.dig(from)
|
|
25
|
+
|
|
26
|
+
block.call(option, local)
|
|
27
|
+
rescue Option::Some::Complex::Wrappers::Abstract::InvalidAccess => e
|
|
28
|
+
local.refute(coordinator.internal_error(:invalid_access, message: e.message))
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
Helpers::WithResult.with_result(self, updated)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Lite
|
|
4
|
+
module Validation
|
|
5
|
+
module Validator
|
|
6
|
+
module Node
|
|
7
|
+
module Implementation
|
|
8
|
+
module Helpers
|
|
9
|
+
module CallForeign
|
|
10
|
+
def self.call_foreign(result, coordinator, &block)
|
|
11
|
+
block.call
|
|
12
|
+
rescue Error::Fatal
|
|
13
|
+
raise
|
|
14
|
+
rescue StandardError => e
|
|
15
|
+
rescue_execution_error(result, coordinator, e)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def self.rescue_execution_error(result, coordinator, error)
|
|
19
|
+
error = coordinator.internal_error(
|
|
20
|
+
:execution_error,
|
|
21
|
+
message: error.message, data: { error_class: error.class.name }
|
|
22
|
+
)
|
|
23
|
+
result.refute(error)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../../../ruling'
|
|
4
|
+
|
|
5
|
+
module Lite
|
|
6
|
+
module Validation
|
|
7
|
+
module Validator
|
|
8
|
+
module Node
|
|
9
|
+
module Implementation
|
|
10
|
+
module Helpers
|
|
11
|
+
module WithResult
|
|
12
|
+
def self.with_result(validator, result)
|
|
13
|
+
return validator if result.equal?(validator.result)
|
|
14
|
+
|
|
15
|
+
validator.send(:with, result: result)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../../../../error'
|
|
4
|
+
|
|
5
|
+
module Lite
|
|
6
|
+
module Validation
|
|
7
|
+
module Validator
|
|
8
|
+
module Node
|
|
9
|
+
module Implementation
|
|
10
|
+
module Helpers
|
|
11
|
+
module YieldStrategy
|
|
12
|
+
module Skip
|
|
13
|
+
def self.child_parameters(validator, option, result, &block)
|
|
14
|
+
maybe_yield(nil, option, result) { block.call(option, validator.send(:state).value_definite) }
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def self.block_parameters(_validator, option, result, &block)
|
|
18
|
+
maybe_yield(nil, option, result) { block.call(option.unwrap) }
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def self.maybe_yield(_, option, result, &block)
|
|
22
|
+
option.some? ? block.call : result
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
module Nullify
|
|
27
|
+
def self.child_parameters(_validator, option, _result, &block)
|
|
28
|
+
block.call(option.some_or_nil)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def self.block_parameters(_validator, option, _result, &block)
|
|
32
|
+
block.call(option.some_or_nil.unwrap)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
module Refute
|
|
37
|
+
def self.child_parameters(validator, option, result, &block)
|
|
38
|
+
maybe_yield(validator, option, result) { block.call(option, validator.send(:state).value_definite) }
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def self.block_parameters(validator, option, result, &block)
|
|
42
|
+
maybe_yield(validator, option, result) { block.call(option.unwrap) }
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def self.maybe_yield(validator, option, result, &block)
|
|
46
|
+
option.some? ? block.call : result.refute(validator.coordinator.internal_error(:value_missing))
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
module YieldOption
|
|
51
|
+
def self.child_parameters(validator, option, _result, &block)
|
|
52
|
+
block.call(option, validator.send(:state).value_optional)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def self.block_parameters(validator, option, _result, &block)
|
|
56
|
+
block.call(option.to_option(validator.coordinator))
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def self.to_yield(strategy)
|
|
61
|
+
case strategy
|
|
62
|
+
when :skip then Skip
|
|
63
|
+
when :nullify then Nullify
|
|
64
|
+
when :refute then Refute
|
|
65
|
+
when :yield_option then YieldOption
|
|
66
|
+
else raise Error::Fatal, "Unexpected missing yield strategy: #{strategy}"
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def self.to_iterate(strategy)
|
|
71
|
+
case strategy
|
|
72
|
+
when :skip then Skip
|
|
73
|
+
when :refute then Refute
|
|
74
|
+
else raise Error::Fatal, "Unexpected missing iteration strategy: #{strategy}"
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'call_foreign'
|
|
4
|
+
|
|
5
|
+
module Lite
|
|
6
|
+
module Validation
|
|
7
|
+
module Validator
|
|
8
|
+
module Node
|
|
9
|
+
module Implementation
|
|
10
|
+
module Helpers
|
|
11
|
+
module YieldValidator
|
|
12
|
+
def self.yield_child(parent, child, block)
|
|
13
|
+
updated, meta = yield_validator(child, block)
|
|
14
|
+
transformed = parent.merge_strategy.transform_result(updated, parent, child.path)
|
|
15
|
+
[transformed, meta]
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def self.yield_validator(validator, block)
|
|
19
|
+
validator = ensure_valid_result!(validator, block.call(validator))
|
|
20
|
+
|
|
21
|
+
[validator.result, validator.context]
|
|
22
|
+
rescue Error::Fatal
|
|
23
|
+
raise
|
|
24
|
+
rescue StandardError => e
|
|
25
|
+
[
|
|
26
|
+
CallForeign.rescue_execution_error(validator.result, validator.coordinator, e),
|
|
27
|
+
validator.context
|
|
28
|
+
]
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def self.ensure_valid_result!(origin, result)
|
|
32
|
+
ensure_validator!(result)
|
|
33
|
+
Implementation::Identity.ensure_identical! origin, result
|
|
34
|
+
|
|
35
|
+
result
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def self.ensure_validator!(candidate)
|
|
39
|
+
return if candidate.is_a?(Abstract::Instance)
|
|
40
|
+
|
|
41
|
+
raise Error::Fatal, "Validator expected, got: #{candidate.inspect}"
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Lite
|
|
4
|
+
module Validation
|
|
5
|
+
module Validator
|
|
6
|
+
module Node
|
|
7
|
+
module Implementation
|
|
8
|
+
module Identity
|
|
9
|
+
def self.intent_id
|
|
10
|
+
@count ||= 0
|
|
11
|
+
@count += 1
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def self.ensure_identical!(origin, current)
|
|
15
|
+
return if origin.identical?(current)
|
|
16
|
+
|
|
17
|
+
raise_error!(origin, current, origin.send(:intent) == current.send(:intent) ? :origin : :intent)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def self.raise_error!(origin, current, key)
|
|
21
|
+
full = key == :intent
|
|
22
|
+
message = "Not the #{key}: #{origin.send(:display_path, full)} <> #{current.send(:display_path, full)}"
|
|
23
|
+
raise Error::Fatal, message
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def self.display_path(full_path)
|
|
27
|
+
case full_path
|
|
28
|
+
when Array then "[#{full_path.map { |element| display_path_element(element) }.join(',')}]"
|
|
29
|
+
else full_path
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def self.display_path_element(element)
|
|
34
|
+
case element
|
|
35
|
+
when Array then "(#{element.map { |path| display_path(path) }.join(',')})"
|
|
36
|
+
else element
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def identical?(other)
|
|
41
|
+
return true if other.equal?(self)
|
|
42
|
+
return false unless other.path == path
|
|
43
|
+
return true if other.parent.equal?(parent)
|
|
44
|
+
return false if other.root? || root?
|
|
45
|
+
|
|
46
|
+
other.parent.identical?(parent)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def key
|
|
50
|
+
path.last
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def full_path(full)
|
|
54
|
+
if root?
|
|
55
|
+
full ? path : []
|
|
56
|
+
else
|
|
57
|
+
parent.full_path(full) + path
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def display_path(full)
|
|
62
|
+
Identity.display_path(full_path(full))
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def path_to(ancestor)
|
|
66
|
+
trace(ancestor, trace: [])
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def intent
|
|
70
|
+
root? ? path.first : parent.intent
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def root?
|
|
74
|
+
parent.nil?
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
protected
|
|
78
|
+
|
|
79
|
+
def trace(ancestor, trace: [])
|
|
80
|
+
return trace if ancestor.identical?(self)
|
|
81
|
+
return if root?
|
|
82
|
+
|
|
83
|
+
parent.trace(ancestor, trace: path + trace)
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../helpers/yield_strategy'
|
|
4
|
+
require_relative '../helpers/yield_validator'
|
|
5
|
+
require_relative '../validation'
|
|
6
|
+
|
|
7
|
+
module Lite
|
|
8
|
+
module Validation
|
|
9
|
+
module Validator
|
|
10
|
+
module Node
|
|
11
|
+
module Implementation
|
|
12
|
+
module Iteration
|
|
13
|
+
class Iterator
|
|
14
|
+
def self.iterate(node, path, from, strategy, commit, &block)
|
|
15
|
+
node.send(:dig!, path, from) do |option, result|
|
|
16
|
+
Helpers::YieldStrategy
|
|
17
|
+
.to_iterate(strategy)
|
|
18
|
+
.maybe_yield(node, option, result) do
|
|
19
|
+
complex = option.to_complex
|
|
20
|
+
next result.refute(node.coordinator.internal_error(:not_iterable)) unless complex.iterable?
|
|
21
|
+
|
|
22
|
+
iterable = node.child(path, result.iterable(commit: commit), option: complex)
|
|
23
|
+
updated, meta = reduce(iterable, block)
|
|
24
|
+
|
|
25
|
+
[node.merge_strategy.transform_result(updated.navigable, node, path), meta]
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def self.reduce(iterable, block)
|
|
31
|
+
iterable.send(:option).reduce([iterable.result, iterable.context]) do |(result, context), (value, key)|
|
|
32
|
+
break [result, context] if result.refuted?
|
|
33
|
+
|
|
34
|
+
result.navigate(key) do |key_result|
|
|
35
|
+
block.call(iterable, key, value, key_result, context)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def initialize(parent, path, from, strategy, commit)
|
|
41
|
+
@parent = parent
|
|
42
|
+
@path = path
|
|
43
|
+
@from = from
|
|
44
|
+
@strategy = strategy
|
|
45
|
+
@commit = commit
|
|
46
|
+
freeze
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def validate(commit: false, &block)
|
|
50
|
+
self.class.iterate(
|
|
51
|
+
parent,
|
|
52
|
+
path,
|
|
53
|
+
from,
|
|
54
|
+
strategy,
|
|
55
|
+
self.commit
|
|
56
|
+
) do |iterable, _key, value, result, context|
|
|
57
|
+
updated = Validation.validate(
|
|
58
|
+
iterable.coordinator,
|
|
59
|
+
value,
|
|
60
|
+
result,
|
|
61
|
+
context,
|
|
62
|
+
commit,
|
|
63
|
+
block
|
|
64
|
+
)
|
|
65
|
+
[updated, context]
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def satisfy(using: nil, severity: :dispute, commit: false, &block)
|
|
70
|
+
predicate = Predication
|
|
71
|
+
.resolve_predicate(using, from, parent.context, block)
|
|
72
|
+
.definite
|
|
73
|
+
.send(severity)
|
|
74
|
+
|
|
75
|
+
self.class.iterate(
|
|
76
|
+
parent,
|
|
77
|
+
path,
|
|
78
|
+
from,
|
|
79
|
+
strategy,
|
|
80
|
+
self.commit
|
|
81
|
+
) do |iterable, _key, value, result, context|
|
|
82
|
+
Validation.validate(
|
|
83
|
+
iterable.coordinator,
|
|
84
|
+
value,
|
|
85
|
+
result,
|
|
86
|
+
context,
|
|
87
|
+
commit,
|
|
88
|
+
predicate
|
|
89
|
+
)
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
private
|
|
94
|
+
|
|
95
|
+
attr_reader :parent, :path, :from, :strategy, :commit
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'dig'
|
|
4
|
+
require_relative 'helpers/yield_validator'
|
|
5
|
+
require_relative 'helpers/yield_strategy'
|
|
6
|
+
require_relative 'iteration/iterator'
|
|
7
|
+
|
|
8
|
+
module Lite
|
|
9
|
+
module Validation
|
|
10
|
+
module Validator
|
|
11
|
+
module Node
|
|
12
|
+
module Implementation
|
|
13
|
+
module Iteration
|
|
14
|
+
include Dig
|
|
15
|
+
|
|
16
|
+
def each_at?(*path, from: nil, commit: false, &block)
|
|
17
|
+
each_at!(path, from, :skip, commit, block)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def each_at(*path, from: nil, commit: false, &block)
|
|
21
|
+
each_at!(path, from, :refute, commit, block)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
private
|
|
25
|
+
|
|
26
|
+
def each_at!(path, from, strategy, commit, block)
|
|
27
|
+
from = Validator::Helpers::Path.expand_path(from || path, [])
|
|
28
|
+
return Iterator.new(self, path, from, strategy, commit) if block.nil?
|
|
29
|
+
|
|
30
|
+
Iterator.iterate(self, path, from, strategy, commit) do |iterable, key, value, result, context|
|
|
31
|
+
child = iterable.child(
|
|
32
|
+
[key],
|
|
33
|
+
result,
|
|
34
|
+
option: Option.some(value),
|
|
35
|
+
state: iterable.send(:state).with(context: context).value_definite
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
Helpers::YieldValidator.yield_child(iterable, child, block)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'dig'
|
|
4
|
+
require_relative 'helpers/yield_validator'
|
|
5
|
+
require_relative '../suspended'
|
|
6
|
+
require_relative 'helpers/yield_strategy'
|
|
7
|
+
|
|
8
|
+
module Lite
|
|
9
|
+
module Validation
|
|
10
|
+
module Validator
|
|
11
|
+
module Node
|
|
12
|
+
module Implementation
|
|
13
|
+
module Navigation
|
|
14
|
+
include Dig
|
|
15
|
+
|
|
16
|
+
def at?(*path, from: nil, &block)
|
|
17
|
+
return Suspended.new(:at!, self, path, from) if block.nil?
|
|
18
|
+
|
|
19
|
+
at!(path, from, :skip, block)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def at(*path, from: nil, &block)
|
|
23
|
+
at!(path, from, :refute, block)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
private
|
|
27
|
+
|
|
28
|
+
def at!(path, from, strategy, block)
|
|
29
|
+
dig(*path, from: from) do |option, result|
|
|
30
|
+
strategy = Helpers::YieldStrategy.to_yield(strategy)
|
|
31
|
+
strategy.child_parameters(self, option, result) do |to_yield, child_state|
|
|
32
|
+
child = child(path, result, option: to_yield, state: child_state)
|
|
33
|
+
|
|
34
|
+
Helpers::YieldValidator.yield_child(self, child, block)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'validation'
|
|
4
|
+
require_relative '../../predicate/registry'
|
|
5
|
+
|
|
6
|
+
module Lite
|
|
7
|
+
module Validation
|
|
8
|
+
module Validator
|
|
9
|
+
module Node
|
|
10
|
+
module Implementation
|
|
11
|
+
module Predication
|
|
12
|
+
include Validation
|
|
13
|
+
|
|
14
|
+
def self.resolve_predicate(using, path, context, block)
|
|
15
|
+
object = call_builder_block(using, path, context, block)
|
|
16
|
+
fetch_predicate(object)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def self.call_builder_block(using, path, context, block)
|
|
20
|
+
case using
|
|
21
|
+
when nil then block.call(context)
|
|
22
|
+
else
|
|
23
|
+
engine = Predicate::Registry.engine(using)
|
|
24
|
+
engine.build_contextual(path, context, &block)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def self.fetch_predicate(object)
|
|
29
|
+
case object
|
|
30
|
+
when Symbol then Predicate::Registry.predicate(object)
|
|
31
|
+
when Predicate::Abstract::Variants then object
|
|
32
|
+
else raise Error::Fatal, "Unexpected predicate object: #{object.inspect}"
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def satisfy?(*path, from: nil, using: nil, severity: :dispute, commit: false, &block)
|
|
37
|
+
return Suspended.new(:satisfy!, self, path, from, using, severity, commit) if block.nil?
|
|
38
|
+
|
|
39
|
+
satisfy!(path, from, :skip, using, severity, commit, block)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def satisfy(*path, from: nil, using: nil, severity: :dispute, commit: false, &block)
|
|
43
|
+
satisfy!(path, from, :refute, using, severity, commit, block)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
private
|
|
47
|
+
|
|
48
|
+
# rubocop:disable Metrics/ParameterLists
|
|
49
|
+
def satisfy!(path, from, strategy, using, severity, commit, block)
|
|
50
|
+
from = Validator::Helpers::Path.expand_path(from || path, [])
|
|
51
|
+
predicate = Predication.resolve_predicate(using, from, context, block)
|
|
52
|
+
variant = strategy == :yield_option ? predicate.optional : predicate.definite
|
|
53
|
+
validate!(path, from, strategy, commit, variant.send(severity))
|
|
54
|
+
end
|
|
55
|
+
# rubocop:enable Metrics/ParameterLists
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|