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,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)
|
data/bench/functional.rb
ADDED
|
@@ -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,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,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
|