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,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../helpers/with_result'
4
+
5
+ module Lite
6
+ module Validation
7
+ module Validator
8
+ module Node
9
+ module Implementation
10
+ module Scoping
11
+ class Evaluator
12
+ def self.instance(validator, path)
13
+ new(validator, [path].freeze)
14
+ end
15
+
16
+ private_class_method :new
17
+
18
+ def initialize(validator, paths)
19
+ @validator = validator
20
+ @paths = paths
21
+ end
22
+
23
+ def and(path, &block)
24
+ compound = self.class.send(:new, validator, [*paths, path])
25
+ return compound if block.nil?
26
+
27
+ compound.call(&block)
28
+ end
29
+
30
+ attr_reader :validator, :paths
31
+
32
+ def call(&block)
33
+ return validator unless paths.all? { validator.result.success_at?(*_1) }
34
+
35
+ Helpers::WithResult.with_result(validator, validator.send(:wrap, &block))
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'helpers/yield_validator'
4
+ require_relative 'scoping/evaluator'
5
+ require_relative 'dig'
6
+ require_relative 'wrap'
7
+
8
+ module Lite
9
+ module Validation
10
+ module Validator
11
+ module Node
12
+ module Implementation
13
+ module Scoping
14
+ include Dig
15
+ include Wrap
16
+
17
+ def critical(error_generator, &block)
18
+ dig do |_option, result|
19
+ child = child(nil, result, state: state.critical(self, error_generator))
20
+ updated, _meta = Helpers::YieldValidator.yield_validator(child, block)
21
+ updated.refuted? ? updated.with(fall_through: false) : updated
22
+ end
23
+ end
24
+
25
+ def with_context(context, &block)
26
+ if block
27
+ result, _meta = wrap(state: state.with(context: context), &block)
28
+ Helpers::WithResult.with_result(self, result)
29
+ else
30
+ with(state: state.with(context: context))
31
+ end
32
+ end
33
+
34
+ def with_valid(*path, &block)
35
+ with_valid = Evaluator.instance(self, path)
36
+ block.nil? ? with_valid : with_valid.call(&block)
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'dig'
4
+ require_relative '../suspended'
5
+ require_relative 'helpers/call_foreign'
6
+ require_relative 'helpers/yield_strategy'
7
+
8
+ module Lite
9
+ module Validation
10
+ module Validator
11
+ module Node
12
+ module Implementation
13
+ module Validation
14
+ # rubocop:disable Metrics/ParameterLists
15
+ def self.validate(coordinator, to_yield, result, context, commit, block)
16
+ updated = Helpers::CallForeign.call_foreign(result, coordinator) do
17
+ ruling = block.call(to_yield, context)
18
+ Validator::Ruling.apply(ruling.nil? ? Validator::Ruling::Pass() : ruling, result, coordinator)
19
+ end
20
+
21
+ case commit
22
+ when false then updated
23
+ when true then updated.commit(to_yield)
24
+ else raise Error::Fatal, "Invalid commit argument. Expected boolean, got: #{commit.inspect}"
25
+ end
26
+ end
27
+ # rubocop:enable Metrics/ParameterLists
28
+
29
+ def validate?(*path, from: nil, commit: false, &block)
30
+ from = Validator::Helpers::Path.expand_path(from || path, [])
31
+ return Suspended.new(:validate!, self, path, from, commit) if block.nil?
32
+
33
+ validate!(path, from, :skip, commit, block)
34
+ end
35
+
36
+ def validate(*path, from: nil, commit: false, &block)
37
+ from = Validator::Helpers::Path.expand_path(from || path, [])
38
+ validate!(path, from, :refute, commit, block)
39
+ end
40
+
41
+ private
42
+
43
+ def validate!(path, from, strategy, commit, block)
44
+ strategy = Helpers::YieldStrategy.to_yield(strategy)
45
+ dig!(path, from) do |option, result|
46
+ updated = strategy.block_parameters(self, option, result) do |to_yield|
47
+ Validation.validate(
48
+ coordinator,
49
+ to_yield,
50
+ result,
51
+ context,
52
+ commit,
53
+ block
54
+ )
55
+ end
56
+ merge_strategy.transform_result(updated, self, path)
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'helpers/call_foreign'
4
+ require_relative 'helpers/yield_validator'
5
+
6
+ module Lite
7
+ module Validation
8
+ module Validator
9
+ module Node
10
+ module Implementation
11
+ module Wrap
12
+ private
13
+
14
+ def wrap(**opts, &block)
15
+ Helpers::CallForeign.call_foreign(result, coordinator) do
16
+ proxy = opts.empty? ? self : child(nil, result, **opts)
17
+
18
+ Helpers::YieldValidator.ensure_valid_result!(proxy, block.call(proxy)).result
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../result'
4
+ require_relative '../state'
5
+ require_relative '../option'
6
+
7
+ require_relative 'abstract/instance'
8
+ require_relative 'abstract/leaf'
9
+ require_relative 'abstract/branch'
10
+ require_relative 'child'
11
+
12
+ module Lite
13
+ module Validation
14
+ module Validator
15
+ module Node
16
+ module Root
17
+ include Child::Parent
18
+
19
+ def self.initial(bare_value, coordinator, context: nil)
20
+ Leaf.instance(
21
+ nil,
22
+ [Node::Implementation::Identity.intent_id],
23
+ Option.some(bare_value),
24
+ Result.valid,
25
+ State.initial(coordinator, context: context)
26
+ )
27
+ end
28
+
29
+ def to_result(coordinator: self.coordinator)
30
+ result.success? ? to_success(coordinator) : to_failure(coordinator)
31
+ end
32
+
33
+ def inspect
34
+ "#<Root::#{super}"
35
+ end
36
+
37
+ private
38
+
39
+ def to_success(coordinator)
40
+ coordinator.success(result.success.some? ? result.success.value : option.value)
41
+ end
42
+
43
+ def to_failure(coordinator)
44
+ coordinator.failure(result.to_failure(coordinator))
45
+ end
46
+
47
+ class Leaf < Abstract::Instance
48
+ include Abstract::Leaf
49
+ include Root
50
+ end
51
+
52
+ class Branch < Abstract::Instance
53
+ include Abstract::Branch
54
+ include Root
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lite
4
+ module Validation
5
+ module Validator
6
+ module Node
7
+ class Suspended
8
+ def initialize(action, node, path, from, *args)
9
+ @action = action
10
+ @node = node
11
+ @path = path
12
+ @from = from
13
+ @args = args
14
+ end
15
+
16
+ attr_reader :action, :node, :path, :from, :args
17
+
18
+ def option(&block)
19
+ node.send(action, path, from, :yield_option, *args, block)
20
+ end
21
+
22
+ def some(&block)
23
+ node.send(action, path, from, :skip, *args, block)
24
+ end
25
+
26
+ def some_or_nil(&block)
27
+ node.send(action, path, from, :nullify, *args, block)
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'node/root'
4
+
5
+ module Lite
6
+ module Validation
7
+ module Validator
8
+ module Node
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lite
4
+ module Validation
5
+ module Validator
6
+ module Option
7
+ module None
8
+ def self.some?
9
+ false
10
+ end
11
+
12
+ def self.none?
13
+ true
14
+ end
15
+
16
+ def self.dig(*_path)
17
+ self
18
+ end
19
+
20
+ def self.to_complex
21
+ self
22
+ end
23
+
24
+ def self.some_or_nil
25
+ Option.some(nil)
26
+ end
27
+
28
+ def self.to_option(coordinator)
29
+ coordinator.none
30
+ end
31
+
32
+ def self.iterable?
33
+ false
34
+ end
35
+
36
+ def self.inspect
37
+ '#<Option::None>'
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'lite/data'
4
+
5
+ module Lite
6
+ module Validation
7
+ module Validator
8
+ module Option
9
+ module Some
10
+ class Abstract
11
+ Lite::Data.define(self, args: %i[value])
12
+
13
+ def some?
14
+ true
15
+ end
16
+
17
+ def none?
18
+ false
19
+ end
20
+
21
+ def inspect
22
+ "#<Option::Some value of #{value.class.name}>"
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'lite/data'
4
+
5
+ module Lite
6
+ module Validation
7
+ module Validator
8
+ module Option
9
+ module Some
10
+ module Complex
11
+ module Registry
12
+ class Abstract
13
+ Lite::Data.define(self, args: [:children])
14
+
15
+ private_class_method :new
16
+
17
+ def self.insert(node, children)
18
+ updated = insert_as_child(node, children)
19
+ return updated if updated
20
+
21
+ insert_as_parent(node, children)
22
+ end
23
+
24
+ def self.insert_as_child(node, children)
25
+ parents, unrelated = children.partition { |child| child.key >= node.key }
26
+
27
+ case parents.length
28
+ when 0 then nil
29
+ when 1
30
+ [parents.first.insert(node), *unrelated]
31
+ else
32
+ raise Error, "Multiple parents found for #{node.key}: #{parents.map(&:key).join(', ')}"
33
+ end
34
+ end
35
+
36
+ def self.insert_as_parent(node, children)
37
+ descendants, unrelated = children.partition { |child| child.key < node.key }
38
+
39
+ if descendants.empty?
40
+ [*unrelated, node]
41
+ else
42
+ [node.with(children: descendants.freeze), *unrelated]
43
+ end
44
+ end
45
+
46
+ def insert(node)
47
+ with(children: self.class.insert(node, children).freeze)
48
+ end
49
+
50
+ def wrapper_for(key)
51
+ provider = children.find { |candidate| candidate.key >= key }
52
+ provider&.wrapper_for(key)
53
+ end
54
+
55
+ private
56
+
57
+ def describe_children(severity)
58
+ children.flat_map { |child| child.describe(severity) }
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'abstract'
4
+
5
+ module Lite
6
+ module Validation
7
+ module Validator
8
+ module Option
9
+ module Some
10
+ module Complex
11
+ module Registry
12
+ class Node < Abstract
13
+ Lite::Data.define(self, args: %i[key wrapper])
14
+
15
+ def self.instance(key, wrapper, children: [])
16
+ raise Error, "Key must be a class, got: #{key.inpect}" unless key.is_a?(Class)
17
+
18
+ new key, wrapper, children.freeze
19
+ end
20
+
21
+ private_class_method :new
22
+
23
+ def insert(node)
24
+ if key > node.key
25
+ super
26
+ elsif key == node.key
27
+ with(wrapper: node.wrapper)
28
+ end
29
+ end
30
+
31
+ def wrapper_for(key)
32
+ return if self.key < key
33
+
34
+ super || wrapper
35
+ end
36
+
37
+ def describe(severity)
38
+ ["#{'--' * severity}#{key}:#{wrapper.class.name}", *describe_children(severity + 1)]
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'abstract'
4
+
5
+ module Lite
6
+ module Validation
7
+ module Validator
8
+ module Option
9
+ module Some
10
+ module Complex
11
+ module Registry
12
+ class Root < Abstract
13
+ def self.instance(children: [])
14
+ new children.freeze
15
+ end
16
+
17
+ def insert(key, wrapper)
18
+ super(Node.instance(key, wrapper))
19
+ end
20
+
21
+ def describe
22
+ describe_children(0).join("\n")
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'registry/root'
4
+ require_relative 'registry/node'
5
+
6
+ module Lite
7
+ module Validation
8
+ module Validator
9
+ module Option
10
+ module Some
11
+ module Complex
12
+ module Registry
13
+ def self.register(key, wrapper)
14
+ @root = root.insert(key, wrapper)
15
+ end
16
+
17
+ def self.root
18
+ @root ||= Root.instance
19
+ end
20
+
21
+ def self.wrapper_for(key)
22
+ root.wrapper_for(key)
23
+ end
24
+
25
+ private_constant :Abstract, :Root, :Node
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../abstract'
4
+
5
+ module Lite
6
+ module Validation
7
+ module Validator
8
+ module Option
9
+ module Some
10
+ module Complex
11
+ module Wrappers
12
+ module Abstract
13
+ class Iterable < Some::Abstract
14
+ include Abstract
15
+
16
+ def iterable?
17
+ true
18
+ end
19
+
20
+ def reduce
21
+ raise NotImplementedError, "#{self.class.name}##{__method__} unimplemented"
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../abstract'
4
+
5
+ module Lite
6
+ module Validation
7
+ module Validator
8
+ module Option
9
+ module Some
10
+ module Complex
11
+ module Wrappers
12
+ module Abstract
13
+ class NonIterable < Some::Abstract
14
+ include Abstract
15
+
16
+ def iterable?
17
+ false
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../../../../error'
4
+ require_relative '../../abstract'
5
+ require_relative '../registry'
6
+
7
+ module Lite
8
+ module Validation
9
+ module Validator
10
+ module Option
11
+ module Some
12
+ module Complex
13
+ module Wrappers
14
+ module Abstract
15
+ class InvalidAccess < Error::Fatal; end
16
+
17
+ def fetch(_key)
18
+ raise NotImplementedError, "#{self.class.name}##{__method__} unimplemented"
19
+ end
20
+
21
+ def iterable?
22
+ raise NotImplementedError, "#{self.class.name}##{__method__} unimplemented"
23
+ end
24
+
25
+ def to_complex
26
+ self
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,41 @@
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 Array < Abstract::Iterable
14
+ include Singular
15
+
16
+ def fetch(index)
17
+ raise InvalidAccess, "Invalid index to array: #{index}" unless index.is_a?(Integer)
18
+ return Option.none unless (0...value.length).include?(index)
19
+
20
+ Option.some(value[index])
21
+ end
22
+
23
+ def reduce(initial_state, &block)
24
+ value.lazy
25
+ .each_with_index
26
+ .reduce(initial_state, &block)
27
+ end
28
+
29
+ def inspect
30
+ "#<Option::Some::Array length=#{value.length}>"
31
+ end
32
+
33
+ Registry.register(::Array, self)
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end