jsi 0.8.1 → 0.9.0
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 -2
- data/CHANGELOG.md +9 -0
- data/LICENSE.md +2 -3
- data/README.md +68 -31
- data/docs/Glossary.md +313 -0
- data/jsi.gemspec +1 -0
- data/lib/jsi/base/mutability.rb +4 -0
- data/lib/jsi/base/node.rb +63 -24
- data/lib/jsi/base.rb +556 -173
- data/lib/jsi/metaschema_node/bootstrap_schema.rb +106 -56
- data/lib/jsi/metaschema_node.rb +227 -160
- data/lib/jsi/ptr.rb +32 -15
- 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 +103 -50
- data/lib/jsi/schema/vocabulary.rb +36 -0
- data/lib/jsi/schema.rb +520 -338
- data/lib/jsi/schema_classes.rb +168 -124
- data/lib/jsi/schema_set.rb +67 -126
- data/lib/jsi/set.rb +23 -0
- data/lib/jsi/simple_wrap.rb +13 -16
- 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 +57 -12
- data/lib/jsi/util/typelike.rb +19 -64
- data/lib/jsi/util.rb +52 -34
- data/lib/jsi/validation/error.rb +41 -2
- data/lib/jsi/validation/result.rb +118 -71
- data/lib/jsi/validation.rb +1 -6
- data/lib/jsi/version.rb +1 -1
- data/lib/jsi.rb +158 -41
- data/lib/schemas/json-schema.org/draft/2020-12/schema.rb +67 -0
- data/lib/schemas/json-schema.org/draft-04/schema.rb +63 -106
- data/lib/schemas/json-schema.org/draft-06/schema.rb +56 -105
- data/lib/schemas/json-schema.org/draft-07/schema.rb +67 -124
- data/readme.rb +3 -3
- 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 +70 -48
- 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 -186
- 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 -93
- 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 -200
- data/lib/jsi/util/private/attr_struct.rb +0 -141
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,14 +102,15 @@ 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
|
|
|
@@ -45,10 +120,10 @@ module JSI
|
|
|
45
120
|
|
|
46
121
|
# invokes {JSI::Schema#new_jsi} on this module's schema, passing the given parameters.
|
|
47
122
|
#
|
|
48
|
-
# @
|
|
49
|
-
#
|
|
50
|
-
# 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.
|
|
51
125
|
def new_jsi(instance, **kw)
|
|
126
|
+
raise(BlockGivenError) if block_given?
|
|
52
127
|
schema.new_jsi(instance, **kw)
|
|
53
128
|
end
|
|
54
129
|
|
|
@@ -66,35 +141,44 @@ module JSI
|
|
|
66
141
|
def instance_valid?(instance)
|
|
67
142
|
schema.instance_valid?(instance)
|
|
68
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
|
|
69
155
|
end
|
|
70
156
|
|
|
71
157
|
# A module to extend the {SchemaModule} of a schema which describes other schemas (a {Schema::MetaSchema})
|
|
72
158
|
module SchemaModule::MetaSchemaModule
|
|
73
159
|
# Instantiates the given schema content as a JSI Schema.
|
|
74
160
|
#
|
|
75
|
-
#
|
|
161
|
+
# See {JSI::Schema::MetaSchema#new_schema}.
|
|
76
162
|
#
|
|
77
|
-
# @
|
|
78
|
-
#
|
|
79
|
-
# @return [JSI::Base subclass + JSI::Schema] a JSI which is a {JSI::Schema} whose content comes from
|
|
80
|
-
# 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.
|
|
81
165
|
def new_schema(schema_content, **kw, &block)
|
|
82
166
|
schema.new_schema(schema_content, **kw, &block)
|
|
83
167
|
end
|
|
84
168
|
|
|
85
169
|
# (see Schema::MetaSchema#new_schema_module)
|
|
86
170
|
def new_schema_module(schema_content, **kw, &block)
|
|
87
|
-
schema.
|
|
171
|
+
schema.new_schema_module(schema_content, **kw, &block)
|
|
88
172
|
end
|
|
89
173
|
|
|
90
|
-
# @return [
|
|
91
|
-
def
|
|
92
|
-
schema.
|
|
174
|
+
# @return [Schema::Dialect]
|
|
175
|
+
def described_dialect
|
|
176
|
+
schema.described_dialect
|
|
93
177
|
end
|
|
94
178
|
end
|
|
95
179
|
|
|
96
180
|
# this module is a namespace for building schema classes and schema modules.
|
|
97
|
-
# @
|
|
181
|
+
# @private
|
|
98
182
|
module SchemaClasses
|
|
99
183
|
class << self
|
|
100
184
|
# @private
|
|
@@ -112,24 +196,26 @@ module JSI
|
|
|
112
196
|
# @api private
|
|
113
197
|
# @param schemas [Enumerable<JSI::Schema>] schemas which the class will represent
|
|
114
198
|
# @param includes [Enumerable<Module>] modules which will be included on the class
|
|
115
|
-
# @return [Class
|
|
199
|
+
# @return [Class subclass of JSI::Base]
|
|
116
200
|
def class_for_schemas(schemas, includes: , mutable: )
|
|
117
201
|
@class_for_schemas_map[
|
|
118
|
-
|
|
119
|
-
includes:
|
|
202
|
+
schema_modules: schemas.map(&:jsi_schema_module).to_set.freeze,
|
|
203
|
+
includes: includes.to_set.freeze,
|
|
120
204
|
mutable: mutable,
|
|
121
205
|
]
|
|
122
206
|
end
|
|
123
207
|
|
|
124
|
-
private def class_for_schemas_compute(
|
|
208
|
+
private def class_for_schemas_compute(schema_modules: , includes: , mutable: )
|
|
125
209
|
Class.new(Base) do
|
|
210
|
+
schemas = SchemaSet.new(schema_modules.map(&:schema))
|
|
211
|
+
|
|
126
212
|
define_singleton_method(:jsi_class_schemas) { schemas }
|
|
127
213
|
define_method(:jsi_schemas) { schemas }
|
|
128
214
|
|
|
129
215
|
define_singleton_method(:jsi_class_includes) { includes }
|
|
130
216
|
|
|
131
217
|
mutability_module = mutable ? Base::Mutable : Base::Immutable
|
|
132
|
-
conflicting_modules = Set[JSI::Base, mutability_module] + includes +
|
|
218
|
+
conflicting_modules = Set[JSI::Base, mutability_module] + includes + schema_modules
|
|
133
219
|
|
|
134
220
|
include(mutability_module)
|
|
135
221
|
|
|
@@ -149,52 +235,10 @@ module JSI
|
|
|
149
235
|
end
|
|
150
236
|
|
|
151
237
|
includes.each { |m| include(m) }
|
|
152
|
-
|
|
153
|
-
jsi_class = self
|
|
154
|
-
define_method(:jsi_class) { jsi_class }
|
|
155
|
-
|
|
156
|
-
self
|
|
157
|
-
end
|
|
158
|
-
end
|
|
159
|
-
|
|
160
|
-
# a subclass of MetaSchemaNode::BootstrapSchema with the given modules included
|
|
161
|
-
# @api private
|
|
162
|
-
# @param modules [Set<Module>] schema implementation modules
|
|
163
|
-
# @return [Class]
|
|
164
|
-
def bootstrap_schema_class(modules)
|
|
165
|
-
@bootstrap_schema_class_map[
|
|
166
|
-
modules: Util.ensure_module_set(modules),
|
|
167
|
-
]
|
|
168
|
-
end
|
|
169
|
-
|
|
170
|
-
private def bootstrap_schema_class_compute(modules: )
|
|
171
|
-
Class.new(MetaSchemaNode::BootstrapSchema) do
|
|
172
|
-
define_singleton_method(:schema_implementation_modules) { modules }
|
|
173
|
-
define_method(:schema_implementation_modules) { modules }
|
|
174
|
-
modules.each { |mod| include(mod) }
|
|
175
|
-
|
|
176
|
-
self
|
|
238
|
+
schema_modules.to_a.reverse_each { |m| include(m) }
|
|
177
239
|
end
|
|
178
240
|
end
|
|
179
241
|
|
|
180
|
-
# see {Schema#jsi_schema_module}
|
|
181
|
-
# @api private
|
|
182
|
-
# @return [SchemaModule]
|
|
183
|
-
def module_for_schema(schema)
|
|
184
|
-
Schema.ensure_schema(schema)
|
|
185
|
-
raise(Bug, "non-Base schema cannot have schema module: #{schema}") unless schema.is_a?(Base)
|
|
186
|
-
@schema_module_map[schema]
|
|
187
|
-
end
|
|
188
|
-
|
|
189
|
-
# @private
|
|
190
|
-
# @deprecated after v0.7
|
|
191
|
-
def accessor_module_for_schema(schema, conflicting_modules: , setters: true)
|
|
192
|
-
Module.new do
|
|
193
|
-
include SchemaClasses.schema_property_reader_module(schema, conflicting_modules: conflicting_modules)
|
|
194
|
-
include SchemaClasses.schema_property_writer_module(schema, conflicting_modules: conflicting_modules) if setters
|
|
195
|
-
end
|
|
196
|
-
end
|
|
197
|
-
|
|
198
242
|
# a module of readers for described property names of the given schema.
|
|
199
243
|
#
|
|
200
244
|
# @private
|
|
@@ -204,18 +248,17 @@ module JSI
|
|
|
204
248
|
# will not be defined as accessors.
|
|
205
249
|
# @return [Module]
|
|
206
250
|
def schema_property_reader_module(schema, conflicting_modules: )
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
end
|
|
210
|
-
|
|
211
|
-
private def schema_property_reader_module_compute(schema: , conflicting_modules: )
|
|
212
|
-
Module.new do
|
|
213
|
-
readers = schema.described_object_property_names.select do |name|
|
|
251
|
+
@schema_property_reader_module_map[
|
|
252
|
+
schema.described_object_property_names.select do |name|
|
|
214
253
|
Util.ok_ruby_method_name?(name) &&
|
|
215
254
|
!conflicting_modules.any? { |m| m.method_defined?(name) || m.private_method_defined?(name) }
|
|
216
255
|
end.to_set.freeze
|
|
256
|
+
]
|
|
257
|
+
end
|
|
217
258
|
|
|
218
|
-
|
|
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(', ')})" }
|
|
219
262
|
|
|
220
263
|
define_singleton_method(:jsi_property_readers) { readers }
|
|
221
264
|
|
|
@@ -230,19 +273,18 @@ module JSI
|
|
|
230
273
|
# a module of writers for described property names of the given schema.
|
|
231
274
|
# @private
|
|
232
275
|
def schema_property_writer_module(schema, conflicting_modules: )
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
end
|
|
236
|
-
|
|
237
|
-
private def schema_property_writer_module_compute(schema: , conflicting_modules: )
|
|
238
|
-
Module.new do
|
|
239
|
-
define_singleton_method(:inspect) { '(JSI Schema Property Writer Module)' }
|
|
240
|
-
|
|
241
|
-
writers = schema.described_object_property_names.select do |name|
|
|
276
|
+
@schema_property_writer_module_map[
|
|
277
|
+
schema.described_object_property_names.select do |name|
|
|
242
278
|
writer = "#{name}="
|
|
243
279
|
Util.ok_ruby_method_name?(name) &&
|
|
244
280
|
!conflicting_modules.any? { |m| m.method_defined?(writer) || m.private_method_defined?(writer) }
|
|
245
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(', ')})" }
|
|
246
288
|
|
|
247
289
|
define_singleton_method(:jsi_property_writers) { writers }
|
|
248
290
|
|
|
@@ -256,14 +298,11 @@ module JSI
|
|
|
256
298
|
end
|
|
257
299
|
|
|
258
300
|
@class_for_schemas_map = Hash.new { |h, k| h[k] = class_for_schemas_compute(**k) }
|
|
259
|
-
@
|
|
260
|
-
@
|
|
261
|
-
@schema_property_reader_module_map = Hash.new { |h, k| h[k] = schema_property_reader_module_compute(**k) }
|
|
262
|
-
@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) }
|
|
263
303
|
end
|
|
264
304
|
|
|
265
|
-
|
|
266
|
-
module SchemaModule::Connects
|
|
305
|
+
class SchemaModule::Connection
|
|
267
306
|
attr_reader :jsi_node
|
|
268
307
|
|
|
269
308
|
# a name relative to a named schema module of an ancestor schema.
|
|
@@ -272,11 +311,11 @@ module JSI
|
|
|
272
311
|
# @api private
|
|
273
312
|
# @return [String, nil]
|
|
274
313
|
def name_from_ancestor
|
|
275
|
-
|
|
276
|
-
return nil unless
|
|
314
|
+
named_ancestor, tokens = named_ancestor_tokens
|
|
315
|
+
return nil unless named_ancestor
|
|
277
316
|
|
|
278
|
-
name =
|
|
279
|
-
ancestor =
|
|
317
|
+
name = named_ancestor.jsi_schema_module_connection.name
|
|
318
|
+
ancestor = named_ancestor
|
|
280
319
|
tokens.each do |token|
|
|
281
320
|
if ancestor.jsi_property_readers.include?(token)
|
|
282
321
|
name += ".#{token}"
|
|
@@ -290,9 +329,16 @@ module JSI
|
|
|
290
329
|
name.freeze
|
|
291
330
|
end
|
|
292
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
|
|
337
|
+
end
|
|
338
|
+
|
|
293
339
|
# Subscripting a JSI schema module or a {SchemaModule::Connection} will subscript its node, and
|
|
294
340
|
# if the result is a JSI::Schema, return the JSI Schema module of that schema; if it is a JSI::Base,
|
|
295
|
-
# 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.
|
|
296
342
|
#
|
|
297
343
|
# @param token [Object]
|
|
298
344
|
# @yield If the token identifies a schema and a block is given,
|
|
@@ -301,35 +347,32 @@ module JSI
|
|
|
301
347
|
# @return [SchemaModule, SchemaModule::Connection, Object]
|
|
302
348
|
def [](token, **kw, &block)
|
|
303
349
|
raise(ArgumentError) unless kw.empty? # TODO remove eventually (keyword argument compatibility)
|
|
350
|
+
@jsi_node.jsi_child_ensure_present(token)
|
|
304
351
|
sub = @jsi_node[token]
|
|
305
352
|
if sub.is_a?(JSI::Schema)
|
|
306
353
|
sub.jsi_schema_module_exec(&block) if block
|
|
307
354
|
sub.jsi_schema_module
|
|
308
355
|
elsif block
|
|
309
|
-
raise(
|
|
356
|
+
raise(BlockGivenError, "block given but token #{token.inspect} does not identify a schema")
|
|
310
357
|
elsif sub.is_a?(JSI::Base)
|
|
311
|
-
|
|
358
|
+
sub.jsi_schema_module_connection
|
|
312
359
|
else
|
|
313
360
|
sub
|
|
314
361
|
end
|
|
315
362
|
end
|
|
316
363
|
|
|
317
|
-
private
|
|
318
|
-
|
|
319
364
|
# @return [Array<JSI::Schema, Array>, nil]
|
|
320
|
-
def
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
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]
|
|
326
373
|
end
|
|
327
374
|
end
|
|
328
375
|
|
|
329
|
-
class SchemaModule
|
|
330
|
-
include Connects
|
|
331
|
-
end
|
|
332
|
-
|
|
333
376
|
# A JSI Schema Module is a module which represents a schema. A SchemaModule::Connection represents
|
|
334
377
|
# a node in a schema's document which is not a schema, such as the 'properties'
|
|
335
378
|
# object (which contains schemas but is not a schema).
|
|
@@ -338,17 +381,18 @@ module JSI
|
|
|
338
381
|
# schema modules to refer to their subschemas' schema modules.
|
|
339
382
|
#
|
|
340
383
|
# A SchemaModule::Connection has readers for property names described by the node's schemas.
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
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
|
|
344
388
|
# @param node [JSI::Base]
|
|
345
389
|
def initialize(node)
|
|
346
|
-
|
|
347
|
-
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)
|
|
348
391
|
@jsi_node = node
|
|
349
392
|
node.jsi_schemas.each do |schema|
|
|
350
393
|
extend(JSI::SchemaClasses.schema_property_reader_module(schema, conflicting_modules: [SchemaModule::Connection]))
|
|
351
394
|
end
|
|
395
|
+
node.jsi_schema_module_connection_created(self)
|
|
352
396
|
end
|
|
353
397
|
|
|
354
398
|
# @return [String]
|