jsi 0.6.0 → 0.8.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 +6 -1
- data/CHANGELOG.md +33 -0
- data/LICENSE.md +1 -1
- data/README.md +29 -23
- data/jsi.gemspec +29 -0
- data/lib/jsi/base/mutability.rb +44 -0
- data/lib/jsi/base/node.rb +348 -0
- data/lib/jsi/base.rb +497 -339
- data/lib/jsi/jsi_coder.rb +19 -17
- data/lib/jsi/metaschema_node/bootstrap_schema.rb +61 -26
- data/lib/jsi/metaschema_node.rb +161 -133
- data/lib/jsi/ptr.rb +80 -47
- data/lib/jsi/schema/application/child_application/contains.rb +11 -2
- data/lib/jsi/schema/application/child_application/draft04.rb +0 -1
- data/lib/jsi/schema/application/child_application/draft06.rb +0 -1
- data/lib/jsi/schema/application/child_application/draft07.rb +0 -1
- data/lib/jsi/schema/application/child_application/items.rb +3 -3
- data/lib/jsi/schema/application/child_application/properties.rb +3 -3
- data/lib/jsi/schema/application/child_application.rb +0 -27
- data/lib/jsi/schema/application/inplace_application/dependencies.rb +1 -1
- data/lib/jsi/schema/application/inplace_application/draft04.rb +0 -1
- data/lib/jsi/schema/application/inplace_application/draft06.rb +0 -1
- data/lib/jsi/schema/application/inplace_application/draft07.rb +0 -1
- data/lib/jsi/schema/application/inplace_application/ifthenelse.rb +3 -3
- data/lib/jsi/schema/application/inplace_application/ref.rb +2 -2
- data/lib/jsi/schema/application/inplace_application/someof.rb +26 -11
- data/lib/jsi/schema/application/inplace_application.rb +0 -32
- data/lib/jsi/schema/draft04.rb +0 -1
- data/lib/jsi/schema/draft06.rb +0 -1
- data/lib/jsi/schema/draft07.rb +0 -1
- data/lib/jsi/schema/ref.rb +46 -19
- data/lib/jsi/schema/schema_ancestor_node.rb +69 -66
- data/lib/jsi/schema/validation/array.rb +3 -3
- data/lib/jsi/schema/validation/const.rb +1 -1
- data/lib/jsi/schema/validation/contains.rb +2 -2
- data/lib/jsi/schema/validation/dependencies.rb +1 -1
- data/lib/jsi/schema/validation/draft04/minmax.rb +8 -6
- data/lib/jsi/schema/validation/draft04.rb +0 -2
- data/lib/jsi/schema/validation/draft06.rb +0 -2
- data/lib/jsi/schema/validation/draft07.rb +0 -2
- data/lib/jsi/schema/validation/enum.rb +1 -1
- data/lib/jsi/schema/validation/ifthenelse.rb +5 -5
- data/lib/jsi/schema/validation/items.rb +7 -7
- data/lib/jsi/schema/validation/not.rb +1 -1
- data/lib/jsi/schema/validation/numeric.rb +5 -5
- data/lib/jsi/schema/validation/object.rb +2 -2
- data/lib/jsi/schema/validation/pattern.rb +2 -2
- data/lib/jsi/schema/validation/properties.rb +7 -7
- data/lib/jsi/schema/validation/property_names.rb +1 -1
- data/lib/jsi/schema/validation/ref.rb +2 -2
- data/lib/jsi/schema/validation/required.rb +1 -1
- data/lib/jsi/schema/validation/someof.rb +3 -3
- data/lib/jsi/schema/validation/string.rb +2 -2
- data/lib/jsi/schema/validation/type.rb +1 -1
- data/lib/jsi/schema/validation.rb +1 -3
- data/lib/jsi/schema.rb +443 -226
- data/lib/jsi/schema_classes.rb +241 -147
- data/lib/jsi/schema_registry.rb +78 -19
- data/lib/jsi/schema_set.rb +114 -28
- data/lib/jsi/simple_wrap.rb +18 -4
- data/lib/jsi/util/private/attr_struct.rb +141 -0
- data/lib/jsi/util/private/memo_map.rb +75 -0
- data/lib/jsi/util/private.rb +185 -0
- data/lib/jsi/{typelike_modules.rb → util/typelike.rb} +79 -105
- data/lib/jsi/util.rb +157 -153
- data/lib/jsi/validation/error.rb +4 -0
- data/lib/jsi/validation/result.rb +18 -32
- data/lib/jsi/version.rb +1 -1
- data/lib/jsi.rb +65 -39
- data/lib/schemas/json-schema.org/draft-04/schema.rb +160 -3
- data/lib/schemas/json-schema.org/draft-06/schema.rb +162 -3
- data/lib/schemas/json-schema.org/draft-07/schema.rb +189 -3
- metadata +27 -11
- data/lib/jsi/metaschema.rb +0 -7
- data/lib/jsi/pathed_node.rb +0 -116
- data/lib/jsi/schema/validation/core.rb +0 -39
- data/lib/jsi/util/attr_struct.rb +0 -106
data/lib/jsi/schema_classes.rb
CHANGED
@@ -1,13 +1,24 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module JSI
|
4
|
-
#
|
5
|
-
|
6
|
-
#
|
7
|
-
|
8
|
-
|
9
|
-
# note: defined on JSI Schema Module by JSI::SchemaClasses.module_for_schema
|
4
|
+
# A Module associated with a JSI Schema. See {Schema#jsi_schema_module}.
|
5
|
+
class SchemaModule < Module
|
6
|
+
# @private
|
7
|
+
def initialize(schema, &block)
|
8
|
+
super(&block)
|
10
9
|
|
10
|
+
@jsi_node = schema
|
11
|
+
|
12
|
+
schema.jsi_schemas.each do |schema_schema|
|
13
|
+
extend SchemaClasses.schema_property_reader_module(schema_schema, conflicting_modules: Set[SchemaModule])
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# The schema for which this is the JSI Schema Module
|
18
|
+
# @return [Base + Schema]
|
19
|
+
def schema
|
20
|
+
@jsi_node
|
21
|
+
end
|
11
22
|
|
12
23
|
# a URI which refers to the schema. see {Schema#schema_uri}.
|
13
24
|
# @return (see Schema#schema_uri)
|
@@ -18,256 +29,339 @@ module JSI
|
|
18
29
|
# @return [String]
|
19
30
|
def inspect
|
20
31
|
if name_from_ancestor
|
21
|
-
|
32
|
+
if schema.schema_absolute_uri
|
33
|
+
-"#{name_from_ancestor} <#{schema.schema_absolute_uri}> (JSI Schema Module)"
|
34
|
+
else
|
35
|
+
-"#{name_from_ancestor} (JSI Schema Module)"
|
36
|
+
end
|
22
37
|
else
|
23
|
-
"(JSI Schema Module: #{schema.schema_uri || schema.jsi_ptr.uri})"
|
38
|
+
-"(JSI Schema Module: #{schema.schema_uri || schema.jsi_ptr.uri})"
|
24
39
|
end
|
25
40
|
end
|
26
41
|
|
27
|
-
|
42
|
+
def to_s
|
43
|
+
inspect
|
44
|
+
end
|
45
|
+
|
46
|
+
# invokes {JSI::Schema#new_jsi} on this module's schema, passing the given parameters.
|
28
47
|
#
|
29
48
|
# @param (see JSI::Schema#new_jsi)
|
30
|
-
# @return [JSI::Base] a JSI whose
|
31
|
-
|
32
|
-
|
49
|
+
# @return [JSI::Base subclass] a JSI whose content comes from the given instance and whose schemas are
|
50
|
+
# inplace applicators of this module's schema.
|
51
|
+
def new_jsi(instance, **kw)
|
52
|
+
schema.new_jsi(instance, **kw)
|
53
|
+
end
|
54
|
+
|
55
|
+
# See {Schema#schema_content}
|
56
|
+
def schema_content
|
57
|
+
schema.jsi_node_content
|
58
|
+
end
|
59
|
+
|
60
|
+
# See {Schema#instance_validate}
|
61
|
+
def instance_validate(instance)
|
62
|
+
schema.instance_validate(instance)
|
63
|
+
end
|
64
|
+
|
65
|
+
# See {Schema#instance_valid?}
|
66
|
+
def instance_valid?(instance)
|
67
|
+
schema.instance_valid?(instance)
|
33
68
|
end
|
34
69
|
end
|
35
70
|
|
36
|
-
#
|
37
|
-
module
|
38
|
-
#
|
71
|
+
# A module to extend the {SchemaModule} of a schema which describes other schemas (a {Schema::MetaSchema})
|
72
|
+
module SchemaModule::MetaSchemaModule
|
73
|
+
# Instantiates the given schema content as a JSI Schema.
|
39
74
|
#
|
40
|
-
# see {JSI::Schema::
|
75
|
+
# see {JSI::Schema::MetaSchema#new_schema}
|
41
76
|
#
|
42
|
-
# @param (see
|
43
|
-
# @
|
44
|
-
#
|
45
|
-
|
46
|
-
|
77
|
+
# @param (see Schema::MetaSchema#new_schema)
|
78
|
+
# @yield (see Schema::MetaSchema#new_schema)
|
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
|
81
|
+
def new_schema(schema_content, **kw, &block)
|
82
|
+
schema.new_schema(schema_content, **kw, &block)
|
47
83
|
end
|
48
84
|
|
49
|
-
#
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
# @return [Module
|
55
|
-
def
|
56
|
-
schema.
|
85
|
+
# (see Schema::MetaSchema#new_schema_module)
|
86
|
+
def new_schema_module(schema_content, **kw, &block)
|
87
|
+
schema.new_schema(schema_content, **kw, &block).jsi_schema_module
|
88
|
+
end
|
89
|
+
|
90
|
+
# @return [Set<Module>]
|
91
|
+
def schema_implementation_modules
|
92
|
+
schema.schema_implementation_modules
|
57
93
|
end
|
58
94
|
end
|
59
95
|
|
60
96
|
# this module is a namespace for building schema classes and schema modules.
|
97
|
+
# @api private
|
61
98
|
module SchemaClasses
|
62
|
-
extend Util::Memoize
|
63
|
-
|
64
99
|
class << self
|
100
|
+
# @private
|
101
|
+
# @return [Set<Module>]
|
102
|
+
def includes_for(instance)
|
103
|
+
includes = Set[]
|
104
|
+
includes << Base::ArrayNode if instance.respond_to?(:to_ary)
|
105
|
+
includes << Base::HashNode if instance.respond_to?(:to_hash)
|
106
|
+
includes << Base::StringNode if instance.respond_to?(:to_str)
|
107
|
+
includes.freeze
|
108
|
+
end
|
109
|
+
|
65
110
|
# a JSI Schema Class which represents the given schemas.
|
66
111
|
# an instance of the class is a JSON Schema instance described by all of the given schemas.
|
67
|
-
# @private
|
112
|
+
# @api private
|
68
113
|
# @param schemas [Enumerable<JSI::Schema>] schemas which the class will represent
|
114
|
+
# @param includes [Enumerable<Module>] modules which will be included on the class
|
69
115
|
# @return [Class subclassing JSI::Base]
|
70
|
-
def class_for_schemas(schemas)
|
71
|
-
|
116
|
+
def class_for_schemas(schemas, includes: , mutable: )
|
117
|
+
@class_for_schemas_map[
|
118
|
+
schemas: SchemaSet.ensure_schema_set(schemas),
|
119
|
+
includes: Util.ensure_module_set(includes),
|
120
|
+
mutable: mutable,
|
121
|
+
]
|
122
|
+
end
|
72
123
|
|
73
|
-
|
74
|
-
Class.new(Base)
|
124
|
+
private def class_for_schemas_compute(schemas: , includes: , mutable: )
|
125
|
+
Class.new(Base) do
|
75
126
|
define_singleton_method(:jsi_class_schemas) { schemas }
|
76
127
|
define_method(:jsi_schemas) { schemas }
|
128
|
+
|
129
|
+
define_singleton_method(:jsi_class_includes) { includes }
|
130
|
+
|
131
|
+
mutability_module = mutable ? Base::Mutable : Base::Immutable
|
132
|
+
conflicting_modules = Set[JSI::Base, mutability_module] + includes + schemas.map(&:jsi_schema_module)
|
133
|
+
|
134
|
+
include(mutability_module)
|
135
|
+
|
136
|
+
reader_modules = schemas.map do |schema|
|
137
|
+
JSI::SchemaClasses.schema_property_reader_module(schema, conflicting_modules: conflicting_modules)
|
138
|
+
end
|
139
|
+
reader_modules.each { |m| include m }
|
140
|
+
readers = reader_modules.map(&:jsi_property_readers).inject(Set[], &:merge).freeze
|
141
|
+
define_method(:jsi_property_readers) { readers }
|
142
|
+
define_singleton_method(:jsi_property_readers) { readers }
|
143
|
+
|
144
|
+
if mutable
|
145
|
+
writer_modules = schemas.map do |schema|
|
146
|
+
JSI::SchemaClasses.schema_property_writer_module(schema, conflicting_modules: conflicting_modules)
|
147
|
+
end
|
148
|
+
writer_modules.each { |m| include(m) }
|
149
|
+
end
|
150
|
+
|
151
|
+
includes.each { |m| include(m) }
|
77
152
|
schemas.each { |schema| include(schema.jsi_schema_module) }
|
78
153
|
jsi_class = self
|
79
154
|
define_method(:jsi_class) { jsi_class }
|
80
155
|
|
81
156
|
self
|
82
157
|
end
|
83
|
-
end
|
84
158
|
end
|
85
159
|
|
86
|
-
#
|
87
|
-
#
|
88
|
-
# @param modules [Set<Module>]
|
160
|
+
# a subclass of MetaSchemaNode::BootstrapSchema with the given modules included
|
161
|
+
# @api private
|
162
|
+
# @param modules [Set<Module>] schema implementation modules
|
89
163
|
# @return [Class]
|
90
164
|
def bootstrap_schema_class(modules)
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
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 }
|
96
174
|
modules.each { |mod| include(mod) }
|
97
175
|
|
98
176
|
self
|
99
177
|
end
|
100
|
-
end
|
101
178
|
end
|
102
179
|
|
103
180
|
# see {Schema#jsi_schema_module}
|
104
181
|
# @api private
|
105
|
-
# @return [
|
182
|
+
# @return [SchemaModule]
|
106
183
|
def module_for_schema(schema)
|
107
184
|
Schema.ensure_schema(schema)
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
define_singleton_method(: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
|
112
188
|
|
113
|
-
|
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
|
114
197
|
|
115
|
-
|
116
|
-
|
117
|
-
|
198
|
+
# a module of readers for described property names of the given schema.
|
199
|
+
#
|
200
|
+
# @private
|
201
|
+
# @param schema [JSI::Schema] a schema for which to define readers for any described property names
|
202
|
+
# @param conflicting_modules [Enumerable<Module>] an array of modules (or classes) which
|
203
|
+
# may be used alongside the accessor module. methods defined by any conflicting_module
|
204
|
+
# will not be defined as accessors.
|
205
|
+
# @return [Module]
|
206
|
+
def schema_property_reader_module(schema, conflicting_modules: )
|
207
|
+
Schema.ensure_schema(schema)
|
208
|
+
@schema_property_reader_module_map[schema: schema, conflicting_modules: conflicting_modules]
|
209
|
+
end
|
118
210
|
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
)
|
123
|
-
|
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|
|
214
|
+
Util.ok_ruby_method_name?(name) &&
|
215
|
+
!conflicting_modules.any? { |m| m.method_defined?(name) || m.private_method_defined?(name) }
|
216
|
+
end.to_set.freeze
|
124
217
|
|
125
|
-
|
218
|
+
define_singleton_method(:inspect) { "(JSI Schema Property Reader Module: #{readers.join(', ')})" }
|
126
219
|
|
127
|
-
|
128
|
-
extend DescribesSchemaModule
|
129
|
-
end
|
220
|
+
define_singleton_method(:jsi_property_readers) { readers }
|
130
221
|
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
extend JSI::SchemaClasses.accessor_module_for_schema(schema_schema,
|
135
|
-
conflicting_modules: Set[Module, SchemaModule, SchemaModulePossibly],
|
136
|
-
setters: false,
|
137
|
-
)
|
222
|
+
readers.each do |property_name|
|
223
|
+
define_method(property_name) do |**kw, &block|
|
224
|
+
self[property_name, **kw, &block]
|
138
225
|
end
|
139
226
|
end
|
140
227
|
end
|
141
|
-
end
|
142
228
|
end
|
143
229
|
|
144
|
-
# a module of
|
145
|
-
#
|
146
|
-
|
147
|
-
# @param conflicting_modules [Enumerable<Module>] an array of modules (or classes) which
|
148
|
-
# may be used alongside the accessor module. methods defined by any conflicting_module
|
149
|
-
# will not be defined as accessors.
|
150
|
-
# @param setters [Boolean] whether to define setter methods
|
151
|
-
# @return [Module]
|
152
|
-
def accessor_module_for_schema(schema, conflicting_modules: , setters: true)
|
230
|
+
# a module of writers for described property names of the given schema.
|
231
|
+
# @private
|
232
|
+
def schema_property_writer_module(schema, conflicting_modules: )
|
153
233
|
Schema.ensure_schema(schema)
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
self[property_name, *a]
|
171
|
-
end
|
172
|
-
if setters
|
234
|
+
@schema_property_writer_module_map[schema: schema, conflicting_modules: conflicting_modules]
|
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|
|
242
|
+
writer = "#{name}="
|
243
|
+
Util.ok_ruby_method_name?(name) &&
|
244
|
+
!conflicting_modules.any? { |m| m.method_defined?(writer) || m.private_method_defined?(writer) }
|
245
|
+
end.to_set.freeze
|
246
|
+
|
247
|
+
define_singleton_method(:jsi_property_writers) { writers }
|
248
|
+
|
249
|
+
writers.each do |property_name|
|
173
250
|
define_method("#{property_name}=") do |value|
|
174
251
|
self[property_name] = value
|
175
252
|
end
|
176
|
-
end
|
177
|
-
end
|
178
253
|
end
|
179
254
|
end
|
180
|
-
end
|
181
255
|
end
|
182
256
|
end
|
257
|
+
|
258
|
+
@class_for_schemas_map = Hash.new { |h, k| h[k] = class_for_schemas_compute(**k) }
|
259
|
+
@bootstrap_schema_class_map = Hash.new { |h, k| h[k] = bootstrap_schema_class_compute(**k) }
|
260
|
+
@schema_module_map = Hash.new { |h, schema| h[schema] = SchemaModule.new(schema) }
|
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) }
|
183
263
|
end
|
184
264
|
|
185
|
-
#
|
186
|
-
|
187
|
-
|
188
|
-
attr_reader :possibly_schema_node
|
265
|
+
# connecting {SchemaModule}s via {SchemaModule::Connection}s
|
266
|
+
module SchemaModule::Connects
|
267
|
+
attr_reader :jsi_node
|
189
268
|
|
190
269
|
# a name relative to a named schema module of an ancestor schema.
|
191
|
-
# for example, if `Foos = JSI::
|
270
|
+
# for example, if `Foos = JSI::JSONSchemaDraft07.new_schema_module({'items' => {}})`
|
192
271
|
# then the module `Foos.items` will have a name_from_ancestor of `"Foos.items"`
|
272
|
+
# @api private
|
193
273
|
# @return [String, nil]
|
194
274
|
def name_from_ancestor
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
return nil unless named_parent_schema
|
275
|
+
named_ancestor_schema, tokens = named_ancestor_schema_tokens
|
276
|
+
return nil unless named_ancestor_schema
|
199
277
|
|
200
|
-
|
201
|
-
|
202
|
-
parent = named_parent_schema
|
278
|
+
name = named_ancestor_schema.jsi_schema_module.name
|
279
|
+
ancestor = named_ancestor_schema
|
203
280
|
tokens.each do |token|
|
204
|
-
if
|
281
|
+
if ancestor.jsi_property_readers.include?(token)
|
205
282
|
name += ".#{token}"
|
206
283
|
elsif [String, Numeric, TrueClass, FalseClass, NilClass].any? { |m| token.is_a?(m) }
|
207
284
|
name += "[#{token.inspect}]"
|
208
285
|
else
|
209
286
|
return nil
|
210
287
|
end
|
211
|
-
|
288
|
+
ancestor = ancestor[token]
|
212
289
|
end
|
213
|
-
name
|
290
|
+
name.freeze
|
214
291
|
end
|
215
292
|
|
216
|
-
#
|
217
|
-
# if the result is a JSI::Schema, return the JSI Schema module of that schema; if it is a
|
218
|
-
# return a
|
293
|
+
# Subscripting a JSI schema module or a {SchemaModule::Connection} will subscript its node, and
|
294
|
+
# 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 basic type), return that value.
|
219
296
|
#
|
220
297
|
# @param token [Object]
|
221
|
-
# @
|
222
|
-
|
223
|
-
|
298
|
+
# @yield If the token identifies a schema and a block is given,
|
299
|
+
# it is evaluated in the context of the schema's JSI schema module
|
300
|
+
# using [Module#module_exec](https://ruby-doc.org/core/Module.html#method-i-module_exec).
|
301
|
+
# @return [SchemaModule, SchemaModule::Connection, Object]
|
302
|
+
def [](token, **kw, &block)
|
303
|
+
raise(ArgumentError) unless kw.empty? # TODO remove eventually (keyword argument compatibility)
|
304
|
+
sub = @jsi_node[token]
|
224
305
|
if sub.is_a?(JSI::Schema)
|
306
|
+
sub.jsi_schema_module_exec(&block) if block
|
225
307
|
sub.jsi_schema_module
|
226
|
-
elsif
|
227
|
-
|
308
|
+
elsif block
|
309
|
+
raise(ArgumentError, "block given but token #{token.inspect} does not identify a schema")
|
310
|
+
elsif sub.is_a?(JSI::Base)
|
311
|
+
SchemaModule::Connection.new(sub)
|
228
312
|
else
|
229
313
|
sub
|
230
314
|
end
|
231
315
|
end
|
316
|
+
|
317
|
+
private
|
318
|
+
|
319
|
+
# @return [Array<JSI::Schema, Array>, nil]
|
320
|
+
def named_ancestor_schema_tokens
|
321
|
+
schema_ancestors = @jsi_node.jsi_ancestor_nodes
|
322
|
+
named_ancestor_schema = schema_ancestors.detect { |jsi| jsi.is_a?(JSI::Schema) && jsi.jsi_schema_module.name }
|
323
|
+
return nil unless named_ancestor_schema
|
324
|
+
tokens = @jsi_node.jsi_ptr.relative_to(named_ancestor_schema.jsi_ptr).tokens
|
325
|
+
[named_ancestor_schema, tokens]
|
326
|
+
end
|
327
|
+
end
|
328
|
+
|
329
|
+
class SchemaModule
|
330
|
+
include Connects
|
232
331
|
end
|
233
332
|
|
234
|
-
#
|
333
|
+
# A JSI Schema Module is a module which represents a schema. A SchemaModule::Connection represents
|
235
334
|
# a node in a schema's document which is not a schema, such as the 'properties'
|
236
335
|
# object (which contains schemas but is not a schema).
|
237
336
|
#
|
238
337
|
# instances of this class act as a stand-in to allow users to subscript or call property accessors on
|
239
338
|
# schema modules to refer to their subschemas' schema modules.
|
240
339
|
#
|
241
|
-
#
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
# value is a basic type - that value itself is returned.
|
247
|
-
class NotASchemaModule
|
248
|
-
# @param node [JSI::PathedNode]
|
340
|
+
# A SchemaModule::Connection has readers for property names described by the node's schemas.
|
341
|
+
class SchemaModule::Connection
|
342
|
+
include SchemaModule::Connects
|
343
|
+
|
344
|
+
# @param node [JSI::Base]
|
249
345
|
def initialize(node)
|
250
|
-
unless node.is_a?(JSI::
|
251
|
-
|
252
|
-
|
253
|
-
if node.is_a?(JSI::Schema)
|
254
|
-
raise(TypeError, "cannot instantiate NotASchemaModule for a JSI::Schema node: #{node.pretty_inspect.chomp}")
|
255
|
-
end
|
256
|
-
@possibly_schema_node = node
|
346
|
+
raise(Bug, "node must be JSI::Base: #{node.pretty_inspect.chomp}") unless node.is_a?(JSI::Base)
|
347
|
+
raise(Bug, "node must not be JSI::Schema: #{node.pretty_inspect.chomp}") if node.is_a?(JSI::Schema)
|
348
|
+
@jsi_node = node
|
257
349
|
node.jsi_schemas.each do |schema|
|
258
|
-
extend(JSI::SchemaClasses.
|
350
|
+
extend(JSI::SchemaClasses.schema_property_reader_module(schema, conflicting_modules: [SchemaModule::Connection]))
|
259
351
|
end
|
260
352
|
end
|
261
353
|
|
262
|
-
include SchemaModulePossibly
|
263
|
-
|
264
354
|
# @return [String]
|
265
355
|
def inspect
|
266
356
|
if name_from_ancestor
|
267
|
-
"#{name_from_ancestor} (
|
357
|
+
-"#{name_from_ancestor} (#{self.class})"
|
268
358
|
else
|
269
|
-
"(
|
359
|
+
-"(#{self.class}: #{@jsi_node.jsi_ptr.uri})"
|
270
360
|
end
|
271
361
|
end
|
362
|
+
|
363
|
+
def to_s
|
364
|
+
inspect
|
365
|
+
end
|
272
366
|
end
|
273
367
|
end
|