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,89 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'benchmark'
4
+ require 'dry/validation'
5
+ require 'byebug'
6
+
7
+ require_relative '../spec/validation/validator/result/support/test_reducer'
8
+
9
+ module Lite
10
+ module Validation
11
+ module Validator
12
+ module Benchmark
13
+ module Calibrational
14
+ module Iteration
15
+ def self.run(n, k) # rubocop:disable Naming/MethodParameterName, Metrics/AbcSize
16
+ runs = {}
17
+
18
+ runs[:ValidArrayValues] = proc do |_idx|
19
+ ValidArrayValues.call(data(k), block)
20
+ end
21
+
22
+ runs[:ValidArrayTuples] = proc do |_idx|
23
+ ValidArrayTuples.call(data(k), block)
24
+ end
25
+
26
+ runs[:ValidHash] = proc do |_idx|
27
+ ValidHash.call(data(k), block)
28
+ end
29
+
30
+ runs.to_a.each do |key, proc|
31
+ result = ::Benchmark.measure { n.times { proc.call } }
32
+ puts "#{key}: #{result}"
33
+ end
34
+ end
35
+
36
+ def self.data(k) # rubocop:disable Naming/MethodParameterName
37
+ k.times.map do
38
+ Random.rand(0...100)
39
+ end
40
+ end
41
+
42
+ def self.block
43
+ lambda { |_iterable, _key, value, result, _context|
44
+ if value.negative?
45
+ result
46
+ else
47
+ [result.commit(value + 1), nil]
48
+ end
49
+ }
50
+ end
51
+
52
+ module ValidArrayValues
53
+ def self.call(data, block)
54
+ iterable = Result::Valid::Iterable::Array::Values.instance
55
+ Node::TestReducer.reduce(iterable, data, block).navigable
56
+ end
57
+ end
58
+
59
+ module ValidArrayTuples
60
+ def self.call(data, block)
61
+ iterable = Result::Valid::Iterable::Array::Tuples.instance(:hash)
62
+ Node::TestReducer.reduce(iterable, data, block).navigable
63
+ end
64
+ end
65
+
66
+ module ValidHash
67
+ def self.call(data, block)
68
+ iterable = Result::Valid::Iterable::Hash.instance(:hash, {})
69
+ Node::TestReducer.reduce(iterable, data, block).navigable
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
78
+
79
+ N = 10_000
80
+
81
+ k = 3
82
+ puts "------------------------------- #{N}, #{k} -------------------------------"
83
+ Lite::Validation::Validator::Benchmark::Calibrational::Iteration.run(N, k)
84
+ k = 30
85
+ puts "------------------------------- #{N}, #{k} -------------------------------"
86
+ Lite::Validation::Validator::Benchmark::Calibrational::Iteration.run(N, k)
87
+ k = 300
88
+ puts "------------------------------- #{N}, #{k} -------------------------------"
89
+ Lite::Validation::Validator::Benchmark::Calibrational::Iteration.run(N, k)
@@ -0,0 +1,197 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'benchmark'
4
+ require 'active_model'
5
+ require 'dry/validation'
6
+ require 'byebug'
7
+
8
+ require_relative '../spec/validation/validator/support/functional/contracts/hash'
9
+ require_relative '../spec/validation/validator/support/functional/coordinators/dry'
10
+ require_relative '../spec/validation/validator/support/shared/predicates/dry'
11
+
12
+ module Lite
13
+ module Validation
14
+ module Validator
15
+ module Benchmark
16
+ module Comparative
17
+ class DryBench < Dry::Validation::Contract
18
+ option(:limit)
19
+
20
+ json do
21
+ required(:id).filled(:string)
22
+ required(:price).value(:integer, gteq?: 0)
23
+ required(:dates).schema do
24
+ required(:issued).value(:date_time)
25
+ required(:due).value(:date_time)
26
+ end
27
+ required(:payments).array do
28
+ schema do
29
+ required(:amount).value(:integer, gteq?: 0)
30
+ required(:type).value(:string, included_in?: %w[card cash])
31
+ end
32
+ end
33
+ required(:items).array do
34
+ schema do
35
+ required(:id).filled(:string)
36
+ required(:name).filled(:string)
37
+ required(:price).value(:integer, gteq?: 0)
38
+ required(:qty).value(:integer, gteq?: 0)
39
+ end
40
+ end
41
+ end
42
+
43
+ rule(dates: %i[issued due]) do
44
+ next if value[0] <= value[1]
45
+
46
+ key.failure('first must be less than or equal to the second')
47
+ end
48
+
49
+ rule(:price) do
50
+ next if value <= limit
51
+
52
+ key.failure('is excessive')
53
+ end
54
+ end
55
+
56
+ class ActiveModelBench < Dry::Validation::Contract
57
+ def self.call(data, limit:)
58
+ model ||= BenchModel.instance(data, limit: limit)
59
+ model.valid? ? nil : model.errors
60
+ end
61
+
62
+ class BenchModel
63
+ def self.instance(data, limit:)
64
+ dates = Dates.new(**data[:dates])
65
+ items = data[:items].map { Item.new(**data.slice(:id, :name, :price, :qty)) }
66
+ payments = data[:payments].map { Payment.new(**data.slice(:amount, :type)) }
67
+
68
+ BenchModel.new(dates: dates, items: items, payments: payments, limit: limit, **data.slice(:id, :price))
69
+ end
70
+
71
+ class Dates
72
+ include ActiveModel::Model
73
+ include ActiveModel::Attributes
74
+ include ActiveModel::Validations
75
+
76
+ attribute :issued, :datetime
77
+ attribute :due, :datetime
78
+
79
+ validates :issued, presence: true
80
+ validates :due, presence: true
81
+
82
+ validate do
83
+ next if issued < due
84
+
85
+ errors.add('(issued,due)', 'first must be less than or equal to the second')
86
+ end
87
+ end
88
+
89
+ class Payment
90
+ include ActiveModel::Model
91
+ include ActiveModel::Attributes
92
+ include ActiveModel::Validations
93
+
94
+ attribute :amount, :integer
95
+ attribute :type, :string
96
+
97
+ validates :amount, presence: true, numericality: { greater_than: 0 }
98
+ validates :type, presence: true, inclusion: %w[cash card]
99
+ end
100
+
101
+ class Item
102
+ include ActiveModel::Model
103
+ include ActiveModel::Attributes
104
+ include ActiveModel::Validations
105
+
106
+ attribute :id, :string
107
+ attribute :name, :string
108
+ attribute :price, :integer
109
+ attribute :qty, :integer
110
+
111
+ validates :price, presence: true, numericality: { greater_than: 0 }
112
+ validates :qty, presence: true, numericality: { greater_than: 0 }
113
+ end
114
+
115
+ include ActiveModel::Model
116
+ include ActiveModel::Attributes
117
+ include ActiveModel::Validations
118
+
119
+ attribute :id, :string
120
+ attribute :price, :integer
121
+ attribute :limit, :integer
122
+ attribute :dates
123
+ attribute :items
124
+ attribute :payments
125
+
126
+ validates :id, presence: true
127
+ validates :price, presence: true
128
+
129
+ validate do
130
+ next if dates.valid?
131
+
132
+ dates.errors.messages.each { |attr, msg| errors.add("dates.#{attr}", msg) }
133
+ end
134
+
135
+ validate do
136
+ items.each_with_index do |item, idx|
137
+ next if item.valid?
138
+
139
+ item.errors.messages.each { |attr, msg| errors.add("items.#{idx}.#{attr}", msg) }
140
+ end
141
+ end
142
+
143
+ validate do
144
+ payments.each_with_index do |payment, idx|
145
+ next if payment.valid?
146
+
147
+ payment.errors.messages.each { |attr, msg| errors.add("payments.#{idx}.#{attr}", msg) }
148
+ end
149
+ end
150
+
151
+ validate do
152
+ errors.add(:price, 'is excessive') if price > limit
153
+ end
154
+ end
155
+ end
156
+
157
+ LiteBench = Support::Functional::Contracts::Hash
158
+
159
+ VALID = LiteBench::VALID
160
+ INVALID = LiteBench::INVALID
161
+ CONTEXT = LiteBench::CONTEXT
162
+
163
+ def self.run(n) # rubocop:disable Naming/MethodParameterName, Metrics/AbcSize
164
+ runs = {}
165
+
166
+ runs[:ActiveModel] = proc do |idx|
167
+ ActiveModelBench.call(data(idx), **CONTEXT)
168
+ end
169
+
170
+ runs[:Dry] = proc do |idx|
171
+ DryBench.new(**CONTEXT).call(data(idx))
172
+ end
173
+
174
+ runs[:Lite] = proc do |idx|
175
+ LiteBench.call(
176
+ data(idx),
177
+ Support::Functional::Coordinators::Dry::Flat,
178
+ CONTEXT
179
+ ).to_result
180
+ end
181
+
182
+ runs.to_a.shuffle.each do |key, proc|
183
+ result = ::Benchmark.measure { n.times { |idx| proc.call(idx) } }
184
+ puts "#{key}: #{result}"
185
+ end
186
+ end
187
+
188
+ def self.data(idx)
189
+ (idx % 5).zero? ? INVALID : VALID
190
+ end
191
+ end
192
+ end
193
+ end
194
+ end
195
+ end
196
+
197
+ Lite::Validation::Validator::Benchmark::Comparative.run(1000)
@@ -0,0 +1,107 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'benchmark'
4
+ require 'dry/validation'
5
+ require 'byebug'
6
+
7
+ require_relative '../lib/lite/validation/validator'
8
+ require_relative '../spec/validation/validator/support/functional/coordinators/dry'
9
+ require_relative '../spec/validation/validator/support/shared/predicates/dry'
10
+
11
+ module Lite
12
+ module Validation
13
+ module Validator
14
+ module Benchmark
15
+ module Functional
16
+ module Iteration
17
+ def self.run(n) # rubocop:disable Naming/MethodParameterName, Metrics/AbcSize
18
+ runs = {}
19
+
20
+ runs[:IndirectValidate] = proc do |_idx|
21
+ IndirectIterationValidate.call(validate_data)
22
+ end
23
+
24
+ runs[:DirectValidate] = proc do |_idx|
25
+ DirectIterationValidate.call(validate_data)
26
+ end
27
+
28
+ runs[:DirectSatisfy] = proc do |_idx|
29
+ DirectIterationSatisfy.call(satisfy_data)
30
+ end
31
+
32
+ runs.to_a.shuffle.each do |key, proc|
33
+ result = ::Benchmark.measure { n.times { |idx| proc.call(idx) } }
34
+ puts "#{key}: #{result}"
35
+ end
36
+ end
37
+
38
+ def self.validate_data
39
+ array = 100.times.map do
40
+ rand = rand()
41
+ case rand
42
+ when 11 then nil
43
+ else rand
44
+ end
45
+ end
46
+
47
+ { array: array }
48
+ end
49
+
50
+ def self.satisfy_data
51
+ { array: 100.times.map { rand } }
52
+ end
53
+
54
+ def self.rand
55
+ Random.rand(-1..11)
56
+ end
57
+
58
+ module IndirectIterationValidate
59
+ extend Ruling::Constructors
60
+
61
+ def self.call(data, coordinator: Support::Functional::Coordinators::Dry::Flat)
62
+ Validator
63
+ .instance(data, coordinator)
64
+ .each_at(:array, commit: :array) do |node|
65
+ node
66
+ .validate(commit: true) do |value, _ctx|
67
+ next Refute(:blank) if value.nil?
68
+
69
+ Dispute(:negative) if value.negative?
70
+ end
71
+ end.auto_commit(as: :hash)
72
+ end
73
+ end
74
+
75
+ module DirectIterationValidate
76
+ extend Ruling::Constructors
77
+
78
+ def self.call(data, coordinator: Support::Functional::Coordinators::Dry::Flat)
79
+ Validator
80
+ .instance(data, coordinator)
81
+ .each_at(:array, commit: :array).validate(commit: true) do |value, _ctx|
82
+ next Refute(:blank) if value.nil?
83
+
84
+ Dispute(:negative) if value.negative?
85
+ end.auto_commit(as: :hash)
86
+ end
87
+ end
88
+
89
+ module DirectIterationSatisfy
90
+ extend Ruling::Constructors
91
+
92
+ def self.call(data, coordinator: Support::Functional::Coordinators::Dry::Flat)
93
+ Validator
94
+ .instance(data, coordinator, context: { min: 0, max: 10 })
95
+ .each_at(:array, commit: :array).satisfy(using: :dry, commit: true) do |builder, context|
96
+ builder.call { gteq?(context[:min]) & lteq?(context[:max]) }
97
+ end.auto_commit(as: :array)
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end
105
+ end
106
+
107
+ Lite::Validation::Validator::Benchmark::Functional::Iteration.run(2000)
data/bench/profile.rb ADDED
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'ruby-prof'
4
+ require 'byebug'
5
+
6
+ require_relative '../spec/validation/validator/support/functional/contracts/hash'
7
+ require_relative '../spec/validation/validator/support/functional/coordinators/dry'
8
+ require_relative '../spec/validation/validator/support/shared/predicates/dry'
9
+
10
+ module Lite
11
+ module Validation
12
+ module Validator
13
+ module Benchmark
14
+ module Profile
15
+ LiteProf = Support::Functional::Contracts::Hash
16
+
17
+ VALID = LiteProf::VALID
18
+ INVALID = LiteProf::INVALID
19
+ CONTEXT = LiteProf::CONTEXT
20
+
21
+ def self.run(n) # rubocop:disable Naming/MethodParameterName
22
+ result = RubyProf::Profile.profile do
23
+ n.times do |idx|
24
+ LiteProf.call(
25
+ data(idx),
26
+ Support::Functional::Coordinators::Dry::Flat,
27
+ CONTEXT
28
+ ).to_result
29
+ end
30
+ end
31
+
32
+ printer = RubyProf::GraphPrinter.new(result)
33
+ printer.print($stdout, {})
34
+ end
35
+
36
+ def self.data(idx)
37
+ (idx % 5).zero? ? INVALID : VALID
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+
45
+ Lite::Validation::Validator::Benchmark::Profile.run(1000)
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'dry-monads'
4
+
5
+ module Lite
6
+ module Validation
7
+ module Adapters
8
+ module Interfaces
9
+ module Dry
10
+ def success(value)
11
+ ::Dry::Monads::Result::Success.new(value)
12
+ end
13
+
14
+ def failure(error)
15
+ ::Dry::Monads::Result::Failure.new(error)
16
+ end
17
+
18
+ def some(value)
19
+ ::Dry::Monads::Result::Success.new(value)
20
+ end
21
+
22
+ def none
23
+ ::Dry::Monads::Result::Failure.new(::Dry::Monads::Unit)
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lite
4
+ module Validation
5
+ class Error < StandardError
6
+ class Fatal < Error; end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../abstract'
4
+
5
+ module Lite
6
+ module Validation
7
+ module Result
8
+ module Abstract
9
+ module Disputable
10
+ def dispute(_error)
11
+ raise NotImplementedError, "#{self.class.name}##{__method__} unimplemented"
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lite
4
+ module Validation
5
+ module Result
6
+ module Abstract
7
+ module Failure
8
+ def failure?
9
+ true
10
+ end
11
+
12
+ def to_result(coordinator)
13
+ coordinator.failure(coordinator.build_final_error(self))
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../abstract'
4
+
5
+ module Lite
6
+ module Validation
7
+ module Result
8
+ module Abstract
9
+ module Refutable
10
+ def refute(_error)
11
+ raise NotImplementedError, "#{self.class.name}##{__method__} unimplemented"
12
+ end
13
+
14
+ def refuted?
15
+ raise NotImplementedError, "#{self.class.name}##{__method__} unimplemented"
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lite
4
+ module Validation
5
+ module Result
6
+ module Abstract
7
+ module Success
8
+ def failure?
9
+ false
10
+ end
11
+
12
+ def to_result(coordinator)
13
+ coordinator.success(success)
14
+ end
15
+
16
+ private
17
+
18
+ def success
19
+ raise NotImplementedError, "#{self.class.name}##{__method__} unimplemented"
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'abstract/failure'
4
+ require_relative 'abstract/success'
5
+
6
+ module Lite
7
+ module Validation
8
+ module Result
9
+ module Abstract
10
+ def success?
11
+ !failure?
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'lite/data'
4
+
5
+ require_relative '../structured_error'
6
+
7
+ module Lite
8
+ module Validation
9
+ module StructuredError
10
+ class Record
11
+ include StructuredError
12
+
13
+ Lite::Data.define(self, args: %i[code message data])
14
+
15
+ def self.instance(code, message: nil, data: nil)
16
+ new(code.to_sym, message&.to_s.freeze, data.freeze)
17
+ end
18
+
19
+ def display_message(*)
20
+ message
21
+ end
22
+
23
+ def inspect
24
+ "#<#{self.class.name} '#{message || code}'>"
25
+ end
26
+
27
+ def to_hash
28
+ { code: code }.tap do |hash|
29
+ hash[:message] = message unless message.nil?
30
+ hash[:data] = data unless data.nil?
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lite
4
+ module Validation
5
+ module StructuredError
6
+ def code
7
+ raise NotImplementedError, "#{self.class.name}##{__method__} unimplemented"
8
+ end
9
+
10
+ def message
11
+ nil
12
+ end
13
+
14
+ def display_message(*)
15
+ nil
16
+ end
17
+
18
+ def data
19
+ nil
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../../structured_error/record'
4
+ require_relative '../../coordinator/errors/flat'
5
+
6
+ module Lite
7
+ module Validation
8
+ module Validator
9
+ module Adapters
10
+ module Errors
11
+ module Default
12
+ def self.internal_error(id, message: nil, data: nil)
13
+ structured_error(id, message: message, data: data)
14
+ end
15
+
16
+ def self.structured_error(code, message: nil, data: nil)
17
+ StructuredError::Record.instance(code, message: message, data: data)
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end