jsi-dev 0.0.8 → 0.0.9
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
- data/.yardopts +3 -4
- data/CHANGELOG.md +19 -0
- data/LICENSE.md +2 -3
- data/README.md +87 -43
- data/docs/{glossary.md → Glossary.md} +84 -52
- data/jsi.gemspec +1 -1
- data/lib/jsi/base/mutability.rb +48 -0
- data/lib/jsi/base/node.rb +66 -52
- data/lib/jsi/base.rb +592 -176
- data/lib/jsi/jsi_coder.rb +4 -2
- data/lib/jsi/metaschema_node/bootstrap_schema.rb +118 -59
- data/lib/jsi/metaschema_node.rb +244 -154
- data/lib/jsi/ptr.rb +45 -17
- data/lib/jsi/ref.rb +197 -0
- data/lib/jsi/registry.rb +311 -0
- data/lib/jsi/schema/cxt/child_application.rb +35 -0
- data/lib/jsi/schema/cxt/inplace_application.rb +37 -0
- data/lib/jsi/schema/cxt.rb +80 -0
- data/lib/jsi/schema/dialect.rb +137 -0
- data/lib/jsi/schema/draft04.rb +113 -5
- data/lib/jsi/schema/draft06.rb +123 -5
- data/lib/jsi/schema/draft07.rb +157 -5
- data/lib/jsi/schema/draft202012.rb +303 -0
- data/lib/jsi/schema/dynamic_anchor_map.rb +63 -0
- data/lib/jsi/schema/element.rb +69 -0
- data/lib/jsi/schema/elements/anchor.rb +13 -0
- data/lib/jsi/schema/elements/array_validation.rb +82 -0
- data/lib/jsi/schema/elements/comment.rb +10 -0
- data/lib/jsi/schema/{validation → elements}/const.rb +11 -7
- data/lib/jsi/schema/elements/contains.rb +59 -0
- data/lib/jsi/schema/elements/contains_minmax.rb +91 -0
- data/lib/jsi/schema/elements/content_encoding.rb +10 -0
- data/lib/jsi/schema/elements/content_media_type.rb +10 -0
- data/lib/jsi/schema/elements/content_schema.rb +16 -0
- data/lib/jsi/schema/elements/default.rb +11 -0
- data/lib/jsi/schema/elements/definitions.rb +19 -0
- data/lib/jsi/schema/elements/dependencies.rb +99 -0
- data/lib/jsi/schema/elements/dependent_required.rb +49 -0
- data/lib/jsi/schema/elements/dependent_schemas.rb +69 -0
- data/lib/jsi/schema/elements/dynamic_ref.rb +69 -0
- data/lib/jsi/schema/elements/enum.rb +26 -0
- data/lib/jsi/schema/elements/examples.rb +10 -0
- data/lib/jsi/schema/elements/format.rb +10 -0
- data/lib/jsi/schema/elements/id.rb +30 -0
- data/lib/jsi/schema/elements/if_then_else.rb +82 -0
- data/lib/jsi/schema/elements/info_bool.rb +10 -0
- data/lib/jsi/schema/elements/info_string.rb +10 -0
- data/lib/jsi/schema/elements/items.rb +93 -0
- data/lib/jsi/schema/elements/items_prefixed.rb +96 -0
- data/lib/jsi/schema/elements/not.rb +31 -0
- data/lib/jsi/schema/elements/numeric.rb +137 -0
- data/lib/jsi/schema/elements/numeric_draft04.rb +77 -0
- data/lib/jsi/schema/elements/object_validation.rb +55 -0
- data/lib/jsi/schema/elements/pattern.rb +35 -0
- data/lib/jsi/schema/elements/properties.rb +145 -0
- data/lib/jsi/schema/elements/property_names.rb +48 -0
- data/lib/jsi/schema/elements/ref.rb +62 -0
- data/lib/jsi/schema/elements/required.rb +34 -0
- data/lib/jsi/schema/elements/self.rb +24 -0
- data/lib/jsi/schema/elements/some_of.rb +180 -0
- data/lib/jsi/schema/elements/string_validation.rb +57 -0
- data/lib/jsi/schema/elements/type.rb +43 -0
- data/lib/jsi/schema/elements/unevaluated_items.rb +54 -0
- data/lib/jsi/schema/elements/unevaluated_properties.rb +54 -0
- data/lib/jsi/schema/elements/xschema.rb +10 -0
- data/lib/jsi/schema/elements/xvocabulary.rb +10 -0
- data/lib/jsi/schema/elements.rb +101 -0
- data/lib/jsi/schema/issue.rb +3 -4
- data/lib/jsi/schema/schema_ancestor_node.rb +105 -52
- data/lib/jsi/schema/vocabulary.rb +36 -0
- data/lib/jsi/schema.rb +598 -383
- data/lib/jsi/schema_classes.rb +195 -141
- data/lib/jsi/schema_set.rb +85 -128
- data/lib/jsi/set.rb +23 -0
- data/lib/jsi/simple_wrap.rb +14 -17
- data/lib/jsi/struct.rb +57 -0
- data/lib/jsi/uri.rb +40 -0
- data/lib/jsi/util/private/memo_map.rb +9 -13
- data/lib/jsi/util/private.rb +59 -31
- data/lib/jsi/util/typelike.rb +19 -60
- data/lib/jsi/util.rb +53 -34
- data/lib/jsi/validation/error.rb +45 -2
- data/lib/jsi/validation/result.rb +121 -90
- data/lib/jsi/validation.rb +1 -6
- data/lib/jsi/version.rb +1 -1
- data/lib/jsi.rb +170 -36
- data/lib/schemas/json-schema.org/draft/2020-12/schema.rb +62 -0
- data/lib/schemas/json-schema.org/draft-04/schema.rb +60 -109
- data/lib/schemas/json-schema.org/draft-06/schema.rb +53 -108
- data/lib/schemas/json-schema.org/draft-07/schema.rb +63 -127
- data/readme.rb +4 -4
- data/{resources}/schemas/2020-12_strict.json +19 -0
- data/{resources}/schemas/json-schema.org/draft/2020-12/meta/applicator.json +48 -0
- data/{resources}/schemas/json-schema.org/draft/2020-12/meta/content.json +17 -0
- data/{resources}/schemas/json-schema.org/draft/2020-12/meta/core.json +51 -0
- data/{resources}/schemas/json-schema.org/draft/2020-12/meta/format-annotation.json +14 -0
- data/{resources}/schemas/json-schema.org/draft/2020-12/meta/format-assertion.json +14 -0
- data/{resources}/schemas/json-schema.org/draft/2020-12/meta/meta-data.json +37 -0
- data/{resources}/schemas/json-schema.org/draft/2020-12/meta/unevaluated.json +15 -0
- data/{resources}/schemas/json-schema.org/draft/2020-12/meta/validation.json +98 -0
- data/{resources}/schemas/json-schema.org/draft/2020-12/schema.json +58 -0
- metadata +73 -52
- data/lib/jsi/metaschema.rb +0 -6
- data/lib/jsi/schema/application/child_application/contains.rb +0 -25
- data/lib/jsi/schema/application/child_application/draft04.rb +0 -21
- data/lib/jsi/schema/application/child_application/draft06.rb +0 -28
- data/lib/jsi/schema/application/child_application/draft07.rb +0 -28
- data/lib/jsi/schema/application/child_application/items.rb +0 -18
- data/lib/jsi/schema/application/child_application/properties.rb +0 -25
- data/lib/jsi/schema/application/child_application.rb +0 -13
- data/lib/jsi/schema/application/draft04.rb +0 -8
- data/lib/jsi/schema/application/draft06.rb +0 -8
- data/lib/jsi/schema/application/draft07.rb +0 -8
- data/lib/jsi/schema/application/inplace_application/dependencies.rb +0 -28
- data/lib/jsi/schema/application/inplace_application/draft04.rb +0 -25
- data/lib/jsi/schema/application/inplace_application/draft06.rb +0 -26
- data/lib/jsi/schema/application/inplace_application/draft07.rb +0 -32
- data/lib/jsi/schema/application/inplace_application/ifthenelse.rb +0 -20
- data/lib/jsi/schema/application/inplace_application/ref.rb +0 -18
- data/lib/jsi/schema/application/inplace_application/someof.rb +0 -44
- data/lib/jsi/schema/application/inplace_application.rb +0 -14
- data/lib/jsi/schema/application.rb +0 -12
- data/lib/jsi/schema/ref.rb +0 -183
- data/lib/jsi/schema/validation/array.rb +0 -69
- data/lib/jsi/schema/validation/contains.rb +0 -25
- data/lib/jsi/schema/validation/dependencies.rb +0 -49
- data/lib/jsi/schema/validation/draft04/minmax.rb +0 -91
- data/lib/jsi/schema/validation/draft04.rb +0 -110
- data/lib/jsi/schema/validation/draft06.rb +0 -120
- data/lib/jsi/schema/validation/draft07.rb +0 -157
- data/lib/jsi/schema/validation/enum.rb +0 -25
- data/lib/jsi/schema/validation/ifthenelse.rb +0 -46
- data/lib/jsi/schema/validation/items.rb +0 -54
- data/lib/jsi/schema/validation/not.rb +0 -20
- data/lib/jsi/schema/validation/numeric.rb +0 -121
- data/lib/jsi/schema/validation/object.rb +0 -45
- data/lib/jsi/schema/validation/pattern.rb +0 -34
- data/lib/jsi/schema/validation/properties.rb +0 -101
- data/lib/jsi/schema/validation/property_names.rb +0 -32
- data/lib/jsi/schema/validation/ref.rb +0 -40
- data/lib/jsi/schema/validation/required.rb +0 -27
- data/lib/jsi/schema/validation/someof.rb +0 -90
- data/lib/jsi/schema/validation/string.rb +0 -47
- data/lib/jsi/schema/validation/type.rb +0 -49
- data/lib/jsi/schema/validation.rb +0 -49
- data/lib/jsi/schema_registry.rb +0 -190
- data/lib/jsi/util/private/attr_struct.rb +0 -130
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 599d7abb635e1cf9cc2ac8918047bf811d17d18833205fa6f07689ba4e065faa
|
|
4
|
+
data.tar.gz: ae0ce6b1348f5278d9df66bd799513673d7f68a2e363d4955bf0097d255419fe
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2aae63956bb9561a5aac559ba3ab1ca91a2722adf10a7b639c103abe2c2cdd1361fb6917b80d05b4c6b25bb41e97e9d79e11cb6505187d050523b6cee91ec2b6
|
|
7
|
+
data.tar.gz: afc015ad1476ddbdb031ac4f5c154d453787a9a643db362b60f1a712dd64eeddfa8dee08e3b4ad0ee98719f056b6cb0e62b51be38de83474fbc4256fda8ba1c5
|
data/.yardopts
CHANGED
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,22 @@
|
|
|
1
|
+
# v0.8.1
|
|
2
|
+
|
|
3
|
+
- JSIs are immutable by default
|
|
4
|
+
|
|
5
|
+
# v0.8.0
|
|
6
|
+
|
|
7
|
+
- Immutable JSIs with new_jsi param `mutable`
|
|
8
|
+
- JSIs are still mutable by default, but in the next release they will default to immutable
|
|
9
|
+
- Base#jsi_indicated_schemas
|
|
10
|
+
- Base::StringNode
|
|
11
|
+
- rename metaschema modules /JSONSchemaOrgDraft0X/JSONSchemaDraft0X/
|
|
12
|
+
- terminology: /Metaschema/Meta-Schema/ and /metaschema/meta-schema/ (where hyphen is allowed)
|
|
13
|
+
- Base::HashNode#jsi_each_propertyName
|
|
14
|
+
- new_schema and/or new_jsi params register, schema_registry, stringify_symbol_keys, to_immutable
|
|
15
|
+
- new_schema block param will module_exec on schema module
|
|
16
|
+
- Base#[] param use_default default false, overridable
|
|
17
|
+
- SchemaModule::Connects, SchemaModule::Connection
|
|
18
|
+
- rm Schema#jsi_schema_instance_modules
|
|
19
|
+
|
|
1
20
|
# v0.7.0
|
|
2
21
|
|
|
3
22
|
- JSI::Base instances include Array/Hash-like modules on subclasses rather than extending each instance; are only Enumerable when appropriate instead of always
|
data/LICENSE.md
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
|
|
1
|
+
JSI Copyright © [Ethan](https://github.com/notEthan/) <ethan.jsi@unth.net>, licensed under the terms of the [GNU Affero General Public License version 3](https://www.gnu.org/licenses/agpl-3.0.html).
|
|
2
2
|
|
|
3
|
-
[<img align="right" src="https://
|
|
3
|
+
[<img align="right" src="https://www.gnu.org/graphics/agplv3-155x51.png">](https://www.gnu.org/licenses/agpl-3.0.html)
|
|
4
4
|
|
|
5
|
-
JSI is licensed under the terms of the [GNU Affero General Public License version 3](https://www.gnu.org/licenses/agpl-3.0.html).
|
|
6
5
|
|
|
7
6
|
GNU Affero General Public License
|
|
8
7
|
=================================
|
data/README.md
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
# JSI: JSON Schema Instantiation
|
|
2
2
|
|
|
3
|
-

|
|
4
4
|
[](https://coveralls.io/github/notEthan/jsi)
|
|
5
5
|
|
|
6
6
|
JSI offers an Object-Oriented representation for JSON data using JSON Schemas. Given your JSON Schemas, JSI constructs Ruby modules and classes which are used to instantiate your JSON data. These modules let you use JSON with all the niceties of OOP such as property accessors and application-defined instance methods.
|
|
7
7
|
|
|
8
8
|
To learn more about JSON Schema see <https://json-schema.org/>.
|
|
9
9
|
|
|
10
|
-
JSI marries object-oriented programming with JSON Schemas by associating a module with each schema, and
|
|
10
|
+
JSI marries object-oriented programming with JSON Schemas by associating a module with each schema, and constructing every instance described by a schema to be an instance of that module. When an application adds methods to a schema module, those methods can be used on the schema's instances.
|
|
11
11
|
|
|
12
12
|
A JSI instance aims to offer a fairly unobtrusive wrapper around its JSON data, which is usually a Hash (JSON Object) or Array described by one or more JSON Schemas. JSI instances have accessors for property names described by schemas, schema validation, and other nice things. Mostly though, you use a JSI as you would use its underlying data, calling the same methods (e.g. `#[]`, `#map`, `#repeated_permutation`) and passing it to anything that duck-types expecting `#to_ary` or `#to_hash`.
|
|
13
13
|
|
|
@@ -15,7 +15,9 @@ Note: The canonical location of this README is on [RubyDoc](http://rubydoc.info/
|
|
|
15
15
|
|
|
16
16
|
## Example
|
|
17
17
|
|
|
18
|
-
Words are boring, let's code.
|
|
18
|
+
Words are boring, let's code. You can follow along from the code blocks - install the gem (`gem install jsi`), load an irb (`irb -r jsi`), and copy/paste/hack.
|
|
19
|
+
|
|
20
|
+
Here's a schema in yaml:
|
|
19
21
|
|
|
20
22
|
```yaml
|
|
21
23
|
$schema: "http://json-schema.org/draft-07/schema"
|
|
@@ -36,7 +38,8 @@ properties:
|
|
|
36
38
|
We pass that to {JSI.new_schema} which will instantiate a JSI Schema which represents it:
|
|
37
39
|
|
|
38
40
|
```ruby
|
|
39
|
-
# this would usually load YAML or JSON; the schema
|
|
41
|
+
# this would usually load YAML or JSON; the schema content
|
|
42
|
+
# is inlined here for copypastability.
|
|
40
43
|
contact_schema = JSI.new_schema({"$schema" => "http://json-schema.org/draft-07/schema", "description" => "A Contact", "type" => "object", "properties" => {"name" => {"type" => "string"}, "phone" => {"type" => "array", "items" => {"type" => "object", "properties" => {"location" => {"type" => "string"}, "number" => {"type" => "string"}}}}}})
|
|
41
44
|
```
|
|
42
45
|
|
|
@@ -61,8 +64,13 @@ nickname: big b
|
|
|
61
64
|
So, if we construct an instance like:
|
|
62
65
|
|
|
63
66
|
```ruby
|
|
64
|
-
|
|
65
|
-
|
|
67
|
+
bill = Contact.new_jsi(
|
|
68
|
+
# this would usually load JSON or YAML; the instance content
|
|
69
|
+
# is inlined for copypastability.
|
|
70
|
+
{"name" => "bill", "phone" => [{"location" => "home", "number" => "555"}], "nickname" => "big b"},
|
|
71
|
+
# note: bill is mutable to demonstrate setters below; the default is immutable.
|
|
72
|
+
mutable: true
|
|
73
|
+
)
|
|
66
74
|
# => #{<JSI (Contact)>
|
|
67
75
|
# "name" => "bill",
|
|
68
76
|
# "phone" => #[<JSI (Contact.properties["phone"])>
|
|
@@ -91,7 +99,7 @@ bill.phone.map(&:location)
|
|
|
91
99
|
# => ["home"]
|
|
92
100
|
```
|
|
93
101
|
|
|
94
|
-
We also get validations, as you'd expect given that's largely what
|
|
102
|
+
We also get validations, as you'd expect given that's largely what JSON Schema exists to do:
|
|
95
103
|
|
|
96
104
|
```ruby
|
|
97
105
|
bill.jsi_valid?
|
|
@@ -109,17 +117,28 @@ bad = Contact.new_jsi({'phone' => [{'number' => [5, 5, 5]}]})
|
|
|
109
117
|
# }
|
|
110
118
|
# ]
|
|
111
119
|
# }
|
|
112
|
-
bad.phone.jsi_validate
|
|
113
|
-
# =>
|
|
114
|
-
#
|
|
115
|
-
#
|
|
116
|
-
#
|
|
117
|
-
#
|
|
118
|
-
#
|
|
119
|
-
#
|
|
120
|
-
#
|
|
121
|
-
#
|
|
122
|
-
#
|
|
120
|
+
bad.phone[0].jsi_validate
|
|
121
|
+
# =>
|
|
122
|
+
# #<JSI::Validation::Result::Full (INVALID)
|
|
123
|
+
# validation errors: JSI::Set[
|
|
124
|
+
# #<JSI::Validation::Error
|
|
125
|
+
# message: "instance object properties are not all valid against corresponding `properties` schemas",
|
|
126
|
+
# instance: {"number" => [5, 5, 5]},
|
|
127
|
+
# instance_ptr: JSI::Ptr["phone", 0],
|
|
128
|
+
# keyword: "properties",
|
|
129
|
+
# schema uri: JSI::URI["#/properties/phone/items"],
|
|
130
|
+
# nested_errors: JSI::Set[
|
|
131
|
+
# #<JSI::Validation::Error
|
|
132
|
+
# message: "instance type does not match `type` value",
|
|
133
|
+
# instance: [5, 5, 5],
|
|
134
|
+
# instance_ptr: JSI::Ptr["phone", 0, "number"],
|
|
135
|
+
# keyword: "type",
|
|
136
|
+
# schema uri: JSI::URI["#/properties/phone/items/properties/number"],
|
|
137
|
+
# nested_errors: JSI::Set[]
|
|
138
|
+
# >
|
|
139
|
+
# ]
|
|
140
|
+
# >
|
|
141
|
+
# ]
|
|
123
142
|
# >
|
|
124
143
|
```
|
|
125
144
|
|
|
@@ -140,9 +159,9 @@ There's plenty more JSI has to offer, but this should give you a pretty good ide
|
|
|
140
159
|
## Terminology and Concepts
|
|
141
160
|
|
|
142
161
|
- `JSI::Base` is the base class for each JSI schema class representing instances of JSON Schemas.
|
|
143
|
-
- a "JSI Schema" is a JSON Schema, instantiated as (usually) a JSI::Base described by a
|
|
144
|
-
- a "JSI Schema Module" is a module
|
|
145
|
-
- a "JSI schema class" is a subclass of `JSI::Base` representing
|
|
162
|
+
- a "JSI Schema" is a JSON Schema, instantiated as (usually) a JSI::Base described by a meta-schema (see the section on meta-schemas below). A JSI Schema is an instance of the module `JSI::Schema`.
|
|
163
|
+
- a "JSI Schema Module" is a module associated with one schema, dynamically created by that schema. Instances of that schema are ruby instances of its JSI schema module. Applications may reopen these modules to add functionality to JSI instances described by the schema.
|
|
164
|
+
- a "JSI schema class" is a subclass of `JSI::Base` representing any number of JSON schemas. Instances of such a class are described by all of the represented schemas. A JSI schema class includes the JSI schema module of each represented schema.
|
|
146
165
|
- "instance" is a term that is significantly overloaded in this space, so documentation will attempt to be clear what kind of instance is meant:
|
|
147
166
|
- a schema instance refers broadly to a data structure that is described by a JSON schema.
|
|
148
167
|
- a JSI instance (or just "a JSI") is a ruby object instantiating a JSI schema class (subclass of `JSI::Base`). This wraps the content of the schema instance (see `JSI::Base#jsi_instance`), and ties it to the schemas which describe the instance (`JSI::Base#jsi_schemas`).
|
|
@@ -157,6 +176,15 @@ JSI supports these JSON Schema specification versions:
|
|
|
157
176
|
| Draft 4 | `http://json-schema.org/draft-04/schema#` | {JSI::JSONSchemaDraft04} |
|
|
158
177
|
| Draft 6 | `http://json-schema.org/draft-06/schema#` | {JSI::JSONSchemaDraft06} |
|
|
159
178
|
| Draft 7 | `http://json-schema.org/draft-07/schema#` | {JSI::JSONSchemaDraft07} |
|
|
179
|
+
| Draft 2020-12 | `https://json-schema.org/draft/2020-12/schema` | {JSI::JSONSchemaDraft202012} |
|
|
180
|
+
|
|
181
|
+
Caveats:
|
|
182
|
+
|
|
183
|
+
- Regular expressions are interpreted by Ruby's Regexp class, whereas JSON Schema recommends interpreting these as ECMA 262 regular expressions. Certain expressions behave differently, particularly `^` and `$`.
|
|
184
|
+
- The `format` keyword does not perform validation. This may be implemented in the future.
|
|
185
|
+
- Draft 2020-12: `$schema` has no effect except at the document root ([#341](https://github.com/notEthan/jsi/issues/341))
|
|
186
|
+
- Draft 7: Keywords `contentMediaType` and `contentEncoding` do not perform validation.
|
|
187
|
+
- Draft 4: `$ref` is only used as a reference from schemas - it will not be followed when used on objects that are not schemas. This is consistent with specifications since Draft 4, but in Draft 4 the [JSON Reference](https://datatracker.ietf.org/doc/html/draft-pbryan-zyp-json-ref-03) specification would allow `$ref` to be used anywhere. JSI does not do this.
|
|
160
188
|
|
|
161
189
|
## JSI and Object Oriented Programming
|
|
162
190
|
|
|
@@ -190,9 +218,9 @@ bill['name']
|
|
|
190
218
|
|
|
191
219
|
For `#name` and `#name=`, we're overriding existing accessor methods. note the use of `super` - this invokes the accessor methods defined by JSI which these override. You could alternatively use `self['name']` and `self['name']=` in these methods, with the same effect as `super`.
|
|
192
220
|
|
|
193
|
-
Working with subschemas is just about as easy as with root schemas.
|
|
221
|
+
Working with subschemas to add methods is just about as easy as with root schemas.
|
|
194
222
|
|
|
195
|
-
You can
|
|
223
|
+
You can use `#[]` or property accessors on a JSI schema module to refer to the schema modules of its subschemas, e.g.:
|
|
196
224
|
|
|
197
225
|
```ruby
|
|
198
226
|
Contact.properties['phone'].items
|
|
@@ -211,8 +239,7 @@ bill.phone.first.number_with_dashes
|
|
|
211
239
|
# => "5-5-5"
|
|
212
240
|
```
|
|
213
241
|
|
|
214
|
-
A recommended convention for naming subschemas is to define them in the namespace of the module of their
|
|
215
|
-
parent schema. The module can then be opened to add methods to the subschema's module.
|
|
242
|
+
A recommended convention for naming subschemas is to define them in the namespace of the module of their parent schema. The module can then be opened to add methods to the subschema's module.
|
|
216
243
|
|
|
217
244
|
```ruby
|
|
218
245
|
module Contact
|
|
@@ -240,31 +267,31 @@ end
|
|
|
240
267
|
|
|
241
268
|
The classes used to instantiate JSIs are dynamically generated subclasses of JSI::Base which include the JSI Schema Module of each schema describing the given instance. These are mostly intended to be ignored: applications aren't expected to instantiate these directly (rather, `#new_jsi` on a Schema or Schema Module is intended), and they are not intended for subclassing or method definition (applications should instead define methods on a schema's {JSI::Schema#jsi_schema_module}).
|
|
242
269
|
|
|
270
|
+
## Mutability
|
|
271
|
+
|
|
272
|
+
JSI instances are immutable by default. Mutable JSIs may be instantiated using the `mutable` param of `new_jsi`. Immutable JSIs are much more performant, because mutation may change what schemas apply to nodes in a document, and checking for that is costly. It is not recommended to instantiate large documents as mutable; their JSI instances become unusably slow.
|
|
273
|
+
|
|
274
|
+
If you are parsing with JSON.parse or YAML.load, it is recommended to pass the `freeze: true` option to these, which lets JSI skip making a frozen copy.
|
|
275
|
+
|
|
243
276
|
## Registration
|
|
244
277
|
|
|
245
|
-
In order for references across documents (generally from a `$ref` schema keyword) to resolve, JSI provides a registry (a {JSI::
|
|
278
|
+
In order for references across documents (generally from a `$ref` schema keyword) to resolve, JSI provides a registry (a {JSI::Registry}) which associates URIs with schemas (or resources containing schemas). The default registry is accessible on {JSI.registry}.
|
|
246
279
|
|
|
247
|
-
Schemas instantiated with `.new_schema`, and their subschemas, are by default registered with `JSI.
|
|
280
|
+
Schemas instantiated with `.new_schema`, and their subschemas, are by default registered with `JSI.registry` if they are identified by an absolute URI. This can be controlled by the `register` param and `registry` configuration.
|
|
248
281
|
|
|
249
|
-
Schemas can automatically be lazily loaded by registering a block which instantiates them with {JSI::
|
|
282
|
+
Schemas can automatically be lazily loaded by registering a block which instantiates them with {JSI::Registry#autoload_uri} (see its documentation).
|
|
250
283
|
|
|
251
284
|
## Validation
|
|
252
285
|
|
|
253
286
|
JSI implements all required features, and many optional features, for validation according to supported JSON Schema specifications. To validate instances, see methods {JSI::Base#jsi_validate}, {JSI::Base#jsi_valid?}, {JSI::Schema#instance_validate}, {JSI::Schema#instance_valid?}.
|
|
254
287
|
|
|
255
|
-
|
|
288
|
+
## Meta-Schemas
|
|
256
289
|
|
|
257
|
-
-
|
|
258
|
-
- Regular expressions are interpreted by Ruby's Regexp class, whereas JSON Schema recommends interpreting these as ECMA 262 regular expressions. Certain expressions behave differently, particularly `^` and `$`.
|
|
259
|
-
- Keywords `contentMediaType` and `contentEncoding` do not perform validation.
|
|
260
|
-
|
|
261
|
-
## Metaschemas
|
|
290
|
+
A meta-schema is a schema that describes schemas. Likewise, a schema is an instance of a meta-schema.
|
|
262
291
|
|
|
263
|
-
|
|
292
|
+
In JSI, a schema is generally a JSI::Base instance whose schemas include a meta-schema.
|
|
264
293
|
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
A self-descriptive metaschema - most commonly one of the JSON schema draft metaschemas - is an object whose schemas include itself. This is instantiated in JSI as a JSI::MetaschemaNode, a special subclass of JSI::Base.
|
|
294
|
+
A self-descriptive meta-schema - most commonly one of the JSON schema draft meta-schemas - is an object whose schemas include itself. This is instantiated in JSI as a JSI::MetaSchemaNode, a special subclass of JSI::Base.
|
|
268
295
|
|
|
269
296
|
## ActiveRecord serialization
|
|
270
297
|
|
|
@@ -272,7 +299,7 @@ A really excellent place to use JSI is when dealing with serialized columns in A
|
|
|
272
299
|
|
|
273
300
|
Let's say you're sticking to JSON types in the database - you have to do so if you're using JSON columns, or JSON serialization, and if you have dealt with arbitrary yaml- or marshal-serialized objects in ruby, you have probably found that approach has its shortcomings when the implementation of your classes changes.
|
|
274
301
|
|
|
275
|
-
But if your database contains JSON, then your deserialized objects in ruby are likewise Hash / Array /
|
|
302
|
+
But if your database contains JSON, then your deserialized objects in ruby are likewise Hash / Array / simple types. You have to use `#[]` instead of accessors, and you don't have any way to add methods to your data types.
|
|
276
303
|
|
|
277
304
|
JSI gives you the best of both with {JSI::JSICoder}. This coder dumps objects which are simple JSON types, and loads instances of a specified JSON Schema. Here's an example, supposing a `users` table with a JSON column `contact_info` to be instantiated using the `Contact` schema module defined in the Example section above:
|
|
278
305
|
|
|
@@ -282,13 +309,30 @@ class User < ActiveRecord::Base
|
|
|
282
309
|
end
|
|
283
310
|
```
|
|
284
311
|
|
|
285
|
-
Now `user.contact_info` will be instantiated as a `Contact` JSI instance, from the JSON type in the database, with Contact's accessors, validations, and
|
|
312
|
+
Now `user.contact_info` will be instantiated as a `Contact` JSI instance, from the JSON type in the database, with Contact's accessors, validations, and application-defined instance methods.
|
|
286
313
|
|
|
287
314
|
See the gem [`arms`](https://github.com/notEthan/arms) if you wish to serialize the dumped JSON-compatible objects further as text.
|
|
288
315
|
|
|
289
|
-
##
|
|
316
|
+
## Hash keys (JSON Object property names)
|
|
317
|
+
|
|
318
|
+
For JSI instances containing Hashes, their keys should be strings. Hashes keyed with symbols are popular in Ruby, but this is not compatible with JSON.
|
|
319
|
+
|
|
320
|
+
JSI generally does not accommodate symbol keys. However, the syntax for Hash literals with symbol keys (`key: "value"` or `"key": "value"` rather than `"key" => "value"`) conveniently resembles JSON such that you can often paste JSON right into your Ruby (apart from Ruby's `nil` vs JSON's `null`). To enable this, JSI offers key conversion on instantiation: methods `new_jsi` and `new_schema` take a boolean param `stringify_symbol_keys` to recursively convert. This _only_ affects instantiation - no key conversion is done once the JSI has been initialized, e.g. by {JSI::Base#[]} or any methods of {JSI::Base::HashNode}.
|
|
321
|
+
|
|
322
|
+
```ruby
|
|
323
|
+
# instantiate schema s and instance j, converting keys
|
|
324
|
+
s = JSI.new_schema(
|
|
325
|
+
# valid JSON
|
|
326
|
+
{
|
|
327
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
328
|
+
"type": "array"
|
|
329
|
+
},
|
|
330
|
+
stringify_symbol_keys: true,
|
|
331
|
+
)
|
|
332
|
+
j = s.new_jsi([{"foo": "bar"}, {"foo": "baz"}], stringify_symbol_keys: true)
|
|
333
|
+
```
|
|
290
334
|
|
|
291
|
-
|
|
335
|
+
Third party libraries such as [ActiveSupport::HashWithIndifferentAccess](https://api.rubyonrails.org/classes/ActiveSupport/HashWithIndifferentAccess.html) or [Hashie](https://github.com/hashie/hashie) with [IndifferentAccess](https://github.com/hashie/hashie#indifferentaccess) exist to make symbol keys interchangeable with string keys. A JSI can be instantiated with an indifferent Hash as its content, but there will be various inconsistencies when accessing values with a string vs a symbol, and this is not recommended or supported.
|
|
292
336
|
|
|
293
337
|
## Contributing
|
|
294
338
|
|
|
@@ -296,7 +340,7 @@ Issues and pull requests are welcome on GitHub at https://github.com/notEthan/js
|
|
|
296
340
|
|
|
297
341
|
## License
|
|
298
342
|
|
|
299
|
-
[<img align="right" src="https://
|
|
343
|
+
[<img align="right" src="https://www.gnu.org/graphics/agplv3-155x51.png">](https://www.gnu.org/licenses/agpl-3.0.html)
|
|
300
344
|
|
|
301
345
|
JSI is licensed under the terms of the [GNU Affero General Public License version 3](https://www.gnu.org/licenses/agpl-3.0.html).
|
|
302
346
|
|
|
@@ -24,18 +24,16 @@ The terminology from these can be contradictory, e.g. 'object' in JSON meaning w
|
|
|
24
24
|
[JSI]: #JSI
|
|
25
25
|
[a JSI]: #JSI
|
|
26
26
|
|
|
27
|
-
JSI is the name of this library. As a [countable](https://en.wikipedia.org/wiki/Count_noun), "a JSI" refers to the library's instantiation of an instance
|
|
28
|
-
|
|
29
|
-
The subclass of JSI::Base which a JSI is instantiated as includes the [schema module] of each schema that describes the instance (its {JSI::Base#jsi_schemas}), as well as type-specific modules for [array] and [hash/object] instances.
|
|
27
|
+
JSI is the name of this library. As a [countable](https://en.wikipedia.org/wiki/Count_noun), "a JSI" refers to the library's instantiation of an instance described by a set of [schema]s. This is a Ruby instance of {JSI::Base}, and also an instance of the [schema module] belonging to each schema that describes it (its {JSI::Base#jsi_schemas}).
|
|
30
28
|
|
|
31
29
|
|
|
32
30
|
- ### node
|
|
33
31
|
|
|
34
32
|
[node]: #node
|
|
35
33
|
|
|
36
|
-
A node is
|
|
34
|
+
A node is part of a [document] at a location identified by a [pointer].
|
|
37
35
|
|
|
38
|
-
In JSI a node generally means [a JSI] - a JSI::Base instance is often referred to just as "a JSI", but is referred to as a node in the context of its relationship to other nodes in its document.
|
|
36
|
+
In JSI a node generally means [a JSI] - a {JSI::Base} instance is often referred to just as "a JSI", but is referred to as a node in the context of its relationship to other nodes in its document.
|
|
39
37
|
|
|
40
38
|
|
|
41
39
|
- ### node content
|
|
@@ -70,31 +68,20 @@ The terminology from these can be contradictory, e.g. 'object' in JSON meaning w
|
|
|
70
68
|
See {JSI::Base#jsi_root_node}.
|
|
71
69
|
|
|
72
70
|
|
|
73
|
-
- ### complex
|
|
74
|
-
|
|
75
|
-
[complex]: #complex
|
|
76
|
-
|
|
77
|
-
A [node] that can have [child]ren is complex. Its [content] is an [array] or a [hash/object].
|
|
78
|
-
|
|
79
|
-
Hash and Array nodes can mostly be used like Ruby Hashes and Arrays. JSI defines or delegates the methods of Hash and Array with nearly perfect compatibility, and supports [implicit conversion](https://docs.ruby-lang.org/en/master/implicit_conversion_rdoc.html) with `#to_hash` and `#to_ary`.
|
|
80
|
-
|
|
81
|
-
These nodes also support implicit conversion for the instance's content, treating any object responding to `#to_hash` or `#to_ary` like Hash or Array - though it is most common that actual Hash and Array instances will be the content. (This support may be incomplete for node content that is implicitly convertible but does not respond to certain methods, especially `#[]`.)
|
|
82
|
-
|
|
83
|
-
|
|
84
71
|
- ### child
|
|
85
72
|
|
|
86
73
|
[child]: #child
|
|
87
74
|
|
|
88
75
|
A [node] immediately below another node, its [parent]. Identified by one [token] relative to the parent.
|
|
89
76
|
|
|
90
|
-
See {JSI::Base#[]}.
|
|
77
|
+
See {JSI::Base#[]} and {JSI::Base#jsi_child_node}.
|
|
91
78
|
|
|
92
79
|
|
|
93
80
|
- ### parent
|
|
94
81
|
|
|
95
82
|
[parent]: #parent
|
|
96
83
|
|
|
97
|
-
A [node] immediately above some number of other nodes, its [child]ren.
|
|
84
|
+
A [node] immediately above some number of other nodes, its [child]ren. Only a [hash/object] or [array] can be a parent.
|
|
98
85
|
|
|
99
86
|
See {JSI::Base#jsi_parent_node}.
|
|
100
87
|
|
|
@@ -112,7 +99,7 @@ The terminology from these can be contradictory, e.g. 'object' in JSON meaning w
|
|
|
112
99
|
|
|
113
100
|
[ancestor]: #ancestor
|
|
114
101
|
|
|
115
|
-
A [node]
|
|
102
|
+
A [node] above any number of other nodes, its [descendent]s. A node is considered to be an ancestor of itself, and the [root] node is an ancestor of every node in the [document].
|
|
116
103
|
|
|
117
104
|
See {JSI::Base#jsi_ancestor_nodes}.
|
|
118
105
|
|
|
@@ -121,7 +108,7 @@ The terminology from these can be contradictory, e.g. 'object' in JSON meaning w
|
|
|
121
108
|
|
|
122
109
|
[token]: #token
|
|
123
110
|
|
|
124
|
-
An [array] [index] or [hash/object] [property name
|
|
111
|
+
An [array] [index] or [hash/object] [key/property name] that identifies a child node of its parent. Generally a String or non-negative Integer. [JSON Pointer](https://www.rfc-editor.org/rfc/rfc6901) calls this a "reference token".
|
|
125
112
|
|
|
126
113
|
A sequence of tokens comprises a [pointer].
|
|
127
114
|
|
|
@@ -134,28 +121,36 @@ The terminology from these can be contradictory, e.g. 'object' in JSON meaning w
|
|
|
134
121
|
|
|
135
122
|
[JSON Pointers](https://www.rfc-editor.org/rfc/rfc6901) are parsed to JSI pointers.
|
|
136
123
|
|
|
137
|
-
A pointer may be referred to as 'absolute' when identifying a descendent of the root node (see {JSI::Base#jsi_ptr}), or 'relative' identifying a descendent of any node (such as the pointer passed to {JSI::Base#jsi_descendent_node}).
|
|
124
|
+
A pointer may be referred to as 'absolute' when identifying a descendent of the root node (see {JSI::Base#jsi_ptr}), or 'relative' identifying a descendent of any ancestor node (such as the pointer passed to {JSI::Base#jsi_descendent_node}).
|
|
138
125
|
|
|
139
126
|
|
|
140
127
|
- ### hash/object
|
|
141
128
|
|
|
142
129
|
[hash/object]: #hash_object
|
|
143
130
|
|
|
144
|
-
|
|
131
|
+
In JSON, an object; in Ruby, a Hash, or something [implicitly convertible](https://docs.ruby-lang.org/en/master/implicit_conversion_rdoc.html) with `#to_hash`.
|
|
132
|
+
|
|
133
|
+
In JSI, a [node] whose content is a Hash/`#to_hash`, and which is a {JSI::Base::HashNode}). These nodes are largely used as one would use a Hash, aiming to replicate Hash's API, as well being implicitly convertible with `#to_hash`.
|
|
134
|
+
|
|
135
|
+
A hash/object has [child] nodes on each [key/property name].
|
|
145
136
|
|
|
146
137
|
|
|
147
138
|
- ### array
|
|
148
139
|
|
|
149
140
|
[array]: #array
|
|
150
141
|
|
|
151
|
-
|
|
142
|
+
In JSON, an array; in Ruby, an Array, or something [implicitly convertible](https://docs.ruby-lang.org/en/master/implicit_conversion_rdoc.html) with `#to_ary`.
|
|
143
|
+
|
|
144
|
+
In JSI, a [node] whose content is an Array/`#to_ary`, and which is a {JSI::Base::ArrayNode}). These nodes are largely used as one would use an Array, aiming to replicate Array's API, as well being implicitly convertible with `#to_ary`.
|
|
145
|
+
|
|
146
|
+
An array has [child] nodes on each [index].
|
|
152
147
|
|
|
153
148
|
|
|
154
|
-
- ### property name
|
|
149
|
+
- ### key/property name
|
|
155
150
|
|
|
156
|
-
[property name
|
|
151
|
+
[key/property name]: #key_property_name
|
|
157
152
|
|
|
158
|
-
A [token] identifying a [child] of a [hash/object] [node]. In Ruby, a Hash key; in JSON Schema, an object property name. Property names are
|
|
153
|
+
A [token] identifying a [child] of a [hash/object] [node]. In Ruby, a Hash key; in JSON Schema, an object property name. Property names are always strings in JSON. Note that symbols are not compatible and generally should not be used.
|
|
159
154
|
|
|
160
155
|
Property names can be described by schemas (using the `propertyNames` keyword), and can be JSI instances of those schemas. See {JSI::Base::HashNode#jsi_each_propertyName}.
|
|
161
156
|
|
|
@@ -164,7 +159,7 @@ The terminology from these can be contradictory, e.g. 'object' in JSON meaning w
|
|
|
164
159
|
|
|
165
160
|
[index]: #index
|
|
166
161
|
|
|
167
|
-
A [token] identifying a [child] of an [array] [node]. A non-negative integer.
|
|
162
|
+
A [token] identifying a [child] of an [array] [node]. A non-negative integer. This may be represented in string form in a [pointer].
|
|
168
163
|
|
|
169
164
|
|
|
170
165
|
- ### instance
|
|
@@ -173,18 +168,18 @@ The terminology from these can be contradictory, e.g. 'object' in JSON meaning w
|
|
|
173
168
|
|
|
174
169
|
A heavily-overloaded term. Context should make it clear in what sense it is being used. 'Instance' can refer to an *object* or a *relationship*, in Ruby or JSON Schema or JSI instantiation:
|
|
175
170
|
|
|
176
|
-
- JSON Schema: the
|
|
177
|
-
- Ruby: the
|
|
178
|
-
- JSI: the
|
|
171
|
+
- JSON Schema: the *instance* (JSON data) is an *instance* (relationship) of JSON Schemas that describe it
|
|
172
|
+
- Ruby: the *instance* (an Object) is an *instance* (relationship) of a Class and included Modules
|
|
173
|
+
- JSI: the *instance* ([a JSI]) is an *instance* (relationship) of [JSI Schemas][schema]
|
|
179
174
|
|
|
180
|
-
These all operate in parallel in JSI: a JSI instance represents a JSON instance, it is described by JSI Schemas which represent JSON Schemas, and it is a Ruby instance of [JSI Schema Modules][schema module] of
|
|
175
|
+
These all operate in parallel in JSI: a JSI instance represents a JSON instance, it is described by JSI Schemas which represent JSON Schemas, and it is a Ruby instance of the [JSI Schema Modules][schema module] of the schemas that describe it.
|
|
181
176
|
|
|
182
177
|
|
|
183
178
|
- ### schema
|
|
184
179
|
|
|
185
180
|
[schema]: #schema
|
|
186
181
|
|
|
187
|
-
A JSI Schema is [a JSI] that represents a JSON Schema. It is a Ruby instance of the module {JSI::Schema}.
|
|
182
|
+
A JSI Schema is [a JSI] that represents a JSON Schema. It is a Ruby instance of {JSI::Base} and the module {JSI::Schema}.
|
|
188
183
|
|
|
189
184
|
A schema describes a set of [instance]s. Any JSI instance that is described by a given schema is a Ruby instance of that schema's [schema module].
|
|
190
185
|
|
|
@@ -195,7 +190,7 @@ The terminology from these can be contradictory, e.g. 'object' in JSON meaning w
|
|
|
195
190
|
|
|
196
191
|
[schema module]: #schema_module
|
|
197
192
|
|
|
198
|
-
A JSI Schema Module is a Ruby module associated with a particular [schema]. Any JSI
|
|
193
|
+
A JSI Schema Module is a Ruby module associated with a particular [schema]. Any JSI instance that is described by that schema is a Ruby instance of the schema's schema module. This is a {JSI::SchemaModule}.
|
|
199
194
|
|
|
200
195
|
See {JSI::Schema#jsi_schema_module}.
|
|
201
196
|
|
|
@@ -208,13 +203,49 @@ The terminology from these can be contradictory, e.g. 'object' in JSON meaning w
|
|
|
208
203
|
|
|
209
204
|
A meta-schema is a [schema] that describes schemas, i.e. [instance]s of the meta-schema are schemas.
|
|
210
205
|
|
|
211
|
-
As with any other instance, a JSI schema
|
|
206
|
+
As with any other JSI instance, a JSI schema is an instance of the [schema module] of the meta-schema that describes it. The meta-schema's schema module defines the functionality for its instances to behave as schemas. It includes the module {JSI::Schema}.
|
|
212
207
|
|
|
213
|
-
A meta-schema is described by a meta-schema, which may be itself or another meta-schema. Examples of self-describing meta-schemas are the JSON Schema meta-schemas. An example of the latter is the [schema describing the OpenAPI v3.0 Schema object](https://github.com/OAI/OpenAPI-Specification/blob/3.0.3/schemas/v3.0/schema.yaml#L203), which describes schemas in OpenAPI documents, but is itself described by JSON Schema draft
|
|
208
|
+
A meta-schema is described by a meta-schema, which may be itself or another meta-schema. Examples of self-describing meta-schemas are the JSON Schema meta-schemas. An example of the latter is the [schema describing the OpenAPI v3.0 Schema object](https://github.com/OAI/OpenAPI-Specification/blob/3.0.3/schemas/v3.0/schema.yaml#L203), which describes schemas in OpenAPI documents, but is itself described by the JSON Schema draft-04 meta-schema.
|
|
214
209
|
|
|
215
210
|
A self-describing meta-schema is a Ruby instance of its own schema module.
|
|
216
211
|
|
|
217
|
-
|
|
212
|
+
A meta-schema has a [dialect] that defines the functionality of the schemas it describes.
|
|
213
|
+
|
|
214
|
+
In JSI, a meta-schema is a {JSI::Base} that is a {JSI::Schema::MetaSchema}. Its schema module is a {JSI::SchemaModule::MetaSchemaModule}, and includes {JSI::Schema}. See also {JSI::Schema#describes_schema?} and {JSI::Schema#describes_schema!}.
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
- ### dialect
|
|
218
|
+
|
|
219
|
+
[dialect]: #dialect
|
|
220
|
+
|
|
221
|
+
A dialect defines all the keywords of a JSON Schema, how they operate, and any other aspects of schema behavior. It consists of a set of one or more [vocabularies][vocabulary]. Note that while not all specifications of dialects use the terms 'dialect' or 'vocabulary', JSI uses these abstractions for all supported specifications.
|
|
222
|
+
|
|
223
|
+
Examples of dialects include:
|
|
224
|
+
- Each published JSON Schema specification
|
|
225
|
+
- variants of JSON Schema defined by OpenAPI 2.x and 3.x
|
|
226
|
+
- custom dialects composed of vocabularies specified using the `$vocabulary` keyword
|
|
227
|
+
|
|
228
|
+
A dialect defines some or all of:
|
|
229
|
+
|
|
230
|
+
- a set of keywords
|
|
231
|
+
- those keywords' behavior and interactions with other keywords
|
|
232
|
+
- non-keyword behaviors of a schema (e.g. boolean schemas)
|
|
233
|
+
- division of keywords into vocabularies
|
|
234
|
+
- how vocabularies operate
|
|
235
|
+
- a meta-schema that describes/validates instances of the schema the dialect defines
|
|
236
|
+
|
|
237
|
+
Represented as a {JSI::Schema::Dialect}.
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
- ### vocabulary
|
|
241
|
+
|
|
242
|
+
[vocabulary]: #vocabulary
|
|
243
|
+
|
|
244
|
+
A vocabulary is one part of a [dialect]'s definition of schema keywords and behaviors. Dialects are composed of one or more vocabularies.
|
|
245
|
+
|
|
246
|
+
A dialect whose specification does not define vocabularies is implemented using one vocabulary. Vocabularies were not defined for JSON Schema up to draft 07.
|
|
247
|
+
|
|
248
|
+
Represented as a {JSI::Schema::Vocabulary}.
|
|
218
249
|
|
|
219
250
|
|
|
220
251
|
- ### resource
|
|
@@ -223,27 +254,27 @@ The terminology from these can be contradictory, e.g. 'object' in JSON meaning w
|
|
|
223
254
|
|
|
224
255
|
A resource, or schema resource, is either:
|
|
225
256
|
|
|
226
|
-
- A [schema] that is identified by an absolute URI (declared with an id keyword)
|
|
257
|
+
- A [schema] that is identified by an absolute URI (typically declared with an id keyword)
|
|
227
258
|
- The root of a document containing schemas, whether or not the root is itself a schema. (Technically the root of any document can be considered a resource, but it is only useful when the document contains schemas.)
|
|
228
259
|
|
|
229
|
-
|
|
260
|
+
For a given node, its *resource root* is the nearest ancestor that is a resource - this is distinct from the [root] node of the whole document.
|
|
230
261
|
|
|
231
262
|
Relative URIs and [pointer]s used by a schema (e.g. in `$ref` or `$id`) are resolved relative to its resource root and that resource's id.
|
|
232
263
|
|
|
233
|
-
See {JSI::Schema#schema_resource_root}
|
|
264
|
+
See {JSI::Schema#schema_resource_root}.
|
|
234
265
|
|
|
235
266
|
|
|
236
267
|
- ### schema application
|
|
237
268
|
|
|
238
269
|
[schema application]: #schema_application
|
|
239
270
|
|
|
240
|
-
The computation of
|
|
271
|
+
The computation of the [schema]s that apply describing a particular [node]. This involves resolving `$ref`s, choosing what conditional schemas apply (e.g. which subschema of a `oneOf` applies), and recursing down children applying child applicator schemas. The steps of this process:
|
|
241
272
|
|
|
242
273
|
- **root indicated schemas**: Application begins with the schemas (usually just one schema) indicated as describing the [root]. `#new_jsi` is invoked on a {JSI::SchemaSet} of the indicated schemas, or more commonly on one schema or [schema module]. These are the root's {JSI::Base#jsi_indicated_schemas}.
|
|
243
|
-
- **root applied schemas**: [in-place application] is performed on each of the root indicated schemas to compute its applied schemas
|
|
274
|
+
- **root applied schemas**: [in-place application] is performed on each of the root's indicated schemas to compute its applied schemas.
|
|
244
275
|
- Descending from the root to the given node, for each [token] of the node's [pointer]:
|
|
245
276
|
- **child indicated schemas**: [child application] is performed on each applied schema of the parent on the current token. This results in the child's indicated schemas.
|
|
246
|
-
- **child applied schemas**: [in-place application] is performed on each child indicated
|
|
277
|
+
- **child applied schemas**: [in-place application] is performed on each of the child's indicated schemas to compute its applied schemas.
|
|
247
278
|
|
|
248
279
|
The schemas that apply describing the node are the result of the final in-place application.
|
|
249
280
|
|
|
@@ -252,30 +283,31 @@ The terminology from these can be contradictory, e.g. 'object' in JSON meaning w
|
|
|
252
283
|
|
|
253
284
|
[child application]: #child_application
|
|
254
285
|
|
|
255
|
-
The computation of subschemas of a given schema that
|
|
286
|
+
The computation of subschemas of a given schema that describe a [child] of an instance on a given [token]. These come from subschemas defined on child applicator keywords such as `properties` and `items`. The result may be an empty schema set if no such keywords are present or none apply.
|
|
256
287
|
|
|
257
288
|
|
|
258
289
|
- ### in-place application
|
|
259
290
|
|
|
260
291
|
[in-place application]: #in_place_application
|
|
261
292
|
|
|
262
|
-
The
|
|
293
|
+
The expansion of a schema to a set of **applied schemas** for a given instance. "In-place" means all the schemas apply to the same location in the instance, in contrast to [child application]. This is a recursive process.
|
|
263
294
|
|
|
264
|
-
- If the schema contains a `$ref` keyword:
|
|
265
|
-
- The reference is resolved
|
|
266
|
-
-
|
|
267
|
-
-
|
|
295
|
+
- If the schema contains a `$ref` keyword, *and* the specification for the schema is draft-07 or older:
|
|
296
|
+
- The reference is resolved.
|
|
297
|
+
- In-place application recurses on the resolved schema.
|
|
298
|
+
- The rest of the schema is ignored. The schema does not apply itself, and any other applicator keywords are ignored (none should be present).
|
|
268
299
|
|
|
269
|
-
The resulting applied schemas are
|
|
300
|
+
The resulting applied schemas are the resolved schema's in-place applicator schemas.
|
|
270
301
|
|
|
271
302
|
- Otherwise:
|
|
272
303
|
- The schema applies itself (it is added to the set of applied schemas).
|
|
273
|
-
- Any in-place applicator keywords (`anyOf`, `dependencies`, etc.) are evaluated for subschemas that apply to the instance.
|
|
304
|
+
- Any in-place applicator keywords (`anyOf`, `dependencies`, etc.) are evaluated for subschemas that apply to the instance. References are resolved from `$ref` or `$dynamicRef`, if present. For each such schema, in-place application recurses.
|
|
305
|
+
|
|
306
|
+
The resulting applied schemas consist of each recursively applied in-place applicator schema.
|
|
274
307
|
|
|
275
|
-
The resulting applied schemas are the given schema plus the results of in-place application of each applicable subschema.
|
|
276
308
|
|
|
277
309
|
- ### validation
|
|
278
310
|
|
|
279
311
|
[validation]: #validation
|
|
280
312
|
|
|
281
|
-
The process of determining whether a given [instance] is valid against the [schema]s that describe it, or collecting validation errors indicating why the instance is not valid. See {JSI::Base#jsi_valid?}, {JSI::Base#jsi_validate}, {JSI::Schema#instance_valid?}, {JSI::Schema#instance_validate}
|
|
313
|
+
The process of determining whether a given [instance] is valid against the [schema]s that describe it, or collecting validation errors indicating why the instance is not valid. See {JSI::Base#jsi_valid?}, {JSI::Base#jsi_validate}, {JSI::Base#jsi_valid!}, {JSI::Schema#instance_valid?}, {JSI::Schema#instance_validate}, {JSI::Schema#instance_valid!}.
|
data/jsi.gemspec
CHANGED