smart_schema 0.11.0 → 0.12.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 +4 -4
- metadata +60 -71
- data/.gitignore +0 -12
- data/.rspec +0 -3
- data/.rubocop.yml +0 -20
- data/CHANGELOG.md +0 -68
- data/CODE_OF_CONDUCT.md +0 -74
- data/Gemfile +0 -5
- data/Gemfile.lock +0 -106
- data/LICENSE.txt +0 -21
- data/README.md +0 -236
- data/Rakefile +0 -21
- data/bin/console +0 -8
- data/bin/setup +0 -8
- data/lib/smart_core/schema/checker/reconciler/constructor.rb +0 -60
- data/lib/smart_core/schema/checker/reconciler/matcher/options.rb +0 -33
- data/lib/smart_core/schema/checker/reconciler/matcher/result.rb +0 -87
- data/lib/smart_core/schema/checker/reconciler/matcher/result_finalizer.rb +0 -186
- data/lib/smart_core/schema/checker/reconciler/matcher.rb +0 -62
- data/lib/smart_core/schema/checker/reconciler.rb +0 -106
- data/lib/smart_core/schema/checker/rules/base.rb +0 -110
- data/lib/smart_core/schema/checker/rules/extra_keys/failure.rb +0 -24
- data/lib/smart_core/schema/checker/rules/extra_keys/result.rb +0 -37
- data/lib/smart_core/schema/checker/rules/extra_keys/success.rb +0 -30
- data/lib/smart_core/schema/checker/rules/extra_keys.rb +0 -31
- data/lib/smart_core/schema/checker/rules/optional.rb +0 -25
- data/lib/smart_core/schema/checker/rules/options/empty.rb +0 -43
- data/lib/smart_core/schema/checker/rules/options/filled.rb +0 -49
- data/lib/smart_core/schema/checker/rules/options/type.rb +0 -86
- data/lib/smart_core/schema/checker/rules/options.rb +0 -60
- data/lib/smart_core/schema/checker/rules/required.rb +0 -25
- data/lib/smart_core/schema/checker/rules/requirement/optional.rb +0 -36
- data/lib/smart_core/schema/checker/rules/requirement/required.rb +0 -36
- data/lib/smart_core/schema/checker/rules/requirement/result.rb +0 -95
- data/lib/smart_core/schema/checker/rules/requirement.rb +0 -9
- data/lib/smart_core/schema/checker/rules/result/base.rb +0 -44
- data/lib/smart_core/schema/checker/rules/result/failure.rb +0 -41
- data/lib/smart_core/schema/checker/rules/result/success.rb +0 -15
- data/lib/smart_core/schema/checker/rules/result.rb +0 -9
- data/lib/smart_core/schema/checker/rules/type_aliases.rb +0 -57
- data/lib/smart_core/schema/checker/rules/verifier/result.rb +0 -75
- data/lib/smart_core/schema/checker/rules/verifier.rb +0 -74
- data/lib/smart_core/schema/checker/rules.rb +0 -89
- data/lib/smart_core/schema/checker/verifiable_hash.rb +0 -65
- data/lib/smart_core/schema/checker.rb +0 -106
- data/lib/smart_core/schema/dsl.rb +0 -81
- data/lib/smart_core/schema/errors.rb +0 -13
- data/lib/smart_core/schema/key_control.rb +0 -39
- data/lib/smart_core/schema/result.rb +0 -62
- data/lib/smart_core/schema/version.rb +0 -14
- data/lib/smart_core/schema.rb +0 -52
- data/smart_schema.gemspec +0 -42
data/README.md
DELETED
|
@@ -1,236 +0,0 @@
|
|
|
1
|
-
# SmartCore::Schema · <a target="_blank" href="https://github.com/Cado-Labs"><img src="https://github.com/Cado-Labs/cado-labs-logos/raw/main/cado_labs_badge.svg" alt="Supported by Cado Labs" style="max-width: 100%; height: 20px"></a> · [](https://badge.fury.io/rb/smart_schema)
|
|
2
|
-
|
|
3
|
-
`SmartCore::Schema` is a schema validator for `Hash`-like data structures (`Array`-like - coming soon) in declarative DSL-powered style.
|
|
4
|
-
|
|
5
|
-
Provides convenient and concise DSL to define complex schemas in easiest way and public validation interface to achieve a comfortable work with detailed validation result.
|
|
6
|
-
|
|
7
|
-
Supports nested structures, type validation (via `smart_types`), required- and optional- schema keys, *strict* and *non-strict* schemas, schema value presence validation, schema inheritance (soon), schema extending (soon) and schema composition (soon).
|
|
8
|
-
|
|
9
|
-
Works in predicate style and in OOP/Monadic result object style. Enjoy :)
|
|
10
|
-
|
|
11
|
-
---
|
|
12
|
-
|
|
13
|
-
<p>
|
|
14
|
-
<a href="https://github.com/Cado-Labs">
|
|
15
|
-
<img src="https://github.com/Cado-Labs/cado-labs-logos/blob/main/cado_labs_supporting.svg" alt="Supported by Cado Labs" />
|
|
16
|
-
</a>
|
|
17
|
-
</p>
|
|
18
|
-
|
|
19
|
-
---
|
|
20
|
-
|
|
21
|
-
## Installation
|
|
22
|
-
|
|
23
|
-
```ruby
|
|
24
|
-
gem 'smart_schema'
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
```shell
|
|
28
|
-
bundle install
|
|
29
|
-
# --- or ---
|
|
30
|
-
gem install smart_schema
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
```ruby
|
|
34
|
-
require 'smart_core/schema'
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
---
|
|
38
|
-
|
|
39
|
-
## Synopsis
|
|
40
|
-
|
|
41
|
-
- key requirement: `required` and `optional`;
|
|
42
|
-
- type validation: `type`;
|
|
43
|
-
- `nil` control: `filled`;
|
|
44
|
-
- nested definitions: `do ... end`;
|
|
45
|
-
- supported types: see `smart_types` gem;
|
|
46
|
-
- strict modes and strict behavior: `strict!`, `non_strict!`, `schema(:strict)`, `schema(:non_strict)`;
|
|
47
|
-
- `:strict` is used by default (in first `schema` invokation);
|
|
48
|
-
- you can make non-strict inner schemas inside strict schemas (and vise-versa);
|
|
49
|
-
- inner schemas inherits their's mode from their's nearest outer schema (and can have own mode too);
|
|
50
|
-
|
|
51
|
-
```ruby
|
|
52
|
-
class MySchema < SmartCore::Schema
|
|
53
|
-
# you can mark strict mode in root schema here:
|
|
54
|
-
#
|
|
55
|
-
# non_strict!
|
|
56
|
-
#
|
|
57
|
-
# -- or --
|
|
58
|
-
#
|
|
59
|
-
# strict!
|
|
60
|
-
|
|
61
|
-
schema do # or here with `schema(:strict)` (default in first time) or `schema(:non_strict)`
|
|
62
|
-
required(:key) do
|
|
63
|
-
# inherits `:strict`
|
|
64
|
-
optional(:data).type(:string).filled
|
|
65
|
-
optional(:value).type(:numeric)
|
|
66
|
-
required(:name).type(:string)
|
|
67
|
-
|
|
68
|
-
required(:nested) do
|
|
69
|
-
# inherits `:strict`
|
|
70
|
-
optional(:version).filled
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
optional(:another_nested) do
|
|
74
|
-
non_strict! # marks current nested schema as `:non_strict`
|
|
75
|
-
end
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
required(:another_key).filled
|
|
79
|
-
end
|
|
80
|
-
end
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
```ruby
|
|
84
|
-
# you can open already defined schema and continue schema definitioning:
|
|
85
|
-
|
|
86
|
-
schema do
|
|
87
|
-
required(:third_key).filled.type(:string)
|
|
88
|
-
end
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
```ruby
|
|
92
|
-
# you can redefine strict behavior of already defined schema:
|
|
93
|
-
|
|
94
|
-
schema(:non_strict) do
|
|
95
|
-
# ...
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
# -- or --
|
|
99
|
-
schema do
|
|
100
|
-
non_strict!
|
|
101
|
-
end
|
|
102
|
-
|
|
103
|
-
# -- or --
|
|
104
|
-
non_strict!
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
```ruby
|
|
108
|
-
# you can redefine nested schema behavior:
|
|
109
|
-
|
|
110
|
-
schema do
|
|
111
|
-
optional(:another_nested) do
|
|
112
|
-
strict! # change from :non_strict to :strict
|
|
113
|
-
end
|
|
114
|
-
end
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
```ruby
|
|
118
|
-
MySchema.new.valid?({
|
|
119
|
-
key: {
|
|
120
|
-
data: '5',
|
|
121
|
-
value: 1,
|
|
122
|
-
name: 'D@iVeR'
|
|
123
|
-
nested: {}
|
|
124
|
-
}
|
|
125
|
-
another_key: true
|
|
126
|
-
}) # => true
|
|
127
|
-
|
|
128
|
-
MySchema.new.valid?({
|
|
129
|
-
key: {
|
|
130
|
-
data: nil,
|
|
131
|
-
value: 1,
|
|
132
|
-
name: 'D@iVeR'
|
|
133
|
-
nested: {}
|
|
134
|
-
}
|
|
135
|
-
}) # => false (missing :another_key, key->data is not filled)
|
|
136
|
-
```
|
|
137
|
-
|
|
138
|
-
```ruby
|
|
139
|
-
result = MySchema.new.validate(
|
|
140
|
-
key: { data: nil, value: '1', name: 'D@iVeR' },
|
|
141
|
-
another_key: nil,
|
|
142
|
-
third_key: 'test'
|
|
143
|
-
)
|
|
144
|
-
|
|
145
|
-
# => outputs:
|
|
146
|
-
# #<SmartCore::Schema::Result:0x00007ffcd8926990
|
|
147
|
-
# @errors={"key.data"=>[:non_filled], "key.value"=>[:invalid_type], "key.nested"=>[:required_key_not_found], "another_key"=>[:non_filled], "third_key"=>[:extra_key]},
|
|
148
|
-
# @extra_keys=#<Set: {"third_key"}>,
|
|
149
|
-
# @spread_keys=#<Set: {}>, (coming soon (spread keys of non-strict schemas))
|
|
150
|
-
# @source={:key=>{:data=>nil, :value=>"1", :name=>"D@iVeR"}, :another_key=>nil, :third_key=>"test"}>
|
|
151
|
-
|
|
152
|
-
result.success? # => false
|
|
153
|
-
result.spread_keys # => <Set: {}> (coming soon (spread keys of non-strict schemas))
|
|
154
|
-
result.extra_keys # => <Set: {"third_key"}>
|
|
155
|
-
result.errors # =>
|
|
156
|
-
{
|
|
157
|
-
"key.data"=>[:non_filled],
|
|
158
|
-
"key.value"=>[:invalid_type],
|
|
159
|
-
"key.nested"=>[:required_key_not_found],
|
|
160
|
-
"another_key"=>[:non_filled],
|
|
161
|
-
"third_key"=>[:extra_key]
|
|
162
|
-
}
|
|
163
|
-
```
|
|
164
|
-
|
|
165
|
-
Possible errors:
|
|
166
|
-
- `:non_filled` (existing key has nil value);
|
|
167
|
-
- `:invalid_type` (existing key has invalid type);
|
|
168
|
-
- `:required_key_not_found` (required key does not exist);
|
|
169
|
-
- `:extra_key` (concrete key does not exist in schema);
|
|
170
|
-
|
|
171
|
-
---
|
|
172
|
-
|
|
173
|
-
## Roadmap
|
|
174
|
-
|
|
175
|
-
- **(x.x.x)** - mutable schemas (value convertion during schema checking with returning the new coerced data structure);
|
|
176
|
-
- **(x.x.x)** - public interface for type aliasing (custom type alias registration API);
|
|
177
|
-
- **(x.x.x)** - support for `Array`-like data structures;
|
|
178
|
-
- **(0.x.0)** - an abiltiy to represent the required schema as a string (conviniet way to check what schema is defained internally when we work wtih a dynamic schema definition or in a console);
|
|
179
|
-
- **(0.x.0)** - migrate to `GitHub Actions` (CI);
|
|
180
|
-
- **(0.x.0)** - value-validation layer;
|
|
181
|
-
- **(0.x.0)** - error messages (that are consistent with error codes), with a support for error-code-auto-mappings for error messages via explicit hashes or via file (yaml, json and other formats);
|
|
182
|
-
- **(0.6.0)** - support for `Array`-type in schema definition;
|
|
183
|
-
- **(0.6.0)** - spread keys of non-strict schemas in validation result;
|
|
184
|
-
- **(0.7.0)** - schema inheritance;
|
|
185
|
-
- **(0.7.0)** - schema composition (`required(:key).schema(SchemaClass)`) (`compose_with(AnotherSchema)`);
|
|
186
|
-
- **(0.7.0)** - dependable schema checking (sample: if one key exist (or not) we should check another (or not), and vice verca) (mb `if(:_key_)` rule);
|
|
187
|
-
- **(0.8.0)** - `smart_type-system` integration;
|
|
188
|
-
- **(0.9.0)** - support for another data structures (such as YAML strings, JSON strings, `Struct`, `OpenStruct`s, custom `Object`s and etc);
|
|
189
|
-
- **(0.10.0)** - mixin-based implementation;
|
|
190
|
-
- **(0.x.0)** - think about pattern matching;
|
|
191
|
-
|
|
192
|
-
---
|
|
193
|
-
|
|
194
|
-
## Build
|
|
195
|
-
|
|
196
|
-
- run tests:
|
|
197
|
-
|
|
198
|
-
```shell
|
|
199
|
-
bundle exec rake rspec
|
|
200
|
-
```
|
|
201
|
-
|
|
202
|
-
- run code style checks:
|
|
203
|
-
|
|
204
|
-
```shell
|
|
205
|
-
bundle exec rake rubocop
|
|
206
|
-
```
|
|
207
|
-
|
|
208
|
-
- run code style checks with auto-correction:
|
|
209
|
-
|
|
210
|
-
```shell
|
|
211
|
-
bundle exec rake rubocop -A
|
|
212
|
-
```
|
|
213
|
-
|
|
214
|
-
---
|
|
215
|
-
|
|
216
|
-
## Contributing
|
|
217
|
-
|
|
218
|
-
- Fork it ( https://github.com/smart-rb/smart_schema )
|
|
219
|
-
- Create your feature branch (`git checkout -b feature/my-new-feature`)
|
|
220
|
-
- Commit your changes (`git commit -am '[feature_context] Add some feature'`)
|
|
221
|
-
- Push to the branch (`git push origin feature/my-new-feature`)
|
|
222
|
-
- Create new Pull Request
|
|
223
|
-
|
|
224
|
-
## License
|
|
225
|
-
|
|
226
|
-
Released under MIT License.
|
|
227
|
-
|
|
228
|
-
## Supporting
|
|
229
|
-
|
|
230
|
-
<a href="https://github.com/Cado-Labs">
|
|
231
|
-
<img src="https://github.com/Cado-Labs/cado-labs-logos/blob/main/cado_labs_logo.png" alt="Supported by Cado Labs" />
|
|
232
|
-
</a>
|
|
233
|
-
|
|
234
|
-
## Authors
|
|
235
|
-
|
|
236
|
-
[Rustam Ibragimov](https://github.com/0exp)
|
data/Rakefile
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'bundler/gem_tasks'
|
|
4
|
-
require 'rspec/core/rake_task'
|
|
5
|
-
require 'rubocop'
|
|
6
|
-
require 'rubocop/rake_task'
|
|
7
|
-
require 'rubocop-performance'
|
|
8
|
-
require 'rubocop-rspec'
|
|
9
|
-
require 'rubocop-rake'
|
|
10
|
-
|
|
11
|
-
RuboCop::RakeTask.new(:rubocop) do |t|
|
|
12
|
-
config_path = File.expand_path(File.join('.rubocop.yml'), __dir__)
|
|
13
|
-
t.options = ['--config', config_path]
|
|
14
|
-
t.requires << 'rubocop-rspec'
|
|
15
|
-
t.requires << 'rubocop-performance'
|
|
16
|
-
t.requires << 'rubocop-rake'
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
RSpec::Core::RakeTask.new(:rspec)
|
|
20
|
-
|
|
21
|
-
task default: :rspec
|
data/bin/console
DELETED
data/bin/setup
DELETED
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
# @api private
|
|
4
|
-
# @since 0.1.0
|
|
5
|
-
# @version 0.3.0
|
|
6
|
-
module SmartCore::Schema::Checker::Reconciler::Constructor
|
|
7
|
-
# @return [Hash<String,Boolean>]
|
|
8
|
-
#
|
|
9
|
-
# @api private
|
|
10
|
-
# @since 0.3.0
|
|
11
|
-
STRICT_MODES = { strict: true, 'strict' => true, non_strict: false, 'non_strict' => true }.freeze
|
|
12
|
-
|
|
13
|
-
# @return [Boolean]
|
|
14
|
-
#
|
|
15
|
-
# @pai private
|
|
16
|
-
# @since 0.3.0
|
|
17
|
-
DEFAULT_STRICT_BEHAVIOR = STRICT_MODES[:strict] # NOTE: means `strict by default`
|
|
18
|
-
|
|
19
|
-
class << self
|
|
20
|
-
# @param reconciler [SmartCore::Schema::Checker::Reconciler]
|
|
21
|
-
# @param definitions [Proc]
|
|
22
|
-
# @return [void]
|
|
23
|
-
#
|
|
24
|
-
# @api private
|
|
25
|
-
# @since 0.1.0
|
|
26
|
-
def append_definitions(reconciler, &definitions)
|
|
27
|
-
reconciler.instance_eval(&definitions)
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
# @param reconciler [SmartCore::Schema::Checker::Reconciler]
|
|
31
|
-
# @param strict_mode [NilClass, String, Symbol]
|
|
32
|
-
# @return [void]
|
|
33
|
-
#
|
|
34
|
-
# @api private
|
|
35
|
-
# @since 0.3.0
|
|
36
|
-
def set_strict_mode(reconciler, strict_mode)
|
|
37
|
-
return if strict_mode == nil
|
|
38
|
-
|
|
39
|
-
is_strict = STRICT_MODES.fetch(strict_mode) do
|
|
40
|
-
raise(SmartCore::Schema::ArgumentError, <<~ERROR_MESSAGE)
|
|
41
|
-
Unsupported strict mode "#{strict_mode}".
|
|
42
|
-
SmartCore::Schema supports "strict" and "non_strict" modes only.
|
|
43
|
-
ERROR_MESSAGE
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
reconciler.strict!(is_strict)
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
# @param definitions [Proc, NilClass]
|
|
50
|
-
# @return [SmarCore::Schema::Checker::Reconciler]
|
|
51
|
-
#
|
|
52
|
-
# @api private
|
|
53
|
-
# @since 0.1.0
|
|
54
|
-
def create(&definitions)
|
|
55
|
-
SmartCore::Schema::Checker::Reconciler.new.tap do |reconciler|
|
|
56
|
-
append_definitions(reconciler, &definitions) if block_given?
|
|
57
|
-
end
|
|
58
|
-
end
|
|
59
|
-
end
|
|
60
|
-
end
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
# @api private
|
|
4
|
-
# @since 0.3.0
|
|
5
|
-
class SmartCore::Schema::Checker::Reconciler::Matcher::Options
|
|
6
|
-
class << self
|
|
7
|
-
# @param reconciler [SmartCore::Schema::Checker::Reconciler]
|
|
8
|
-
# @return [SmartCore::Schema::Checker::Reconciler::Matcher::Options]
|
|
9
|
-
#
|
|
10
|
-
# @api private
|
|
11
|
-
# @since 0.3.0
|
|
12
|
-
def build_from(reconciler)
|
|
13
|
-
new(reconciler.__strict?)
|
|
14
|
-
end
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
# @param is_strict_schema [Boolean]
|
|
18
|
-
# @return [void]
|
|
19
|
-
#
|
|
20
|
-
# @api private
|
|
21
|
-
# @since 0.3.0
|
|
22
|
-
def initialize(is_strict_schema)
|
|
23
|
-
@is_strict_schema = is_strict_schema
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
# @return [Boolean]
|
|
27
|
-
#
|
|
28
|
-
# @api private
|
|
29
|
-
# @since 0.3.0
|
|
30
|
-
def strict_schema?
|
|
31
|
-
@is_strict_schema
|
|
32
|
-
end
|
|
33
|
-
end
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
# @api private
|
|
4
|
-
# @since 0.1.0
|
|
5
|
-
# @version 0.8.0
|
|
6
|
-
class SmartCore::Schema::Checker::Reconciler::Matcher::Result
|
|
7
|
-
# @return [Hash<String|Symbol,Any>]
|
|
8
|
-
#
|
|
9
|
-
# @api private
|
|
10
|
-
# @since 0.1.0
|
|
11
|
-
attr_reader :verifiable_hash
|
|
12
|
-
|
|
13
|
-
# @return [SmartCore::Schema::Checker::Rules::Verifier::Result]
|
|
14
|
-
#
|
|
15
|
-
# @api private
|
|
16
|
-
# @since 0.1.0
|
|
17
|
-
attr_reader :contract_keys_results
|
|
18
|
-
|
|
19
|
-
# @return [
|
|
20
|
-
# SmartCore::Schema::Checker::Rules::ExtraKeys::Success,
|
|
21
|
-
# SmartCore::Schema::Checker::Rules::ExtraKeys::Failure
|
|
22
|
-
# ]
|
|
23
|
-
# @api private
|
|
24
|
-
# @since 0.1.0
|
|
25
|
-
attr_reader :extra_keys_results
|
|
26
|
-
|
|
27
|
-
# @param verifiable_hash [SmartCore::Schema::Checker::VerifiableHash]
|
|
28
|
-
# @return [void]
|
|
29
|
-
#
|
|
30
|
-
# @api private
|
|
31
|
-
# @since 0.1.0
|
|
32
|
-
# @version 0.8.0
|
|
33
|
-
def initialize(verifiable_hash)
|
|
34
|
-
@verifiable_hash = verifiable_hash
|
|
35
|
-
@contract_keys_results = []
|
|
36
|
-
@extra_keys_results = []
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
# @param block
|
|
40
|
-
# @yield [result]
|
|
41
|
-
# @yieldparam result [
|
|
42
|
-
# SmartCore::Schema::Checker::Rules::Verifier::Result,
|
|
43
|
-
# SmartCore::Schema::Checker::Rules::ExtraKeys::Success,
|
|
44
|
-
# SmartCore::Schema::Checker::Rules::ExtraKeys::Failure
|
|
45
|
-
# ]
|
|
46
|
-
# @return [void]
|
|
47
|
-
#
|
|
48
|
-
# @api private
|
|
49
|
-
# @since 0.1.0
|
|
50
|
-
# @version 0.8.0
|
|
51
|
-
def each_result(&block)
|
|
52
|
-
contract_keys_results.each(&block)
|
|
53
|
-
extra_keys_results.each(&block)
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
# @param result [SmartCore::Schema::Checker::Rules::Verifier::Result]
|
|
57
|
-
# @return [void]
|
|
58
|
-
#
|
|
59
|
-
# @api private
|
|
60
|
-
# @since 0.1.0
|
|
61
|
-
# @version 0.8.0
|
|
62
|
-
def contract_key_result(result)
|
|
63
|
-
contract_keys_results << result
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
# @param result [
|
|
67
|
-
# SmartCore::Schema::Checker::Rules::ExtraKeys::Success,
|
|
68
|
-
# SmartCore::Schema::Checker::Rules::ExtraKeys::Failure
|
|
69
|
-
# ]
|
|
70
|
-
# @return [void]
|
|
71
|
-
#
|
|
72
|
-
# @api private
|
|
73
|
-
# @since 0.1.0
|
|
74
|
-
# @version 0.8.0
|
|
75
|
-
def extra_keys_result(result)
|
|
76
|
-
extra_keys_results << result
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
# @return [SmartCore::Schema::Result]
|
|
80
|
-
#
|
|
81
|
-
# @api private
|
|
82
|
-
# @since 0.1.0
|
|
83
|
-
# @version 0.8.0
|
|
84
|
-
def complete!
|
|
85
|
-
SmartCore::Schema::Checker::Reconciler::Matcher::ResultFinalizer.finalize(self)
|
|
86
|
-
end
|
|
87
|
-
end
|
|
@@ -1,186 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
# TODO: refactor error data propagating (with Value Object)
|
|
4
|
-
|
|
5
|
-
# @api private
|
|
6
|
-
# @since 0.1.0
|
|
7
|
-
# @version 0.3.0
|
|
8
|
-
module SmartCore::Schema::Checker::Reconciler::Matcher::ResultFinalizer
|
|
9
|
-
# @return [Proc]
|
|
10
|
-
#
|
|
11
|
-
# @api private
|
|
12
|
-
# @since 0.1.0
|
|
13
|
-
ERRORS_CONTAINER_BUILDER = -> { Hash.new { |hash, key| hash[key] = Set.new } }
|
|
14
|
-
|
|
15
|
-
# @return [Proc]
|
|
16
|
-
#
|
|
17
|
-
# @api private
|
|
18
|
-
# @since 0.1.0
|
|
19
|
-
EXTRA_KEYS_CONTAINER_BUILDER = -> { Set.new }
|
|
20
|
-
|
|
21
|
-
# @return [Proc]
|
|
22
|
-
#
|
|
23
|
-
# @api private
|
|
24
|
-
# @since 0.3.0
|
|
25
|
-
SPREAD_KEYS_CONTAINER_BUILDER = -> { Set.new }
|
|
26
|
-
|
|
27
|
-
# @return [Symbol]
|
|
28
|
-
#
|
|
29
|
-
# @api private
|
|
30
|
-
# @since 0.2.0
|
|
31
|
-
EXTRA_KEY_ERROR_CODE = :extra_key
|
|
32
|
-
|
|
33
|
-
class << self
|
|
34
|
-
# @param result [SmartCore::Schema::Checker::Reconciler::Matcher::Result]
|
|
35
|
-
# @return [SmartCore::Schema::Result]
|
|
36
|
-
#
|
|
37
|
-
# @ai privates
|
|
38
|
-
# @since 0.1.0
|
|
39
|
-
# @version 0.3.0
|
|
40
|
-
# rubocop:disable Layout/LineLength
|
|
41
|
-
def finalize(result)
|
|
42
|
-
schema_errors, extra_keys, spread_keys = aggregate_errors(result)
|
|
43
|
-
schema_errors, extra_keys, spread_keys = compile_errors(schema_errors, extra_keys, spread_keys)
|
|
44
|
-
build_final_result(result, schema_errors, extra_keys, spread_keys)
|
|
45
|
-
end
|
|
46
|
-
# rubocop:enable Layout/LineLength
|
|
47
|
-
|
|
48
|
-
private
|
|
49
|
-
|
|
50
|
-
# @param result [SmartCore::Schema::Checker::Reconciler::Matcher::Result]
|
|
51
|
-
# @param schema_errors [Hash<String,Array<Symbol>>]
|
|
52
|
-
# @param extra_keys [Set<String>]
|
|
53
|
-
# @param spread_keys [Set<String>]
|
|
54
|
-
# @return [SmartCore::Schema::Result]
|
|
55
|
-
#
|
|
56
|
-
# @api private
|
|
57
|
-
# @since 0.1.0
|
|
58
|
-
# @version 0.3.0
|
|
59
|
-
def build_final_result(result, schema_errors, extra_keys, spread_keys)
|
|
60
|
-
SmartCore::Schema::Result.new(
|
|
61
|
-
result.verifiable_hash.source,
|
|
62
|
-
schema_errors.freeze,
|
|
63
|
-
extra_keys.freeze,
|
|
64
|
-
SPREAD_KEYS_CONTAINER_BUILDER.call.freeze # TODO: spread_keys.freeze
|
|
65
|
-
)
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
# @param result [SmartCore::Schema::Checker::Reconciler::Matcher::Result]
|
|
69
|
-
# @return [Array<Hash<String,Any>,Set<String>>]
|
|
70
|
-
#
|
|
71
|
-
# @api private
|
|
72
|
-
# @since 0.1.0
|
|
73
|
-
def aggregate_errors(result)
|
|
74
|
-
schema_errors = ERRORS_CONTAINER_BUILDER.call
|
|
75
|
-
extra_keys = EXTRA_KEYS_CONTAINER_BUILDER.call
|
|
76
|
-
spread_keys = SPREAD_KEYS_CONTAINER_BUILDER.call
|
|
77
|
-
|
|
78
|
-
result.each_result do |concrete_result|
|
|
79
|
-
case concrete_result
|
|
80
|
-
when SmartCore::Schema::Checker::Rules::Verifier::Result
|
|
81
|
-
aggregate_verifier_errors(concrete_result, schema_errors)
|
|
82
|
-
when SmartCore::Schema::Checker::Rules::ExtraKeys::Failure
|
|
83
|
-
aggregate_extra_keys_errors(concrete_result, extra_keys)
|
|
84
|
-
when SmartCore::Schema::Checker::Rules::ExtraKeys::Success
|
|
85
|
-
aggregate_spread_keys_notice(concrete_result, spread_keys)
|
|
86
|
-
end
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
[schema_errors, extra_keys, spread_keys]
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
# @param result [SmartCore::Schema::Checker::Rules::Verifier::Result]
|
|
93
|
-
# @param errors [Hash<String,Array<String>|Hash<String,Hash>>]
|
|
94
|
-
# @return [void]
|
|
95
|
-
#
|
|
96
|
-
# @api private
|
|
97
|
-
# @since 0.1.0
|
|
98
|
-
def aggregate_verifier_errors(result, errors)
|
|
99
|
-
result.each_result do |concrete_result|
|
|
100
|
-
case concrete_result
|
|
101
|
-
when SmartCore::Schema::Checker::Reconciler::Matcher::Result
|
|
102
|
-
sub_schema_errors, sub_extra_keys = aggregate_errors(concrete_result)
|
|
103
|
-
errors[result.key] << [sub_schema_errors, sub_extra_keys]
|
|
104
|
-
when SmartCore::Schema::Checker::Rules::Requirement::Result
|
|
105
|
-
errors[concrete_result.key] << concrete_result.error if concrete_result.failure?
|
|
106
|
-
when SmartCore::Schema::Checker::Rules::Result::Failure
|
|
107
|
-
errors[concrete_result.key] << concrete_result.error
|
|
108
|
-
end
|
|
109
|
-
end
|
|
110
|
-
end
|
|
111
|
-
|
|
112
|
-
# @param result [SmartCore::Schema::Checker::Rules::ExtraKeys::Failure]
|
|
113
|
-
# @param extra_keys [Set<String>]
|
|
114
|
-
# @return [void]
|
|
115
|
-
#
|
|
116
|
-
# @api private
|
|
117
|
-
# @since 0.1.0
|
|
118
|
-
def aggregate_extra_keys_errors(result, extra_keys)
|
|
119
|
-
extra_keys.merge(result.extra_keys)
|
|
120
|
-
end
|
|
121
|
-
|
|
122
|
-
# @param result [SmartCore::Schema::Checker::Rules::ExtraKeys::Success]
|
|
123
|
-
# @param spread_keys [Set<String>]
|
|
124
|
-
# @return [void]
|
|
125
|
-
#
|
|
126
|
-
# @api private
|
|
127
|
-
# @since 0.3.0
|
|
128
|
-
def aggregate_spread_keys_notice(result, spread_keys)
|
|
129
|
-
spread_keys.merge(result.spread_keys)
|
|
130
|
-
end
|
|
131
|
-
|
|
132
|
-
# @param errors [Hash]
|
|
133
|
-
# @param extra_keys [Set]
|
|
134
|
-
# @param spread_keys [Set]
|
|
135
|
-
# @param initial_error_key [NilClass, String]
|
|
136
|
-
# @return [Array<Hash<String,Set<Symbol>>,Set<String>]
|
|
137
|
-
#
|
|
138
|
-
# @api private
|
|
139
|
-
# @since 0.1.0
|
|
140
|
-
# @version 0.3.0
|
|
141
|
-
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength
|
|
142
|
-
def compile_errors(errors, extra_keys, spread_keys, initial_error_key = nil)
|
|
143
|
-
compiled_errors = ERRORS_CONTAINER_BUILDER.call
|
|
144
|
-
compiled_extra_keys = EXTRA_KEYS_CONTAINER_BUILDER.call
|
|
145
|
-
compiled_spread_keys = SPREAD_KEYS_CONTAINER_BUILDER.call
|
|
146
|
-
|
|
147
|
-
compiled_extra_keys.merge(extra_keys).map! do |key|
|
|
148
|
-
# dot-notated nested keys
|
|
149
|
-
initial_error_key ? "#{initial_error_key}.#{key}" : key
|
|
150
|
-
end
|
|
151
|
-
|
|
152
|
-
compiled_spread_keys.merge(spread_keys).map! do |key|
|
|
153
|
-
# dot-notated nested keys
|
|
154
|
-
initial_error_key ? "#{initial_error_key}.#{key}" : key
|
|
155
|
-
end
|
|
156
|
-
|
|
157
|
-
errors.each_pair do |key, error_set|
|
|
158
|
-
# dot-notated nested key
|
|
159
|
-
compiled_key = initial_error_key ? "#{initial_error_key}.#{key}" : key
|
|
160
|
-
|
|
161
|
-
error_set.each do |error|
|
|
162
|
-
case error
|
|
163
|
-
when Symbol # error code
|
|
164
|
-
compiled_errors[compiled_key] << error
|
|
165
|
-
when Array # nested errors
|
|
166
|
-
sub_errors, sub_extra_keys = error
|
|
167
|
-
sub_spread_keys = SPREAD_KEYS_CONTAINER_BUILDER.call
|
|
168
|
-
compiled_sub_errors, compiled_sub_extra_keys, compiled_sub_spread_keys = compile_errors(
|
|
169
|
-
sub_errors, sub_extra_keys, sub_spread_keys, compiled_key
|
|
170
|
-
)
|
|
171
|
-
compiled_errors.merge!(compiled_sub_errors)
|
|
172
|
-
compiled_extra_keys.merge(compiled_sub_extra_keys)
|
|
173
|
-
compiled_spread_keys.merge(compiled_sub_spread_keys)
|
|
174
|
-
end
|
|
175
|
-
end
|
|
176
|
-
end
|
|
177
|
-
|
|
178
|
-
compiled_extra_keys.each do |compiled_extra_key|
|
|
179
|
-
compiled_errors[compiled_extra_key] << EXTRA_KEY_ERROR_CODE
|
|
180
|
-
end
|
|
181
|
-
|
|
182
|
-
[compiled_errors, compiled_extra_keys, compiled_spread_keys]
|
|
183
|
-
end
|
|
184
|
-
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength
|
|
185
|
-
end
|
|
186
|
-
end
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
# @api private
|
|
4
|
-
# @since 0.1.0
|
|
5
|
-
# @version 0.3.0
|
|
6
|
-
module SmartCore::Schema::Checker::Reconciler::Matcher
|
|
7
|
-
require_relative 'matcher/options'
|
|
8
|
-
require_relative 'matcher/result'
|
|
9
|
-
require_relative 'matcher/result_finalizer'
|
|
10
|
-
|
|
11
|
-
class << self
|
|
12
|
-
# @param reconciler [SmartCore::Schema::Checker::Reconciler]
|
|
13
|
-
# @param verifiable_hash [SmartCore::Schema::Checker::VerifiableHash]
|
|
14
|
-
# @return [SmartCore::Schema::Checker::Reconciler::Matcher::Result]
|
|
15
|
-
#
|
|
16
|
-
# @api private
|
|
17
|
-
# @since 0.1.0
|
|
18
|
-
# @version 0.3.0
|
|
19
|
-
def match(reconciler, verifiable_hash)
|
|
20
|
-
matcher_options = Options.build_from(reconciler)
|
|
21
|
-
|
|
22
|
-
Result.new(verifiable_hash).tap do |result|
|
|
23
|
-
match_for_contract_keys(reconciler, matcher_options, verifiable_hash, result)
|
|
24
|
-
match_for_extra_keys(reconciler, matcher_options, verifiable_hash, result)
|
|
25
|
-
end
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
private
|
|
29
|
-
|
|
30
|
-
# @param reconciler [SmartCore::Schema::Checker::Reconciler]
|
|
31
|
-
# @param matcher_options [SmartCore::Schema::Checker::Reconciler::Matcher::Options]
|
|
32
|
-
# @param verifiable_hash [SmartCore::Schema::Checker::VerifiableHash]
|
|
33
|
-
# @param result [SmartCore::Schema::Checker::Reconciler::Matcher::Result]
|
|
34
|
-
# @return [void]
|
|
35
|
-
#
|
|
36
|
-
# @api private
|
|
37
|
-
# @since 0.1.0
|
|
38
|
-
# @version 0.3.0
|
|
39
|
-
def match_for_contract_keys(reconciler, matcher_options, verifiable_hash, result)
|
|
40
|
-
reconciler.__contract_rules.each_rule do |rule|
|
|
41
|
-
verification_result = rule.__verify!(verifiable_hash, matcher_options)
|
|
42
|
-
result.contract_key_result(verification_result)
|
|
43
|
-
end
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
# @param reconciler [SmartCore::Schema::Checker::Reconciler]
|
|
47
|
-
# @param matcher_options [SmartCore::Schema::Checker::Reconciler::Matcher::Options]
|
|
48
|
-
# @param verifiable_hash [SmartCore::Schema::Checker::VerifiableHash]
|
|
49
|
-
# @param result [SmartCore::Schema::Checker::Reconciler::Matcher::Result]
|
|
50
|
-
# @return [void]
|
|
51
|
-
#
|
|
52
|
-
# @api private
|
|
53
|
-
# @since 0.1.0
|
|
54
|
-
# @version 0.3.0
|
|
55
|
-
def match_for_extra_keys(reconciler, matcher_options, verifiable_hash, result)
|
|
56
|
-
verification_result = reconciler.__extra_keys_contract.__verify!(
|
|
57
|
-
verifiable_hash, reconciler.__contract_rules, matcher_options
|
|
58
|
-
)
|
|
59
|
-
result.extra_keys_result(verification_result)
|
|
60
|
-
end
|
|
61
|
-
end
|
|
62
|
-
end
|