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
data/lib/jsi/schema_classes.rb
CHANGED
|
@@ -1,19 +1,93 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module JSI
|
|
4
|
-
#
|
|
5
|
-
class SchemaModule
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
extend SchemaClasses.schema_property_reader_module(schema_schema, conflicting_modules: Set[SchemaModule])
|
|
14
|
-
end
|
|
15
|
-
end
|
|
4
|
+
# class SchemaModule < class SchemaModule::Connection < class Module
|
|
5
|
+
# this unusual configuration of a class (SchemaModule) subclassing a class inside its own
|
|
6
|
+
# namespace (SchemaModule::Connection) follows reconfiguration changing Connection from a regular
|
|
7
|
+
# class to subclass Module, so that a JSI that isn't a Schema can have a named module, and schemas
|
|
8
|
+
# within that JSI's document have a useful name_from_ancestor when inspecting their instances.
|
|
9
|
+
begin # shenanigans to get classes configured while not confusing yard
|
|
10
|
+
SchemaModule = Class.new(Class.new(Module))
|
|
11
|
+
SchemaModule.const_set(:Connection, SchemaModule.superclass)
|
|
12
|
+
end
|
|
16
13
|
|
|
14
|
+
# A Module associated with a JSI Schema (its {Schema#jsi_schema_module #jsi_schema_module}).
|
|
15
|
+
#
|
|
16
|
+
# This module may be opened by the application to define methods for instances described by its schema.
|
|
17
|
+
#
|
|
18
|
+
# The schema module can also be used in some of the same ways as its schema:
|
|
19
|
+
# JSI instances of the schema can be instantiated using {#new_jsi}, or instances
|
|
20
|
+
# can be validated with {#instance_valid?} or {#instance_validate}.
|
|
21
|
+
# Often the schema module is the more convenient object to work with with than the JSI Schema.
|
|
22
|
+
#
|
|
23
|
+
# Naming the schema module (assigning it to a constant) can be useful in a few ways.
|
|
24
|
+
#
|
|
25
|
+
# - When inspected, instances of a schema with a named schema module will show that name.
|
|
26
|
+
# - Naming the module allows it to be opened with Ruby's `module` syntax. Any schema module
|
|
27
|
+
# can be opened with [Module#module_exec](https://ruby-doc.org/core/Module.html#method-i-module_exec)
|
|
28
|
+
# (or from the Schema with {Schema#jsi_schema_module_exec jsi_schema_module_exec})
|
|
29
|
+
# but the `module` syntax can be more convenient, especially for assigning or accessing constants.
|
|
30
|
+
#
|
|
31
|
+
# The schema module makes it straightforward to access the schema modules of the schema's subschemas.
|
|
32
|
+
# It defines readers for schema properties (keywords) on its singleton (that is,
|
|
33
|
+
# called on the module itself, not on instances of it) to access these.
|
|
34
|
+
# The {SchemaModule::Connection#[] #[]} method can also be used.
|
|
35
|
+
#
|
|
36
|
+
# For example, given a schema with an `items` subschema, then `schema.items.jsi_schema_module`
|
|
37
|
+
# and `schema.jsi_schema_module.items` both refer to the same module.
|
|
38
|
+
# Subscripting with {SchemaModule::Connection#[] #[]} can refer to subschemas on properties
|
|
39
|
+
# that can have any name, e.g. `schema.properties['foo'].jsi_schema_module` is the same as
|
|
40
|
+
# `schema.jsi_schema_module.properties['foo']`.
|
|
41
|
+
#
|
|
42
|
+
# Schema module property readers and `#[]` can also take a block, which is passed to `module_exec`.
|
|
43
|
+
#
|
|
44
|
+
# Putting the above together, here is example usage with the schema module of the Contact
|
|
45
|
+
# schema used in the README:
|
|
46
|
+
#
|
|
47
|
+
# ```ruby
|
|
48
|
+
# Contact = JSI.new_schema_module({
|
|
49
|
+
# "$schema" => "http://json-schema.org/draft-07/schema",
|
|
50
|
+
# "type" => "object",
|
|
51
|
+
# "properties" => {
|
|
52
|
+
# "name" => {"type" => "string"},
|
|
53
|
+
# "phone" => {
|
|
54
|
+
# "type" => "array",
|
|
55
|
+
# "items" => {
|
|
56
|
+
# "type" => "object",
|
|
57
|
+
# "properties" => {
|
|
58
|
+
# "location" => {"type" => "string"},
|
|
59
|
+
# "number" => {"type" => "string"}
|
|
60
|
+
# }
|
|
61
|
+
# }
|
|
62
|
+
# }
|
|
63
|
+
# }
|
|
64
|
+
# })
|
|
65
|
+
#
|
|
66
|
+
# module Contact
|
|
67
|
+
# # name a subschema's schema module
|
|
68
|
+
# PhoneNumber = properties['phone'].items
|
|
69
|
+
#
|
|
70
|
+
# # open a subschema's schema module to define methods
|
|
71
|
+
# properties['phone'] do
|
|
72
|
+
# def numbers
|
|
73
|
+
# map(&:number)
|
|
74
|
+
# end
|
|
75
|
+
# end
|
|
76
|
+
# end
|
|
77
|
+
#
|
|
78
|
+
# bill = Contact.new_jsi({"name" => "bill", "phone" => [{"location" => "home", "number" => "555"}]})
|
|
79
|
+
# #> #{<JSI (Contact)>
|
|
80
|
+
# #> "name" => "bill",
|
|
81
|
+
# #> "phone" => #[<JSI (Contact.properties["phone"])>
|
|
82
|
+
# #> #{<JSI (Contact::PhoneNumber)> "location" => "home", "number" => "555"}
|
|
83
|
+
# #> ],
|
|
84
|
+
# #> "nickname" => "big b"
|
|
85
|
+
# #> }
|
|
86
|
+
# ```
|
|
87
|
+
#
|
|
88
|
+
# Note that when `bill` is inspected, schema module names `Contact`, `Contact.properties["phone"]`,
|
|
89
|
+
# and `Contact::PhoneNumber` are informatively shown on respective instances.
|
|
90
|
+
class SchemaModule < SchemaModule::Connection
|
|
17
91
|
# The schema for which this is the JSI Schema Module
|
|
18
92
|
# @return [Base + Schema]
|
|
19
93
|
def schema
|
|
@@ -28,25 +102,28 @@ module JSI
|
|
|
28
102
|
|
|
29
103
|
# @return [String]
|
|
30
104
|
def inspect
|
|
105
|
+
dam_s = " #{schema.jsi_schema_dynamic_anchor_map.anchor_schemas_identifier}" if !schema.jsi_schema_dynamic_anchor_map.empty?
|
|
31
106
|
if name_from_ancestor
|
|
32
|
-
if schema.
|
|
33
|
-
-"#{name_from_ancestor} <#{schema.
|
|
107
|
+
if schema.jsi_resource_uri
|
|
108
|
+
-"#{name_from_ancestor} <#{schema.jsi_resource_uri}>#{dam_s} (JSI Schema Module)"
|
|
34
109
|
else
|
|
35
|
-
-"#{name_from_ancestor} (JSI Schema Module)"
|
|
110
|
+
-"#{name_from_ancestor}#{dam_s} (JSI Schema Module)"
|
|
36
111
|
end
|
|
37
112
|
else
|
|
38
|
-
-"(JSI Schema Module: #{schema.schema_uri || schema.jsi_ptr.uri})"
|
|
113
|
+
-"(JSI Schema Module: #{schema.schema_uri || schema.jsi_ptr.uri}#{dam_s})"
|
|
39
114
|
end
|
|
40
115
|
end
|
|
41
116
|
|
|
42
|
-
|
|
117
|
+
def to_s
|
|
118
|
+
inspect
|
|
119
|
+
end
|
|
43
120
|
|
|
44
|
-
# invokes {JSI::Schema#new_jsi} on this module's schema, passing the given
|
|
121
|
+
# invokes {JSI::Schema#new_jsi} on this module's schema, passing the given parameters.
|
|
45
122
|
#
|
|
46
|
-
# @
|
|
47
|
-
#
|
|
48
|
-
# inplace applicators of this module's schema.
|
|
123
|
+
# @return [Base] a JSI whose content comes from the given instance and whose schemas are
|
|
124
|
+
# in-place applicators of this module's schema.
|
|
49
125
|
def new_jsi(instance, **kw)
|
|
126
|
+
raise(BlockGivenError) if block_given?
|
|
50
127
|
schema.new_jsi(instance, **kw)
|
|
51
128
|
end
|
|
52
129
|
|
|
@@ -64,35 +141,47 @@ module JSI
|
|
|
64
141
|
def instance_valid?(instance)
|
|
65
142
|
schema.instance_valid?(instance)
|
|
66
143
|
end
|
|
144
|
+
|
|
145
|
+
# See {Schema#describes_schema!}
|
|
146
|
+
def describes_schema!(dialect = nil)
|
|
147
|
+
schema.describes_schema!(dialect)
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
# @private pending stronger stability of dynamic scope
|
|
151
|
+
# See {Schema#with_dynamic_scope_from}
|
|
152
|
+
def with_dynamic_scope_from(node)
|
|
153
|
+
schema.with_dynamic_scope_from(node).jsi_schema_module
|
|
154
|
+
end
|
|
67
155
|
end
|
|
68
156
|
|
|
69
|
-
# A module to extend the {SchemaModule} of a schema which describes other schemas (a {Schema::
|
|
70
|
-
module SchemaModule::
|
|
157
|
+
# A module to extend the {SchemaModule} of a schema which describes other schemas (a {Schema::MetaSchema})
|
|
158
|
+
module SchemaModule::MetaSchemaModule
|
|
71
159
|
# Instantiates the given schema content as a JSI Schema.
|
|
72
160
|
#
|
|
73
|
-
#
|
|
161
|
+
# See {JSI::Schema::MetaSchema#new_schema}.
|
|
74
162
|
#
|
|
75
|
-
# @
|
|
76
|
-
#
|
|
77
|
-
# @return [JSI::Base subclass + JSI::Schema] a JSI which is a {JSI::Schema} whose content comes from
|
|
78
|
-
# the given `schema_content` and whose schemas are inplace applicators of this module's schema
|
|
163
|
+
# @return [Base + Schema] A JSI which is a {Schema} whose content comes from
|
|
164
|
+
# the given `schema_content` and whose schemas are in-place applicators of this module's schema.
|
|
79
165
|
def new_schema(schema_content, **kw, &block)
|
|
80
166
|
schema.new_schema(schema_content, **kw, &block)
|
|
81
167
|
end
|
|
82
168
|
|
|
83
|
-
# (see Schema::
|
|
169
|
+
# (see Schema::MetaSchema#new_schema_module)
|
|
84
170
|
def new_schema_module(schema_content, **kw, &block)
|
|
85
|
-
schema.
|
|
171
|
+
schema.new_schema_module(schema_content, **kw, &block)
|
|
86
172
|
end
|
|
87
173
|
|
|
88
|
-
# @return [
|
|
89
|
-
|
|
174
|
+
# @return [Schema::Dialect]
|
|
175
|
+
def described_dialect
|
|
176
|
+
schema.described_dialect
|
|
177
|
+
end
|
|
90
178
|
end
|
|
91
179
|
|
|
92
180
|
# this module is a namespace for building schema classes and schema modules.
|
|
181
|
+
# @private
|
|
93
182
|
module SchemaClasses
|
|
94
183
|
class << self
|
|
95
|
-
# @
|
|
184
|
+
# @private
|
|
96
185
|
# @return [Set<Module>]
|
|
97
186
|
def includes_for(instance)
|
|
98
187
|
includes = Set[]
|
|
@@ -107,22 +196,28 @@ module JSI
|
|
|
107
196
|
# @api private
|
|
108
197
|
# @param schemas [Enumerable<JSI::Schema>] schemas which the class will represent
|
|
109
198
|
# @param includes [Enumerable<Module>] modules which will be included on the class
|
|
110
|
-
# @return [Class
|
|
111
|
-
def class_for_schemas(schemas, includes: )
|
|
199
|
+
# @return [Class subclass of JSI::Base]
|
|
200
|
+
def class_for_schemas(schemas, includes: , mutable: )
|
|
112
201
|
@class_for_schemas_map[
|
|
113
|
-
|
|
114
|
-
includes:
|
|
202
|
+
schema_modules: schemas.map(&:jsi_schema_module).to_set.freeze,
|
|
203
|
+
includes: includes.to_set.freeze,
|
|
204
|
+
mutable: mutable,
|
|
115
205
|
]
|
|
116
206
|
end
|
|
117
207
|
|
|
118
|
-
private def class_for_schemas_compute(
|
|
208
|
+
private def class_for_schemas_compute(schema_modules: , includes: , mutable: )
|
|
119
209
|
Class.new(Base) do
|
|
210
|
+
schemas = SchemaSet.new(schema_modules.map(&:schema))
|
|
211
|
+
|
|
120
212
|
define_singleton_method(:jsi_class_schemas) { schemas }
|
|
121
213
|
define_method(:jsi_schemas) { schemas }
|
|
122
214
|
|
|
123
215
|
define_singleton_method(:jsi_class_includes) { includes }
|
|
124
216
|
|
|
125
|
-
|
|
217
|
+
mutability_module = mutable ? Base::Mutable : Base::Immutable
|
|
218
|
+
conflicting_modules = Set[JSI::Base, mutability_module] + includes + schema_modules
|
|
219
|
+
|
|
220
|
+
include(mutability_module)
|
|
126
221
|
|
|
127
222
|
reader_modules = schemas.map do |schema|
|
|
128
223
|
JSI::SchemaClasses.schema_property_reader_module(schema, conflicting_modules: conflicting_modules)
|
|
@@ -132,82 +227,38 @@ module JSI
|
|
|
132
227
|
define_method(:jsi_property_readers) { readers }
|
|
133
228
|
define_singleton_method(:jsi_property_readers) { readers }
|
|
134
229
|
|
|
135
|
-
|
|
136
|
-
|
|
230
|
+
if mutable
|
|
231
|
+
writer_modules = schemas.map do |schema|
|
|
232
|
+
JSI::SchemaClasses.schema_property_writer_module(schema, conflicting_modules: conflicting_modules)
|
|
233
|
+
end
|
|
234
|
+
writer_modules.each { |m| include(m) }
|
|
137
235
|
end
|
|
138
|
-
writer_modules.each { |m| include m }
|
|
139
236
|
|
|
140
237
|
includes.each { |m| include(m) }
|
|
141
|
-
|
|
142
|
-
jsi_class = self
|
|
143
|
-
define_method(:jsi_class) { jsi_class }
|
|
144
|
-
|
|
145
|
-
self
|
|
146
|
-
end
|
|
147
|
-
end
|
|
148
|
-
|
|
149
|
-
# a subclass of MetaschemaNode::BootstrapSchema with the given modules included
|
|
150
|
-
# @api private
|
|
151
|
-
# @param modules [Set<Module>] schema implementation modules
|
|
152
|
-
# @return [Class]
|
|
153
|
-
def bootstrap_schema_class(modules)
|
|
154
|
-
@bootstrap_schema_class_map[
|
|
155
|
-
modules: Util.ensure_module_set(modules),
|
|
156
|
-
]
|
|
157
|
-
end
|
|
158
|
-
|
|
159
|
-
private def bootstrap_schema_class_compute(modules: )
|
|
160
|
-
Class.new(MetaschemaNode::BootstrapSchema) do
|
|
161
|
-
define_singleton_method(:schema_implementation_modules) { modules }
|
|
162
|
-
define_method(:schema_implementation_modules) { modules }
|
|
163
|
-
modules.each { |mod| include(mod) }
|
|
164
|
-
|
|
165
|
-
self
|
|
238
|
+
schema_modules.to_a.reverse_each { |m| include(m) }
|
|
166
239
|
end
|
|
167
240
|
end
|
|
168
241
|
|
|
169
|
-
# see {Schema#jsi_schema_module}
|
|
170
|
-
# @api private
|
|
171
|
-
# @return [Module + SchemaModule]
|
|
172
|
-
def module_for_schema(schema)
|
|
173
|
-
Schema.ensure_schema(schema)
|
|
174
|
-
raise(Bug, "non-Base schema cannot have schema module: #{schema}") unless schema.is_a?(Base)
|
|
175
|
-
@schema_module_map[schema: schema]
|
|
176
|
-
end
|
|
177
|
-
|
|
178
|
-
private def schema_module_compute(schema: )
|
|
179
|
-
SchemaModule.new(schema)
|
|
180
|
-
end
|
|
181
|
-
|
|
182
|
-
# @deprecated after v0.7
|
|
183
|
-
def accessor_module_for_schema(schema, conflicting_modules: , setters: true)
|
|
184
|
-
Module.new do
|
|
185
|
-
include SchemaClasses.schema_property_reader_module(schema, conflicting_modules: conflicting_modules)
|
|
186
|
-
include SchemaClasses.schema_property_writer_module(schema, conflicting_modules: conflicting_modules) if setters
|
|
187
|
-
end
|
|
188
|
-
end
|
|
189
|
-
|
|
190
242
|
# a module of readers for described property names of the given schema.
|
|
191
243
|
#
|
|
192
|
-
# @
|
|
244
|
+
# @private
|
|
193
245
|
# @param schema [JSI::Schema] a schema for which to define readers for any described property names
|
|
194
246
|
# @param conflicting_modules [Enumerable<Module>] an array of modules (or classes) which
|
|
195
247
|
# may be used alongside the accessor module. methods defined by any conflicting_module
|
|
196
248
|
# will not be defined as accessors.
|
|
197
249
|
# @return [Module]
|
|
198
250
|
def schema_property_reader_module(schema, conflicting_modules: )
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
end
|
|
202
|
-
|
|
203
|
-
private def schema_property_reader_module_compute(schema: , conflicting_modules: )
|
|
204
|
-
Module.new do
|
|
205
|
-
define_singleton_method(:inspect) { '(JSI Schema Property Reader Module)' }
|
|
206
|
-
|
|
207
|
-
readers = schema.described_object_property_names.select do |name|
|
|
251
|
+
@schema_property_reader_module_map[
|
|
252
|
+
schema.described_object_property_names.select do |name|
|
|
208
253
|
Util.ok_ruby_method_name?(name) &&
|
|
209
254
|
!conflicting_modules.any? { |m| m.method_defined?(name) || m.private_method_defined?(name) }
|
|
210
255
|
end.to_set.freeze
|
|
256
|
+
]
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
private def schema_property_reader_module_compute(readers)
|
|
260
|
+
Module.new do
|
|
261
|
+
define_singleton_method(:inspect) { -"(JSI Schema Property Reader Module: #{readers.to_a.join(', ')})" }
|
|
211
262
|
|
|
212
263
|
define_singleton_method(:jsi_property_readers) { readers }
|
|
213
264
|
|
|
@@ -220,21 +271,20 @@ module JSI
|
|
|
220
271
|
end
|
|
221
272
|
|
|
222
273
|
# a module of writers for described property names of the given schema.
|
|
223
|
-
# @
|
|
274
|
+
# @private
|
|
224
275
|
def schema_property_writer_module(schema, conflicting_modules: )
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
end
|
|
228
|
-
|
|
229
|
-
private def schema_property_writer_module_compute(schema: , conflicting_modules: )
|
|
230
|
-
Module.new do
|
|
231
|
-
define_singleton_method(:inspect) { '(JSI Schema Property Writer Module)' }
|
|
232
|
-
|
|
233
|
-
writers = schema.described_object_property_names.select do |name|
|
|
276
|
+
@schema_property_writer_module_map[
|
|
277
|
+
schema.described_object_property_names.select do |name|
|
|
234
278
|
writer = "#{name}="
|
|
235
279
|
Util.ok_ruby_method_name?(name) &&
|
|
236
280
|
!conflicting_modules.any? { |m| m.method_defined?(writer) || m.private_method_defined?(writer) }
|
|
237
281
|
end.to_set.freeze
|
|
282
|
+
]
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
private def schema_property_writer_module_compute(writers)
|
|
286
|
+
Module.new do
|
|
287
|
+
define_singleton_method(:inspect) { -"(JSI Schema Property Writer Module: #{writers.to_a.join(', ')})" }
|
|
238
288
|
|
|
239
289
|
define_singleton_method(:jsi_property_writers) { writers }
|
|
240
290
|
|
|
@@ -248,14 +298,11 @@ module JSI
|
|
|
248
298
|
end
|
|
249
299
|
|
|
250
300
|
@class_for_schemas_map = Hash.new { |h, k| h[k] = class_for_schemas_compute(**k) }
|
|
251
|
-
@
|
|
252
|
-
@
|
|
253
|
-
@schema_property_reader_module_map = Hash.new { |h, k| h[k] = schema_property_reader_module_compute(**k) }
|
|
254
|
-
@schema_property_writer_module_map = Hash.new { |h, k| h[k] = schema_property_writer_module_compute(**k) }
|
|
301
|
+
@schema_property_reader_module_map = Hash.new { |h, k| h[k] = schema_property_reader_module_compute(k) }
|
|
302
|
+
@schema_property_writer_module_map = Hash.new { |h, k| h[k] = schema_property_writer_module_compute(k) }
|
|
255
303
|
end
|
|
256
304
|
|
|
257
|
-
|
|
258
|
-
module SchemaModule::Connects
|
|
305
|
+
class SchemaModule::Connection
|
|
259
306
|
attr_reader :jsi_node
|
|
260
307
|
|
|
261
308
|
# a name relative to a named schema module of an ancestor schema.
|
|
@@ -264,11 +311,11 @@ module JSI
|
|
|
264
311
|
# @api private
|
|
265
312
|
# @return [String, nil]
|
|
266
313
|
def name_from_ancestor
|
|
267
|
-
|
|
268
|
-
return nil unless
|
|
314
|
+
named_ancestor, tokens = named_ancestor_tokens
|
|
315
|
+
return nil unless named_ancestor
|
|
269
316
|
|
|
270
|
-
name =
|
|
271
|
-
ancestor =
|
|
317
|
+
name = named_ancestor.jsi_schema_module_connection.name
|
|
318
|
+
ancestor = named_ancestor
|
|
272
319
|
tokens.each do |token|
|
|
273
320
|
if ancestor.jsi_property_readers.include?(token)
|
|
274
321
|
name += ".#{token}"
|
|
@@ -279,49 +326,53 @@ module JSI
|
|
|
279
326
|
end
|
|
280
327
|
ancestor = ancestor[token]
|
|
281
328
|
end
|
|
282
|
-
name
|
|
329
|
+
name.freeze
|
|
330
|
+
end
|
|
331
|
+
|
|
332
|
+
# See {Base#/} - descendent's {Base#jsi_schema_module_connection}
|
|
333
|
+
# @param (see Base#/)
|
|
334
|
+
# @return [SchemaModule::Connection]
|
|
335
|
+
def /(ptr)
|
|
336
|
+
(jsi_node / ptr).jsi_schema_module_connection
|
|
283
337
|
end
|
|
284
338
|
|
|
285
339
|
# Subscripting a JSI schema module or a {SchemaModule::Connection} will subscript its node, and
|
|
286
340
|
# if the result is a JSI::Schema, return the JSI Schema module of that schema; if it is a JSI::Base,
|
|
287
|
-
# return a SchemaModule::Connection; or if it is another value (a
|
|
341
|
+
# return a SchemaModule::Connection; or if it is another value (a simple type), return that value.
|
|
288
342
|
#
|
|
289
343
|
# @param token [Object]
|
|
290
344
|
# @yield If the token identifies a schema and a block is given,
|
|
291
345
|
# it is evaluated in the context of the schema's JSI schema module
|
|
292
346
|
# using [Module#module_exec](https://ruby-doc.org/core/Module.html#method-i-module_exec).
|
|
293
|
-
# @return [
|
|
347
|
+
# @return [SchemaModule, SchemaModule::Connection, Object]
|
|
294
348
|
def [](token, **kw, &block)
|
|
295
349
|
raise(ArgumentError) unless kw.empty? # TODO remove eventually (keyword argument compatibility)
|
|
350
|
+
@jsi_node.jsi_child_ensure_present(token)
|
|
296
351
|
sub = @jsi_node[token]
|
|
297
352
|
if sub.is_a?(JSI::Schema)
|
|
298
353
|
sub.jsi_schema_module_exec(&block) if block
|
|
299
354
|
sub.jsi_schema_module
|
|
300
355
|
elsif block
|
|
301
|
-
raise(
|
|
356
|
+
raise(BlockGivenError, "block given but token #{token.inspect} does not identify a schema")
|
|
302
357
|
elsif sub.is_a?(JSI::Base)
|
|
303
|
-
|
|
358
|
+
sub.jsi_schema_module_connection
|
|
304
359
|
else
|
|
305
360
|
sub
|
|
306
361
|
end
|
|
307
362
|
end
|
|
308
363
|
|
|
309
|
-
private
|
|
310
|
-
|
|
311
364
|
# @return [Array<JSI::Schema, Array>, nil]
|
|
312
|
-
def
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
365
|
+
private def named_ancestor_tokens
|
|
366
|
+
ancestors = @jsi_node.jsi_ancestor_nodes
|
|
367
|
+
named_ancestor = ancestors.detect do |jsi|
|
|
368
|
+
jsi.jsi_schema_module_connection_defined? && jsi.jsi_schema_module_connection.name
|
|
369
|
+
end
|
|
370
|
+
return nil unless named_ancestor
|
|
371
|
+
tokens = @jsi_node.jsi_ptr.relative_to(named_ancestor.jsi_ptr).tokens
|
|
372
|
+
[named_ancestor, tokens]
|
|
318
373
|
end
|
|
319
374
|
end
|
|
320
375
|
|
|
321
|
-
class SchemaModule
|
|
322
|
-
include Connects
|
|
323
|
-
end
|
|
324
|
-
|
|
325
376
|
# A JSI Schema Module is a module which represents a schema. A SchemaModule::Connection represents
|
|
326
377
|
# a node in a schema's document which is not a schema, such as the 'properties'
|
|
327
378
|
# object (which contains schemas but is not a schema).
|
|
@@ -330,17 +381,18 @@ module JSI
|
|
|
330
381
|
# schema modules to refer to their subschemas' schema modules.
|
|
331
382
|
#
|
|
332
383
|
# A SchemaModule::Connection has readers for property names described by the node's schemas.
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
384
|
+
#
|
|
385
|
+
# This class subclasses Module only so that it can be named, to identify schemas descendent of its node.
|
|
386
|
+
# No object is ever expected to be an instance of a SchemaModule::Connection module.
|
|
387
|
+
class SchemaModule::Connection < Module
|
|
336
388
|
# @param node [JSI::Base]
|
|
337
389
|
def initialize(node)
|
|
338
|
-
|
|
339
|
-
raise(Bug, "node must not be JSI::Schema: #{node.pretty_inspect.chomp}") if node.is_a?(JSI::Schema)
|
|
390
|
+
fail(Bug, "node must be JSI::Base: #{node.pretty_inspect.chomp}") unless node.is_a?(JSI::Base)
|
|
340
391
|
@jsi_node = node
|
|
341
392
|
node.jsi_schemas.each do |schema|
|
|
342
393
|
extend(JSI::SchemaClasses.schema_property_reader_module(schema, conflicting_modules: [SchemaModule::Connection]))
|
|
343
394
|
end
|
|
395
|
+
node.jsi_schema_module_connection_created(self)
|
|
344
396
|
end
|
|
345
397
|
|
|
346
398
|
# @return [String]
|
|
@@ -352,6 +404,8 @@ module JSI
|
|
|
352
404
|
end
|
|
353
405
|
end
|
|
354
406
|
|
|
355
|
-
|
|
407
|
+
def to_s
|
|
408
|
+
inspect
|
|
409
|
+
end
|
|
356
410
|
end
|
|
357
411
|
end
|