json_skooma 0.1.0 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +25 -1
- data/README.md +39 -0
- data/data/draft-2019-09/meta/applicator.json +0 -3
- data/data/draft-2019-09/meta/content.json +0 -3
- data/data/draft-2019-09/meta/core.json +0 -3
- data/data/draft-2019-09/meta/format.json +0 -3
- data/data/draft-2019-09/meta/hyper-schema.json +0 -3
- data/data/draft-2019-09/meta/meta-data.json +0 -3
- data/data/draft-2019-09/meta/validation.json +0 -3
- data/data/draft-2020-12/meta/applicator.json +0 -3
- data/data/draft-2020-12/meta/content.json +0 -3
- data/data/draft-2020-12/meta/core.json +0 -3
- data/data/draft-2020-12/meta/format-annotation.json +0 -3
- data/data/draft-2020-12/meta/format-assertion.json +0 -3
- data/data/draft-2020-12/meta/hyper-schema.json +0 -3
- data/data/draft-2020-12/meta/meta-data.json +0 -3
- data/data/draft-2020-12/meta/unevaluated.json +0 -3
- data/data/draft-2020-12/meta/validation.json +0 -3
- data/lib/json_skooma/dialects/draft201909.rb +1 -1
- data/lib/json_skooma/formatters.rb +7 -5
- data/lib/json_skooma/inflector.rb +1 -1
- data/lib/json_skooma/json_node.rb +22 -18
- data/lib/json_skooma/json_pointer.rb +11 -7
- data/lib/json_skooma/json_schema.rb +28 -17
- data/lib/json_skooma/keywords/applicator/additional_properties.rb +3 -2
- data/lib/json_skooma/keywords/applicator/all_of.rb +1 -1
- data/lib/json_skooma/keywords/applicator/pattern_properties.rb +1 -1
- data/lib/json_skooma/keywords/applicator/prefix_items.rb +1 -1
- data/lib/json_skooma/keywords/applicator/properties.rb +1 -1
- data/lib/json_skooma/keywords/applicator/property_names.rb +1 -1
- data/lib/json_skooma/keywords/core/ref.rb +1 -16
- data/lib/json_skooma/keywords/draft_2019_09/items.rb +1 -1
- data/lib/json_skooma/keywords/draft_2019_09/unevaluated_items.rb +6 -10
- data/lib/json_skooma/keywords/draft_2019_09/unevaluated_properties.rb +45 -0
- data/lib/json_skooma/keywords/unevaluated/unevaluated_items.rb +8 -11
- data/lib/json_skooma/keywords/unevaluated/unevaluated_properties.rb +6 -4
- data/lib/json_skooma/keywords/validation/const.rb +1 -1
- data/lib/json_skooma/keywords/validation/enum.rb +1 -1
- data/lib/json_skooma/keywords/validation/minimum.rb +1 -1
- data/lib/json_skooma/keywords/validation/required.rb +2 -3
- data/lib/json_skooma/metaschema.rb +1 -1
- data/lib/json_skooma/result.rb +71 -33
- data/lib/json_skooma/validators/idn_hostname.rb +2 -1
- data/lib/json_skooma/validators/ipv4.rb +4 -7
- data/lib/json_skooma/validators/ipv6.rb +8 -6
- data/lib/json_skooma/validators/iri.rb +1 -1
- data/lib/json_skooma/validators/uri.rb +2 -7
- data/lib/json_skooma/version.rb +1 -1
- data/lib/json_skooma.rb +1 -1
- metadata +6 -6
- data/lib/json_skooma/memoizable.rb +0 -21
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9da78d5df937e93b851e37daf72770aeb62c61a09922232a2dc308533a4c5e36
|
4
|
+
data.tar.gz: 13759edb9c18994d8f315f740b37a5e32c4935415c0262292f77f6f52e648a30
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b5b8b57d54a71b2c75f85c4f4964757cce15acedbbc49d967ebcea2447a17dfd0acbd36441aafb647f4e744ae91b78e84917ff0a7964b584a157602797210655
|
7
|
+
data.tar.gz: 8435cc06b0e079f1980797b0b2cbf3a7d635bb78bcbab8431f7c4408b54e871ee2dd79bd37bf948653f5d9c1f87626618135894e54fef24135e162aca046f7e3
|
data/CHANGELOG.md
CHANGED
@@ -7,6 +7,28 @@ and this project adheres to [Semantic Versioning].
|
|
7
7
|
|
8
8
|
## [Unreleased]
|
9
9
|
|
10
|
+
## [0.2.1] - 2023-12-03
|
11
|
+
|
12
|
+
### Fixed
|
13
|
+
|
14
|
+
- Make `unevaluated*` keyword respect reference keywords. ([@skryukov])
|
15
|
+
- Fix `:basic` output. ([@skryukov])
|
16
|
+
|
17
|
+
## [0.2.0] - 2023-10-23
|
18
|
+
|
19
|
+
### Added
|
20
|
+
|
21
|
+
- Add JSON Schema evaluation against a reference. ([@skryukov])
|
22
|
+
|
23
|
+
### Changed
|
24
|
+
|
25
|
+
- Optimized JSON Schema evaluation. ([@skryukov])
|
26
|
+
|
27
|
+
### Fixed
|
28
|
+
|
29
|
+
- Fix compatibility issues for Ruby < 3.1 and JRuby. ([@skryukov])
|
30
|
+
- Fix Zeitwerk eager loading. ([@skryukov])
|
31
|
+
|
10
32
|
## [0.1.0] - 2023-09-27
|
11
33
|
|
12
34
|
### Added
|
@@ -15,7 +37,9 @@ and this project adheres to [Semantic Versioning].
|
|
15
37
|
|
16
38
|
[@skryukov]: https://github.com/skryukov
|
17
39
|
|
18
|
-
[Unreleased]: https://github.com/skryukov/json_skooma/compare/v0.1
|
40
|
+
[Unreleased]: https://github.com/skryukov/json_skooma/compare/v0.2.1...HEAD
|
41
|
+
[0.2.1]: https://github.com/skryukov/json_skooma/compare/v0.2.0...v0.2.1
|
42
|
+
[0.2.0]: https://github.com/skryukov/json_skooma/compare/v0.1.0...v0.2.0
|
19
43
|
[0.1.0]: https://github.com/skryukov/json_skooma/commits/v0.1.0
|
20
44
|
|
21
45
|
[Keep a Changelog]: https://keepachangelog.com/en/1.0.0/
|
data/README.md
CHANGED
@@ -3,6 +3,8 @@
|
|
3
3
|
[![Gem Version](https://badge.fury.io/rb/json_skooma.svg)](https://rubygems.org/gems/json_skooma)
|
4
4
|
[![Ruby](https://github.com/skryukov/json_skooma/actions/workflows/main.yml/badge.svg)](https://github.com/skryukov/json_skooma/actions/workflows/main.yml)
|
5
5
|
|
6
|
+
<img align="right" height="150" width="150" title="JSONSkooma logo" src="./assets/logo.svg">
|
7
|
+
|
6
8
|
JSONSkooma is a Ruby library for validating JSONs against JSON Schemas.
|
7
9
|
|
8
10
|
### Features
|
@@ -78,6 +80,43 @@ result.output(:basic)
|
|
78
80
|
# "The instance value \"Human\" must be equal to one of the elements in the defined enumeration: [\"Nord\", \"Khajiit\", \"Argonian\", \"Breton\", \"Redguard\", \"Dunmer\", \"Altmer\", \"Bosmer\", \"Orc\", \"Imperial\"]"}]}
|
79
81
|
```
|
80
82
|
|
83
|
+
### Evaluating against a reference
|
84
|
+
|
85
|
+
```ruby
|
86
|
+
require "json_skooma"
|
87
|
+
|
88
|
+
# Create a registry to store schemas, vocabularies, dialects, etc.
|
89
|
+
JSONSkooma.create_registry("2020-12", assert_formats: true)
|
90
|
+
|
91
|
+
# Load a schema
|
92
|
+
schema_hash = {
|
93
|
+
"$schema" => "https://json-schema.org/draft/2020-12/schema",
|
94
|
+
"$defs" => {
|
95
|
+
"Foo": {
|
96
|
+
"type" => "object",
|
97
|
+
"properties" => {
|
98
|
+
"foo" => {"enum" => ["baz"]}
|
99
|
+
},
|
100
|
+
}
|
101
|
+
}
|
102
|
+
}
|
103
|
+
|
104
|
+
schema = JSONSkooma::JSONSchema.new(schema_hash)
|
105
|
+
|
106
|
+
result = schema.evaluate({foo: "bar"}, ref: "#/$defs/Foo")
|
107
|
+
|
108
|
+
result.valid? # => false
|
109
|
+
|
110
|
+
result.output(:basic)
|
111
|
+
# {"valid"=>false,
|
112
|
+
# "errors"=>
|
113
|
+
# [{"instanceLocation"=>"", "keywordLocation"=>"/properties", "absoluteKeywordLocation"=>"urn:uuid:cb8fb0a0-ce16-416f-b5ba-2a6531992be9#/$defs/Foo/properties", "error"=>"Properties [\"foo\"] are invalid"},
|
114
|
+
# {"instanceLocation"=>"/foo",
|
115
|
+
# "keywordLocation"=>"/properties/foo/enum",
|
116
|
+
# "absoluteKeywordLocation"=>"urn:uuid:cb8fb0a0-ce16-416f-b5ba-2a6531992be9#/$defs/Foo/properties/foo/enum",
|
117
|
+
# "error"=>"The instance value \"bar\" must be equal to one of the elements in the defined enumeration: [\"baz\"]"}]}
|
118
|
+
```
|
119
|
+
|
81
120
|
## Alternatives
|
82
121
|
|
83
122
|
- [json_schemer](https://github.com/davishmcclurg/json_schemer) – Draft 4, 6, 7, 2019-09 and 2020-12 compliant
|
@@ -1,9 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"$schema": "https://json-schema.org/draft/2019-09/schema",
|
3
3
|
"$id": "https://json-schema.org/draft/2019-09/meta/applicator",
|
4
|
-
"$vocabulary": {
|
5
|
-
"https://json-schema.org/draft/2019-09/vocab/applicator": true
|
6
|
-
},
|
7
4
|
"$recursiveAnchor": true,
|
8
5
|
|
9
6
|
"title": "Applicator vocabulary meta-schema",
|
@@ -1,9 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"$schema": "https://json-schema.org/draft/2019-09/schema",
|
3
3
|
"$id": "https://json-schema.org/draft/2019-09/meta/content",
|
4
|
-
"$vocabulary": {
|
5
|
-
"https://json-schema.org/draft/2019-09/vocab/content": true
|
6
|
-
},
|
7
4
|
"$recursiveAnchor": true,
|
8
5
|
|
9
6
|
"title": "Content vocabulary meta-schema",
|
@@ -1,9 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"$schema": "https://json-schema.org/draft/2019-09/schema",
|
3
3
|
"$id": "https://json-schema.org/draft/2019-09/meta/core",
|
4
|
-
"$vocabulary": {
|
5
|
-
"https://json-schema.org/draft/2019-09/vocab/core": true
|
6
|
-
},
|
7
4
|
"$recursiveAnchor": true,
|
8
5
|
|
9
6
|
"title": "Core vocabulary meta-schema",
|
@@ -1,9 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"$schema": "https://json-schema.org/draft/2019-09/schema",
|
3
3
|
"$id": "https://json-schema.org/draft/2019-09/meta/format",
|
4
|
-
"$vocabulary": {
|
5
|
-
"https://json-schema.org/draft/2019-09/vocab/format": true
|
6
|
-
},
|
7
4
|
"$recursiveAnchor": true,
|
8
5
|
|
9
6
|
"title": "Format vocabulary meta-schema",
|
@@ -1,9 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"$schema": "https://json-schema.org/draft/2019-09/hyper-schema",
|
3
3
|
"$id": "https://json-schema.org/draft/2019-09/meta/hyper-schema",
|
4
|
-
"$vocabulary": {
|
5
|
-
"https://json-schema.org/draft/2019-09/vocab/hyper-schema": true
|
6
|
-
},
|
7
4
|
"$recursiveAnchor": true,
|
8
5
|
|
9
6
|
"title": "JSON Hyper-Schema Vocabulary Schema",
|
@@ -1,9 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"$schema": "https://json-schema.org/draft/2019-09/schema",
|
3
3
|
"$id": "https://json-schema.org/draft/2019-09/meta/meta-data",
|
4
|
-
"$vocabulary": {
|
5
|
-
"https://json-schema.org/draft/2019-09/vocab/meta-data": true
|
6
|
-
},
|
7
4
|
"$recursiveAnchor": true,
|
8
5
|
|
9
6
|
"title": "Meta-data vocabulary meta-schema",
|
@@ -1,9 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"$schema": "https://json-schema.org/draft/2019-09/schema",
|
3
3
|
"$id": "https://json-schema.org/draft/2019-09/meta/validation",
|
4
|
-
"$vocabulary": {
|
5
|
-
"https://json-schema.org/draft/2019-09/vocab/validation": true
|
6
|
-
},
|
7
4
|
"$recursiveAnchor": true,
|
8
5
|
|
9
6
|
"title": "Validation vocabulary meta-schema",
|
@@ -1,9 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
3
3
|
"$id": "https://json-schema.org/draft/2020-12/meta/applicator",
|
4
|
-
"$vocabulary": {
|
5
|
-
"https://json-schema.org/draft/2020-12/vocab/applicator": true
|
6
|
-
},
|
7
4
|
"$dynamicAnchor": "meta",
|
8
5
|
|
9
6
|
"title": "Applicator vocabulary meta-schema",
|
@@ -1,9 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
3
3
|
"$id": "https://json-schema.org/draft/2020-12/meta/content",
|
4
|
-
"$vocabulary": {
|
5
|
-
"https://json-schema.org/draft/2020-12/vocab/content": true
|
6
|
-
},
|
7
4
|
"$dynamicAnchor": "meta",
|
8
5
|
|
9
6
|
"title": "Content vocabulary meta-schema",
|
@@ -1,9 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
3
3
|
"$id": "https://json-schema.org/draft/2020-12/meta/core",
|
4
|
-
"$vocabulary": {
|
5
|
-
"https://json-schema.org/draft/2020-12/vocab/core": true
|
6
|
-
},
|
7
4
|
"$dynamicAnchor": "meta",
|
8
5
|
|
9
6
|
"title": "Core vocabulary meta-schema",
|
@@ -1,9 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
3
3
|
"$id": "https://json-schema.org/draft/2020-12/meta/format-annotation",
|
4
|
-
"$vocabulary": {
|
5
|
-
"https://json-schema.org/draft/2020-12/vocab/format-annotation": true
|
6
|
-
},
|
7
4
|
"$dynamicAnchor": "meta",
|
8
5
|
|
9
6
|
"title": "Format vocabulary meta-schema for annotation results",
|
@@ -1,9 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
3
3
|
"$id": "https://json-schema.org/draft/2020-12/meta/format-assertion",
|
4
|
-
"$vocabulary": {
|
5
|
-
"https://json-schema.org/draft/2020-12/vocab/format-assertion": true
|
6
|
-
},
|
7
4
|
"$dynamicAnchor": "meta",
|
8
5
|
|
9
6
|
"title": "Format vocabulary meta-schema for assertion results",
|
@@ -1,9 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/hyper-schema",
|
3
3
|
"$id": "https://json-schema.org/draft/2020-12/meta/hyper-schema",
|
4
|
-
"$vocabulary": {
|
5
|
-
"https://json-schema.org/draft/2019-09/vocab/hyper-schema": true
|
6
|
-
},
|
7
4
|
"$dynamicAnchor": "meta",
|
8
5
|
|
9
6
|
"title": "JSON Hyper-Schema Vocabulary Schema",
|
@@ -1,9 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
3
3
|
"$id": "https://json-schema.org/draft/2020-12/meta/meta-data",
|
4
|
-
"$vocabulary": {
|
5
|
-
"https://json-schema.org/draft/2020-12/vocab/meta-data": true
|
6
|
-
},
|
7
4
|
"$dynamicAnchor": "meta",
|
8
5
|
|
9
6
|
"title": "Meta-data vocabulary meta-schema",
|
@@ -1,9 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
3
3
|
"$id": "https://json-schema.org/draft/2020-12/meta/unevaluated",
|
4
|
-
"$vocabulary": {
|
5
|
-
"https://json-schema.org/draft/2020-12/vocab/unevaluated": true
|
6
|
-
},
|
7
4
|
"$dynamicAnchor": "meta",
|
8
5
|
|
9
6
|
"title": "Unevaluated applicator vocabulary meta-schema",
|
@@ -1,9 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
3
3
|
"$id": "https://json-schema.org/draft/2020-12/meta/validation",
|
4
|
-
"$vocabulary": {
|
5
|
-
"https://json-schema.org/draft/2020-12/vocab/validation": true
|
6
|
-
},
|
7
4
|
"$dynamicAnchor": "meta",
|
8
5
|
|
9
6
|
"title": "Validation vocabulary meta-schema",
|
@@ -36,11 +36,11 @@ module JSONSkooma
|
|
36
36
|
Keywords::Draft201909::Items,
|
37
37
|
Keywords::Draft201909::AdditionalItems,
|
38
38
|
Keywords::Draft201909::UnevaluatedItems,
|
39
|
+
Keywords::Draft201909::UnevaluatedProperties,
|
39
40
|
Keywords::Applicator::Contains,
|
40
41
|
Keywords::Applicator::Properties,
|
41
42
|
Keywords::Applicator::PatternProperties,
|
42
43
|
Keywords::Applicator::AdditionalProperties,
|
43
|
-
Keywords::Unevaluated::UnevaluatedProperties,
|
44
44
|
Keywords::Applicator::PropertyNames
|
45
45
|
)
|
46
46
|
|
@@ -43,7 +43,7 @@ module JSONSkooma
|
|
43
43
|
key = valid ? "annotation" : "error"
|
44
44
|
result << node_data(node, key) if node.public_send(key)
|
45
45
|
|
46
|
-
node.
|
46
|
+
node.each_children do |child|
|
47
47
|
collect_nodes(child, valid, result)
|
48
48
|
end
|
49
49
|
|
@@ -83,8 +83,9 @@ module JSONSkooma
|
|
83
83
|
child_key = valid ? "annotations" : "errors"
|
84
84
|
msg_key = valid ? "annotation" : "error"
|
85
85
|
|
86
|
-
child_data =
|
87
|
-
|
86
|
+
child_data = []
|
87
|
+
node.each_children do |child|
|
88
|
+
child_data << node_data(child, valid) if child.valid? == valid
|
88
89
|
end
|
89
90
|
|
90
91
|
if first || child_data.length > 1
|
@@ -121,8 +122,9 @@ module JSONSkooma
|
|
121
122
|
data[msg_key] = node.public_send(msg_key) if node.public_send(msg_key)
|
122
123
|
|
123
124
|
child_key = valid ? "annotations" : "errors"
|
124
|
-
child_data =
|
125
|
-
|
125
|
+
child_data = []
|
126
|
+
node.each_children do |child|
|
127
|
+
child_data << node_data(child)
|
126
128
|
end
|
127
129
|
data[child_key] = child_data if child_data.length > 0
|
128
130
|
|
@@ -4,14 +4,11 @@ require "delegate"
|
|
4
4
|
|
5
5
|
module JSONSkooma
|
6
6
|
class JSONNode < SimpleDelegator
|
7
|
-
|
8
|
-
|
9
|
-
attr_reader :parent, :root, :key, :type
|
7
|
+
attr_reader :parent, :key, :type
|
10
8
|
|
11
9
|
def initialize(value, key: nil, parent: nil, item_class: JSONNode, **item_params)
|
12
10
|
@key = key
|
13
11
|
@parent = parent
|
14
|
-
@root = parent&.root || self
|
15
12
|
@item_class = item_class
|
16
13
|
@item_params = item_params
|
17
14
|
@type, data = parse_value(value)
|
@@ -19,6 +16,10 @@ module JSONSkooma
|
|
19
16
|
super(data)
|
20
17
|
end
|
21
18
|
|
19
|
+
def root
|
20
|
+
@root ||= parent&.root || self
|
21
|
+
end
|
22
|
+
|
22
23
|
def [](key)
|
23
24
|
case type
|
24
25
|
when "array"
|
@@ -31,23 +32,24 @@ module JSONSkooma
|
|
31
32
|
end
|
32
33
|
|
33
34
|
def value
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
35
|
+
return @value if instance_variable_defined?(:@value)
|
36
|
+
|
37
|
+
@value =
|
38
|
+
case type
|
39
|
+
when "array"
|
40
|
+
map(&:value)
|
41
|
+
when "object"
|
42
|
+
transform_values(&:value)
|
43
|
+
else
|
44
|
+
__getobj__
|
45
|
+
end
|
42
46
|
end
|
43
|
-
memoize :value
|
44
47
|
|
45
48
|
def path
|
46
|
-
|
47
|
-
|
48
|
-
JSONPointer.new(
|
49
|
+
return @path if instance_variable_defined?(:@path)
|
50
|
+
|
51
|
+
@path = @parent.nil? ? JSONPointer.new([]) : @parent.path.child(@key)
|
49
52
|
end
|
50
|
-
memoize :path
|
51
53
|
|
52
54
|
def ==(other)
|
53
55
|
return super(other.__getobj__) if other.is_a?(self.class)
|
@@ -94,7 +96,9 @@ module JSONSkooma
|
|
94
96
|
end
|
95
97
|
|
96
98
|
def map_object_value(value)
|
97
|
-
value.
|
99
|
+
value.each_with_object({}) do |(k, v), h|
|
100
|
+
h[k.to_s] = @item_class.new(v, key: k.to_s, parent: self, **@item_params)
|
101
|
+
end
|
98
102
|
end
|
99
103
|
end
|
100
104
|
end
|
@@ -5,7 +5,6 @@ require "cgi"
|
|
5
5
|
|
6
6
|
module JSONSkooma
|
7
7
|
class JSONPointer < Hana::Pointer
|
8
|
-
extend Memoizable
|
9
8
|
ESC_REGEX = /[\/^~]/.freeze
|
10
9
|
ESC2 = {"^" => "^^", "~" => "~0", "/" => "~1"}.freeze
|
11
10
|
ESCAPE_REGEX = /([^ a-zA-Z0-9_.\-~\/!$&'()*+,;=]+)/.freeze
|
@@ -47,14 +46,19 @@ module JSONSkooma
|
|
47
46
|
end
|
48
47
|
|
49
48
|
def to_s
|
50
|
-
return
|
51
|
-
|
52
|
-
|
53
|
-
|
49
|
+
return @to_s if instance_variable_defined?(:@to_s)
|
50
|
+
|
51
|
+
@to_s =
|
52
|
+
case @path
|
53
|
+
when []
|
54
|
+
""
|
55
|
+
when [""]
|
56
|
+
"/"
|
57
|
+
else
|
58
|
+
"/" + @path.map(&method(:escape)).join("/")
|
59
|
+
end
|
54
60
|
end
|
55
61
|
|
56
|
-
memoize :to_s
|
57
|
-
|
58
62
|
def ==(other)
|
59
63
|
return super unless other.is_a?(self.class)
|
60
64
|
other.path == path
|
@@ -2,10 +2,7 @@
|
|
2
2
|
|
3
3
|
module JSONSkooma
|
4
4
|
class JSONSchema < JSONNode
|
5
|
-
extend Memoizable
|
6
|
-
|
7
5
|
attr_reader :uri, :cache_id, :registry
|
8
|
-
|
9
6
|
attr_writer :metaschema_uri
|
10
7
|
|
11
8
|
def initialize(value, registry: Registry::DEFAULT_NAME, cache_id: "default", uri: nil, metaschema_uri: nil, parent: nil, key: nil)
|
@@ -25,7 +22,9 @@ module JSONSkooma
|
|
25
22
|
resolve_references if parent.nil?
|
26
23
|
end
|
27
24
|
|
28
|
-
def evaluate(instance, result = nil)
|
25
|
+
def evaluate(instance, result = nil, ref: nil)
|
26
|
+
return resolve_ref(ref).evaluate(instance, result) if ref
|
27
|
+
|
29
28
|
instance = JSONSkooma::JSONNode.new(instance) unless instance.is_a?(JSONNode)
|
30
29
|
|
31
30
|
result ||= Result.new(self, instance)
|
@@ -43,7 +42,7 @@ module JSONSkooma
|
|
43
42
|
end
|
44
43
|
end
|
45
44
|
|
46
|
-
if result.children.any? { |_, child| !child.passed?
|
45
|
+
if result.children[instance.path]&.any? { |_, child| !child.passed? }
|
47
46
|
result.failure
|
48
47
|
end
|
49
48
|
end
|
@@ -51,19 +50,32 @@ module JSONSkooma
|
|
51
50
|
result
|
52
51
|
end
|
53
52
|
|
53
|
+
def resolve_uri(uri)
|
54
|
+
uri = URI.parse(uri)
|
55
|
+
return uri if uri.absolute?
|
56
|
+
return base_uri + uri if base_uri
|
57
|
+
|
58
|
+
raise Error, "No base URI against which to resolve uri `#{uri}`"
|
59
|
+
end
|
60
|
+
|
61
|
+
def resolve_ref(uri)
|
62
|
+
registry.schema(resolve_uri(uri), metaschema_uri: metaschema_uri, cache_id: cache_id)
|
63
|
+
end
|
64
|
+
|
54
65
|
def validate
|
55
66
|
metaschema.evaluate(self)
|
56
67
|
end
|
57
68
|
|
58
69
|
def parent_schema
|
70
|
+
return @parent_schema if instance_variable_defined?(:@parent_schema)
|
71
|
+
|
59
72
|
node = parent
|
60
73
|
while node
|
61
|
-
return node if node.is_a?(JSONSchema)
|
74
|
+
return @parent_schema = node if node.is_a?(JSONSchema)
|
62
75
|
|
63
76
|
node = node.parent
|
64
77
|
end
|
65
78
|
end
|
66
|
-
memoize :parent_schema
|
67
79
|
|
68
80
|
def uri=(uri)
|
69
81
|
return if @uri == uri
|
@@ -81,9 +93,8 @@ module JSONSkooma
|
|
81
93
|
end
|
82
94
|
|
83
95
|
def metaschema_uri
|
84
|
-
@metaschema_uri
|
96
|
+
@metaschema_uri ||= parent_schema&.metaschema_uri
|
85
97
|
end
|
86
|
-
memoize :metaschema_uri
|
87
98
|
|
88
99
|
def base_uri
|
89
100
|
return parent_schema&.base_uri unless uri
|
@@ -93,6 +104,7 @@ module JSONSkooma
|
|
93
104
|
|
94
105
|
def canonical_uri
|
95
106
|
return uri if uri
|
107
|
+
return @canonical_uri if instance_variable_defined?(:@canonical_uri)
|
96
108
|
|
97
109
|
keys = []
|
98
110
|
node = self
|
@@ -102,14 +114,13 @@ module JSONSkooma
|
|
102
114
|
|
103
115
|
if node.is_a?(JSONSchema) && node.uri
|
104
116
|
fragment = JSONPointer.new(node.uri.fragment || "") << keys
|
105
|
-
return node.uri.dup.tap { |u| u.fragment = fragment.to_s }
|
117
|
+
return @canonical_uri = node.uri.dup.tap { |u| u.fragment = fragment.to_s }
|
106
118
|
end
|
107
119
|
end
|
108
120
|
end
|
109
|
-
memoize :canonical_uri
|
110
121
|
|
111
122
|
def resolve_references
|
112
|
-
@keywords.each_value
|
123
|
+
@keywords.each_value(&:resolve)
|
113
124
|
end
|
114
125
|
|
115
126
|
private
|
@@ -150,19 +161,19 @@ module JSONSkooma
|
|
150
161
|
end
|
151
162
|
|
152
163
|
def dependencies_in_order(kw_classes)
|
153
|
-
dependencies = kw_classes.
|
154
|
-
[kw_class
|
155
|
-
end
|
164
|
+
dependencies = kw_classes.each_value.with_object({}) do |kw_class, res|
|
165
|
+
res[kw_class] = kw_class.depends_on.filter_map { |dep| kw_classes[dep] }
|
166
|
+
end
|
156
167
|
|
157
168
|
while dependencies.any?
|
158
169
|
kw_class, _ = dependencies.find { |_, depclasses| depclasses.empty? }
|
159
170
|
dependencies.delete(kw_class)
|
160
|
-
dependencies.
|
171
|
+
dependencies.each_value { |deps| deps.delete(kw_class) }
|
161
172
|
yield kw_class
|
162
173
|
end
|
163
174
|
end
|
164
175
|
|
165
|
-
def parse_value(value
|
176
|
+
def parse_value(value)
|
166
177
|
case value
|
167
178
|
when true, false
|
168
179
|
["boolean", value]
|
@@ -11,13 +11,14 @@ module JSONSkooma
|
|
11
11
|
|
12
12
|
def evaluate(instance, result)
|
13
13
|
known_property_names = result.sibling(instance, "properties")&.schema_node&.keys || []
|
14
|
-
known_property_patterns = result.sibling(instance, "patternProperties")&.schema_node&.keys || []
|
14
|
+
known_property_patterns = (result.sibling(instance, "patternProperties")&.schema_node&.keys || [])
|
15
|
+
.map { |pattern| Regexp.new(pattern) }
|
15
16
|
|
16
17
|
annotation = []
|
17
18
|
error = []
|
18
19
|
|
19
20
|
instance.each do |name, item|
|
20
|
-
if !known_property_names.include?(name) && !known_property_patterns.any? { |pattern|
|
21
|
+
if !known_property_names.include?(name) && !known_property_patterns.any? { |pattern| pattern.match?(name) }
|
21
22
|
if json.evaluate(item, result).passed?
|
22
23
|
annotation << name
|
23
24
|
else
|
@@ -11,7 +11,7 @@ module JSONSkooma
|
|
11
11
|
def evaluate(instance, result)
|
12
12
|
annotation = nil
|
13
13
|
error = []
|
14
|
-
instance.take(json.length).each_with_index do |item, index|
|
14
|
+
instance.take(json.value.length).each_with_index do |item, index|
|
15
15
|
annotation = index
|
16
16
|
result.call(item, index.to_s) do |subresult|
|
17
17
|
unless json[index].evaluate(item, subresult).passed?
|
@@ -7,28 +7,13 @@ module JSONSkooma
|
|
7
7
|
self.key = "$ref"
|
8
8
|
|
9
9
|
def resolve
|
10
|
-
|
11
|
-
@ref_schema = parent_schema.registry.schema(
|
12
|
-
uri,
|
13
|
-
metaschema_uri: parent_schema.metaschema_uri,
|
14
|
-
cache_id: parent_schema.cache_id
|
15
|
-
)
|
10
|
+
@ref_schema = parent_schema.resolve_ref(json)
|
16
11
|
end
|
17
12
|
|
18
13
|
def evaluate(instance, result)
|
19
14
|
@ref_schema.evaluate(instance, result)
|
20
15
|
result.ref_schema = @ref_schema
|
21
16
|
end
|
22
|
-
|
23
|
-
private
|
24
|
-
|
25
|
-
def resolve_uri
|
26
|
-
uri = URI.parse(json)
|
27
|
-
return uri if uri.absolute?
|
28
|
-
return parent_schema.base_uri + uri if parent_schema.base_uri
|
29
|
-
|
30
|
-
raise Error, "No base URI against which to resolve the `$ref` value `#{uri}`"
|
31
|
-
end
|
32
17
|
end
|
33
18
|
end
|
34
19
|
end
|
@@ -22,7 +22,7 @@ module JSONSkooma
|
|
22
22
|
annotation = nil
|
23
23
|
error = []
|
24
24
|
|
25
|
-
instance.take(json.length).each_with_index do |item, index|
|
25
|
+
instance.take(json.value.length).each_with_index do |item, index|
|
26
26
|
annotation = index
|
27
27
|
result.call(item, index.to_s) do |subresult|
|
28
28
|
unless json[index].evaluate(item, subresult).passed?
|
@@ -10,23 +10,19 @@ module JSONSkooma
|
|
10
10
|
self.depends_on = %w[
|
11
11
|
items additionalItems
|
12
12
|
if then else allOf anyOf oneOf not
|
13
|
+
$ref $dynamicRef $recursiveRef
|
13
14
|
]
|
14
15
|
|
16
|
+
LOOKUP_KEYWORDS = %w[items additionalItems unevaluatedItems].freeze
|
17
|
+
|
15
18
|
def evaluate(instance, result)
|
16
19
|
last_evaluated_item = -1
|
17
20
|
|
18
|
-
result.parent.collect_annotations(instance,
|
21
|
+
result.parent.collect_annotations(instance, keys: LOOKUP_KEYWORDS) do |node|
|
22
|
+
i = node.annotation
|
19
23
|
next result.discard if i == true
|
20
24
|
|
21
|
-
last_evaluated_item = i if i > last_evaluated_item
|
22
|
-
end
|
23
|
-
|
24
|
-
result.parent.collect_annotations(instance, "additionalItems") do |i|
|
25
|
-
next result.discard if i == true
|
26
|
-
end
|
27
|
-
|
28
|
-
result.parent.collect_annotations(instance, "unevaluatedItems") do |i|
|
29
|
-
next result.discard if i == true
|
25
|
+
last_evaluated_item = i if node.key == "items" && i > last_evaluated_item
|
30
26
|
end
|
31
27
|
|
32
28
|
annotation = nil
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module JSONSkooma
|
4
|
+
module Keywords
|
5
|
+
module Draft201909
|
6
|
+
class UnevaluatedProperties < Base
|
7
|
+
self.key = "unevaluatedProperties"
|
8
|
+
self.instance_types = %w[object]
|
9
|
+
self.value_schema = :schema
|
10
|
+
self.depends_on = %w[
|
11
|
+
properties patternProperties additionalProperties
|
12
|
+
if then else dependentSchemas allOf anyOf oneOf not
|
13
|
+
$ref $dynamicRef $recursiveRef
|
14
|
+
]
|
15
|
+
|
16
|
+
LOOKUP_KEYWORDS = %w[properties patternProperties additionalProperties unevaluatedProperties].freeze
|
17
|
+
|
18
|
+
def evaluate(instance, result)
|
19
|
+
evaluated_names = Set.new
|
20
|
+
result.parent.collect_annotations(instance, keys: LOOKUP_KEYWORDS) do |node|
|
21
|
+
evaluated_names += node.annotation
|
22
|
+
end
|
23
|
+
|
24
|
+
annotation = []
|
25
|
+
error = []
|
26
|
+
instance.each do |name, item|
|
27
|
+
next if evaluated_names.include?(name)
|
28
|
+
|
29
|
+
if json.evaluate(item, result).passed?
|
30
|
+
annotation << name
|
31
|
+
else
|
32
|
+
error << name
|
33
|
+
# reset to success for the next iteration
|
34
|
+
result.success
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
return result.failure(error) if error.any?
|
39
|
+
|
40
|
+
result.annotate(annotation)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -10,27 +10,24 @@ module JSONSkooma
|
|
10
10
|
self.depends_on = %w[
|
11
11
|
prefixItems items contains
|
12
12
|
if then else allOf anyOf oneOf not
|
13
|
+
$ref $dynamicRef
|
13
14
|
]
|
14
15
|
|
16
|
+
LOOKUP_KEYWORDS = %w[items unevaluatedItems prefixItems contains].freeze
|
17
|
+
|
15
18
|
def evaluate(instance, result)
|
19
|
+
contains_indices = Set.new
|
16
20
|
last_evaluated_item = -1
|
17
21
|
|
18
|
-
result.parent.collect_annotations(instance,
|
19
|
-
next
|
20
|
-
|
21
|
-
last_evaluated_item = i if i > last_evaluated_item
|
22
|
-
end
|
22
|
+
result.parent.collect_annotations(instance, keys: LOOKUP_KEYWORDS) do |node|
|
23
|
+
next contains_indices += node.annotation if node.key == "contains"
|
23
24
|
|
24
|
-
|
25
|
+
i = node.annotation
|
25
26
|
next result.discard if i == true
|
26
|
-
end
|
27
27
|
|
28
|
-
|
29
|
-
next result.discard if i == true
|
28
|
+
last_evaluated_item = i if node.key == "prefixItems" && i > last_evaluated_item
|
30
29
|
end
|
31
30
|
|
32
|
-
contains_indices = Set.new
|
33
|
-
result.parent.collect_annotations(instance, "contains") { |i| contains_indices += Set.new(i) }
|
34
31
|
annotation = nil
|
35
32
|
error = []
|
36
33
|
|
@@ -10,14 +10,16 @@ module JSONSkooma
|
|
10
10
|
self.depends_on = %w[
|
11
11
|
properties patternProperties additionalProperties
|
12
12
|
if then else dependentSchemas allOf anyOf oneOf not
|
13
|
+
$ref $dynamicRef
|
13
14
|
]
|
14
15
|
|
16
|
+
LOOKUP_KEYWORDS = %w[properties patternProperties additionalProperties unevaluatedProperties].freeze
|
17
|
+
|
15
18
|
def evaluate(instance, result)
|
16
19
|
evaluated_names = Set.new
|
17
|
-
result.parent.collect_annotations(instance,
|
18
|
-
|
19
|
-
|
20
|
-
result.parent.collect_annotations(instance, "unevaluatedProperties") { |name| evaluated_names += Set.new(name) }
|
20
|
+
result.parent.collect_annotations(instance, keys: LOOKUP_KEYWORDS) do |node|
|
21
|
+
evaluated_names += node.annotation
|
22
|
+
end
|
21
23
|
|
22
24
|
annotation = []
|
23
25
|
error = []
|
@@ -9,7 +9,7 @@ module JSONSkooma
|
|
9
9
|
def evaluate(instance, result)
|
10
10
|
return if instance == json
|
11
11
|
|
12
|
-
result.failure("The instance value #{instance.value
|
12
|
+
result.failure("The instance value #{instance.value} must be equal to the defined constant #{json.value}")
|
13
13
|
end
|
14
14
|
end
|
15
15
|
end
|
@@ -10,7 +10,7 @@ module JSONSkooma
|
|
10
10
|
return if json.include?(instance)
|
11
11
|
|
12
12
|
result.failure(
|
13
|
-
"The instance value #{instance.value
|
13
|
+
"The instance value #{instance.value} must be equal to one of the elements in the defined enumeration: #{json.value.join(", ")}"
|
14
14
|
)
|
15
15
|
end
|
16
16
|
end
|
@@ -8,10 +8,9 @@ module JSONSkooma
|
|
8
8
|
self.instance_types = "object"
|
9
9
|
|
10
10
|
def evaluate(instance, result)
|
11
|
-
|
12
|
-
return if missing_keys.empty?
|
11
|
+
return if json.value.all? { |val| instance.key?(val) }
|
13
12
|
|
14
|
-
result.failure("The object is missing required properties #{json.value}")
|
13
|
+
result.failure("The object is missing required properties #{json.value.join(", ")}")
|
15
14
|
end
|
16
15
|
end
|
17
16
|
end
|
@@ -21,7 +21,7 @@ module JSONSkooma
|
|
21
21
|
def bootstrap(value)
|
22
22
|
super
|
23
23
|
|
24
|
-
kw = Keywords::Core::Vocabulary.new(self, value.fetch("$vocabulary"
|
24
|
+
kw = Keywords::Core::Vocabulary.new(self, value.fetch("$vocabulary") { default_vocabulary_urls })
|
25
25
|
add_keyword(kw) if value.key?("$vocabulary")
|
26
26
|
end
|
27
27
|
|
data/lib/json_skooma/result.rb
CHANGED
@@ -4,36 +4,68 @@ module JSONSkooma
|
|
4
4
|
class Result
|
5
5
|
attr_writer :ref_schema
|
6
6
|
|
7
|
-
attr_reader :
|
7
|
+
attr_reader :schema, :instance, :parent, :annotation, :error, :key
|
8
8
|
|
9
9
|
def initialize(schema, instance, parent: nil, key: nil)
|
10
|
-
|
11
|
-
|
10
|
+
reset_with(instance, key, parent, schema)
|
11
|
+
end
|
12
|
+
|
13
|
+
def children
|
14
|
+
@children ||= {}
|
15
|
+
end
|
16
|
+
|
17
|
+
def each_children
|
18
|
+
children.each_value do |child|
|
19
|
+
child.each_value do |grandchild|
|
20
|
+
yield grandchild
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def path
|
26
|
+
@path ||= @parent.nil? ? JSONPointer.new([]) : parent.path.child(key)
|
27
|
+
end
|
28
|
+
|
29
|
+
def relative_path
|
30
|
+
@relative_path ||=
|
31
|
+
if @parent.nil?
|
32
|
+
JSONPointer.new([])
|
33
|
+
elsif schema.equal?(parent.schema)
|
34
|
+
parent.relative_path.child(key)
|
35
|
+
else
|
36
|
+
JSONPointer.new_root(key)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def root
|
41
|
+
@root ||= parent&.root || self
|
42
|
+
end
|
43
|
+
|
44
|
+
def reset_with(instance, key, parent, schema = nil)
|
45
|
+
@schema = schema if schema
|
12
46
|
@parent = parent
|
13
|
-
@root = parent&.root || self
|
14
47
|
@key = key
|
15
|
-
@children = {}
|
16
48
|
@valid = true
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
end
|
28
|
-
end
|
49
|
+
@instance = instance
|
50
|
+
|
51
|
+
@children = nil
|
52
|
+
@annotation = nil
|
53
|
+
@discard = false
|
54
|
+
@skip_assertion = false
|
55
|
+
@error = nil
|
56
|
+
@path = nil
|
57
|
+
@ref_schema = nil
|
58
|
+
@relative_path = nil
|
29
59
|
end
|
30
60
|
|
31
|
-
def call(instance, key, schema = nil
|
32
|
-
child =
|
61
|
+
def call(instance, key, schema = nil)
|
62
|
+
child = dup
|
63
|
+
child.reset_with(instance, key, self, schema)
|
33
64
|
|
34
65
|
yield child
|
35
66
|
|
36
|
-
|
67
|
+
return if child.discard?
|
68
|
+
(children[instance.path] ||= {})[key] = child
|
37
69
|
end
|
38
70
|
|
39
71
|
def schema_node
|
@@ -41,7 +73,7 @@ module JSONSkooma
|
|
41
73
|
end
|
42
74
|
|
43
75
|
def sibling(instance, key)
|
44
|
-
@parent
|
76
|
+
@parent&.children&.dig(instance.path, key)
|
45
77
|
end
|
46
78
|
|
47
79
|
def annotate(value)
|
@@ -86,34 +118,36 @@ module JSONSkooma
|
|
86
118
|
schema.canonical_uri.dup.tap { |u| u.fragment = path.to_s }
|
87
119
|
end
|
88
120
|
|
89
|
-
def collect_annotations(instance
|
121
|
+
def collect_annotations(instance, key: nil, keys: nil)
|
90
122
|
return if !valid? || discard?
|
91
123
|
|
92
124
|
if @annotation &&
|
93
125
|
(key.nil? || key == @key) &&
|
94
|
-
(
|
95
|
-
|
126
|
+
(keys.nil? || keys.include?(@key)) &&
|
127
|
+
(instance.path == @instance.path)
|
128
|
+
yield self
|
96
129
|
end
|
97
130
|
|
98
|
-
|
99
|
-
child.collect_annotations(instance, key) do |
|
100
|
-
yield
|
131
|
+
children[instance.path]&.each_value do |child|
|
132
|
+
child.collect_annotations(instance, key: key, keys: keys) do |node|
|
133
|
+
yield node
|
101
134
|
end
|
102
135
|
end
|
103
136
|
end
|
104
137
|
|
105
|
-
def collect_errors(instance: nil,
|
138
|
+
def collect_errors(instance, key: nil, keys: nil)
|
106
139
|
return if valid? || discard?
|
107
140
|
|
108
141
|
if @error &&
|
109
142
|
(key.nil? || key == @key) &&
|
110
|
-
(
|
111
|
-
|
143
|
+
(keys.nil? || keys.include?(@key)) &&
|
144
|
+
(instance.path == @instance.path)
|
145
|
+
yield self
|
112
146
|
end
|
113
147
|
|
114
|
-
|
115
|
-
child.collect_errors(instance, key) do |
|
116
|
-
yield
|
148
|
+
children[instance.path]&.each_value do |child|
|
149
|
+
child.collect_errors(instance, key: key, keys: keys) do |node|
|
150
|
+
yield node
|
117
151
|
end
|
118
152
|
end
|
119
153
|
end
|
@@ -121,5 +155,9 @@ module JSONSkooma
|
|
121
155
|
def output(format, **options)
|
122
156
|
Formatters[format].call(self, **options)
|
123
157
|
end
|
158
|
+
|
159
|
+
def to_s
|
160
|
+
output(:simple)
|
161
|
+
end
|
124
162
|
end
|
125
163
|
end
|
@@ -6,7 +6,8 @@ module JSONSkooma
|
|
6
6
|
module Validators
|
7
7
|
class IdnHostname < Base
|
8
8
|
def call(data)
|
9
|
-
|
9
|
+
register_opts = data.value.ascii_only? ? {alabel: data.value} : {ulabel: data.value}
|
10
|
+
URI::IDNA.register(**register_opts)
|
10
11
|
rescue URI::IDNA::Error => e
|
11
12
|
raise FormatError, "#{data} is not a valid IDN hostname: #{e.message}"
|
12
13
|
end
|
@@ -1,18 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "ipaddr"
|
4
|
-
|
5
3
|
module JSONSkooma
|
6
4
|
module Validators
|
7
5
|
class Ipv4 < Base
|
8
|
-
|
6
|
+
IPV4_ADDRESS = /((25[0-5]|(2[0-4]|1\d|[1-9])?\d)\.?\b){4}/
|
7
|
+
REGEXP = /\A#{IPV4_ADDRESS}\z/
|
9
8
|
|
10
9
|
class << self
|
11
10
|
def call(data)
|
12
|
-
|
13
|
-
raise FormatError, "must be a valid IPv4 address"
|
14
|
-
rescue IPAddr::Error => e
|
15
|
-
raise FormatError, e.message
|
11
|
+
match = REGEXP.match(data)
|
12
|
+
raise FormatError, "must be a valid IPv4 address" if match.nil?
|
16
13
|
end
|
17
14
|
end
|
18
15
|
end
|
@@ -1,15 +1,17 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "ipaddr"
|
4
|
-
|
5
3
|
module JSONSkooma
|
6
4
|
module Validators
|
7
5
|
class Ipv6 < Base
|
6
|
+
H16 = /\h{1,4}/
|
7
|
+
LS32 = /(?:#{H16}:#{H16})|#{Ipv4::IPV4_ADDRESS}/
|
8
|
+
IPV6_ADDRESS = /(?:#{H16}:){6}#{LS32}|::(?:#{H16}:){5}#{LS32}|(?:#{H16})?::(?:#{H16}:){4}#{LS32}|(?:(?:#{H16}:){0,1}#{H16})?::(?:#{H16}:){3}#{LS32}|(?:(?:#{H16}:){0,2}#{H16})?::(?:#{H16}:){2}#{LS32}|(?:(?:#{H16}:){0,3}#{H16})?::(?:#{H16}:){1}#{LS32}|(?:(?:#{H16}:){0,4}#{H16})?::#{LS32}|(?:(?:#{H16}:){0,5}#{H16})?::#{H16}|(?:(?:#{H16}:){0,6}#{H16})?::/.freeze
|
9
|
+
|
10
|
+
REGEXP = /\A#{IPV6_ADDRESS}\z/
|
11
|
+
|
8
12
|
def call(data)
|
9
|
-
|
10
|
-
raise FormatError, "must be a valid IPv6 address"
|
11
|
-
rescue IPAddr::Error => e
|
12
|
-
raise FormatError, e.message
|
13
|
+
match = REGEXP.match(data)
|
14
|
+
raise FormatError, "must be a valid IPv6 address" if match.nil?
|
13
15
|
end
|
14
16
|
end
|
15
17
|
end
|
@@ -23,7 +23,7 @@ module JSONSkooma
|
|
23
23
|
IPATH_OLD = /#{IPATH_ABEMPTY}|#{IPATH_ABSOLUTE}|#{IPATH_NOSCHEME}|#{IPATH_ROOTLESS}|/.freeze
|
24
24
|
|
25
25
|
IREG_NAME = /(?:#{IUNRESERVED}|#{Uri::PCT_ENCODED}|#{Uri::SUB_DELIMS})*/.freeze
|
26
|
-
IHOST = /#{Uri::IP_LITERAL}|#{
|
26
|
+
IHOST = /#{Uri::IP_LITERAL}|#{Ipv4::IPV4_ADDRESS}|#{IREG_NAME}/.freeze
|
27
27
|
IUSERINFO = /(?:#{IUNRESERVED}|#{Uri::PCT_ENCODED}|#{Uri::SUB_DELIMS}|:)*/.freeze
|
28
28
|
IAUTHORITY = /(?:#{IUSERINFO}@)?#{IHOST}(?::#{Uri::PORT})?/.freeze
|
29
29
|
|
@@ -22,17 +22,12 @@ module JSONSkooma
|
|
22
22
|
PATH_ROOTLESS = /#{SEGMENT_NZ}(?:\/#{SEGMENT})*/.freeze
|
23
23
|
PATH = /(?:#{PATH_ABEMPTY}|#{PATH_ABSOLUTE}|#{PATH_NOSCHEME}|#{PATH_ROOTLESS})?/.freeze
|
24
24
|
|
25
|
-
IPV4_ADDRESS = /((25[0-5]|(2[0-4]|1\d|[1-9])?\d)\.?\b){4}/
|
26
|
-
H16 = /\h{1,4}/
|
27
|
-
LS32 = /(?:#{H16}:#{H16})|#{IPV4_ADDRESS}/
|
28
|
-
IPV6_ADDRESS = /(?:#{H16}:){6}#{LS32}|::(?:#{H16}:){5}#{LS32}|(?:#{H16})?::(?:#{H16}:){4}#{LS32}|(?:(?:#{H16}:){0,1}#{H16})?::(?:#{H16}:){3}#{LS32}|(?:(?:#{H16}:){0,2}#{H16})?::(?:#{H16}:){2}#{LS32}|(?:(?:#{H16}:){0,3}#{H16})?::(?:#{H16}:){1}#{LS32}|(?:(?:#{H16}:){0,4}#{H16})?::#{LS32}|(?:(?:#{H16}:){0,5}#{H16})?::#{H16}|(?:(?:#{H16}:){0,6}#{H16})?::/.freeze
|
29
|
-
|
30
25
|
IPV_FUTURE = /v\h+\.(?:#{UNRESERVED}|#{SUB_DELIMS}|:)+/.freeze
|
31
|
-
IP_LITERAL = /\[(?:#{IPV6_ADDRESS}|#{IPV_FUTURE})\]/.freeze
|
26
|
+
IP_LITERAL = /\[(?:#{Ipv6::IPV6_ADDRESS}|#{IPV_FUTURE})\]/.freeze
|
32
27
|
|
33
28
|
PORT = /\d*/.freeze
|
34
29
|
REG_NAME = /(?:#{UNRESERVED}|#{PCT_ENCODED}|#{SUB_DELIMS})*/.freeze
|
35
|
-
HOST = /(?:#{IP_LITERAL}|#{IPV4_ADDRESS}|#{REG_NAME})/.freeze
|
30
|
+
HOST = /(?:#{IP_LITERAL}|#{Ipv4::IPV4_ADDRESS}|#{REG_NAME})/.freeze
|
36
31
|
USERINFO = /(?:#{UNRESERVED}|#{PCT_ENCODED}|#{SUB_DELIMS}|:)*/.freeze
|
37
32
|
AUTHORITY = /(?:#{USERINFO}@)?#{HOST}(?::#{PORT})?/.freeze
|
38
33
|
|
data/lib/json_skooma/version.rb
CHANGED
data/lib/json_skooma.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: json_skooma
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1
|
4
|
+
version: 0.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Svyatoslav Kryukov
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-12-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: zeitwerk
|
@@ -58,17 +58,17 @@ dependencies:
|
|
58
58
|
requirements:
|
59
59
|
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: '0.
|
61
|
+
version: '0.2'
|
62
62
|
type: :runtime
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version: '0.
|
68
|
+
version: '0.2'
|
69
69
|
description: I bring some sugar for your JSONs.
|
70
70
|
email:
|
71
|
-
-
|
71
|
+
- me@skryukov.dev
|
72
72
|
executables: []
|
73
73
|
extensions: []
|
74
74
|
extra_rdoc_files: []
|
@@ -152,6 +152,7 @@ files:
|
|
152
152
|
- lib/json_skooma/keywords/draft_2019_09/recursive_anchor.rb
|
153
153
|
- lib/json_skooma/keywords/draft_2019_09/recursive_ref.rb
|
154
154
|
- lib/json_skooma/keywords/draft_2019_09/unevaluated_items.rb
|
155
|
+
- lib/json_skooma/keywords/draft_2019_09/unevaluated_properties.rb
|
155
156
|
- lib/json_skooma/keywords/format_annotation/format.rb
|
156
157
|
- lib/json_skooma/keywords/meta_data/default.rb
|
157
158
|
- lib/json_skooma/keywords/meta_data/deprecated.rb
|
@@ -184,7 +185,6 @@ files:
|
|
184
185
|
- lib/json_skooma/keywords/validation/type.rb
|
185
186
|
- lib/json_skooma/keywords/validation/unique_items.rb
|
186
187
|
- lib/json_skooma/keywords/value_schemas.rb
|
187
|
-
- lib/json_skooma/memoizable.rb
|
188
188
|
- lib/json_skooma/metaschema.rb
|
189
189
|
- lib/json_skooma/registry.rb
|
190
190
|
- lib/json_skooma/result.rb
|
@@ -1,21 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module JSONSkooma
|
4
|
-
module Memoizable
|
5
|
-
def self.included(base)
|
6
|
-
base.extend(Memoizable)
|
7
|
-
end
|
8
|
-
|
9
|
-
def memoize(method_name)
|
10
|
-
this = respond_to?(:prepend) ? self : singleton_class
|
11
|
-
var_name = "@memoized_#{method_name}"
|
12
|
-
this.prepend(Module.new do
|
13
|
-
define_method(method_name) do
|
14
|
-
return instance_variable_get(var_name) if instance_variable_defined?(var_name)
|
15
|
-
|
16
|
-
instance_variable_set(var_name, super())
|
17
|
-
end
|
18
|
-
end)
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|