jsi 0.6.0 → 0.7.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/CHANGELOG.md +18 -0
- data/LICENSE.md +1 -1
- data/README.md +11 -6
- data/jsi.gemspec +30 -0
- data/lib/jsi/base/node.rb +183 -0
- data/lib/jsi/base.rb +135 -161
- data/lib/jsi/jsi_coder.rb +3 -3
- data/lib/jsi/metaschema.rb +0 -1
- data/lib/jsi/metaschema_node/bootstrap_schema.rb +9 -8
- data/lib/jsi/metaschema_node.rb +48 -51
- data/lib/jsi/ptr.rb +28 -17
- data/lib/jsi/schema/application/child_application/contains.rb +11 -2
- 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 +1 -3
- data/lib/jsi/schema/application/inplace_application/dependencies.rb +1 -1
- data/lib/jsi/schema/application/inplace_application/ifthenelse.rb +3 -3
- data/lib/jsi/schema/application/inplace_application/ref.rb +1 -1
- data/lib/jsi/schema/application/inplace_application/someof.rb +26 -11
- data/lib/jsi/schema/application/inplace_application.rb +1 -6
- data/lib/jsi/schema/ref.rb +3 -2
- data/lib/jsi/schema/schema_ancestor_node.rb +11 -17
- 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 +1 -1
- data/lib/jsi/schema/validation/dependencies.rb +1 -1
- data/lib/jsi/schema/validation/draft04/minmax.rb +6 -6
- 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 +4 -4
- 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 +1 -1
- data/lib/jsi/schema/validation/properties.rb +3 -3
- data/lib/jsi/schema/validation/property_names.rb +1 -1
- data/lib/jsi/schema/validation/ref.rb +1 -1
- 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 -1
- data/lib/jsi/schema.rb +91 -85
- data/lib/jsi/schema_classes.rb +70 -45
- data/lib/jsi/schema_registry.rb +15 -5
- data/lib/jsi/schema_set.rb +42 -2
- data/lib/jsi/simple_wrap.rb +23 -4
- data/lib/jsi/util/{attr_struct.rb → private/attr_struct.rb} +40 -19
- data/lib/jsi/util/private.rb +204 -0
- data/lib/jsi/{typelike_modules.rb → util/typelike.rb} +56 -82
- data/lib/jsi/util.rb +68 -148
- data/lib/jsi/version.rb +1 -1
- data/lib/jsi.rb +1 -17
- data/lib/schemas/json-schema.org/draft-04/schema.rb +3 -1
- data/lib/schemas/json-schema.org/draft-06/schema.rb +3 -1
- data/lib/schemas/json-schema.org/draft-07/schema.rb +3 -1
- metadata +11 -9
- data/lib/jsi/pathed_node.rb +0 -116
data/lib/jsi/metaschema_node.rb
CHANGED
@@ -25,27 +25,31 @@ module JSI
|
|
25
25
|
|
26
26
|
# @param jsi_document the document containing the metaschema
|
27
27
|
# @param jsi_ptr [JSI::Ptr] ptr to this MetaschemaNode in jsi_document
|
28
|
-
# @param
|
29
|
-
#
|
30
|
-
#
|
31
|
-
# metaschema.
|
28
|
+
# @param schema_implementation_modules [Enumerable<Module>] modules which implement the functionality
|
29
|
+
# of the schema. these are included on the {Schema#jsi_schema_module} of the metaschema.
|
30
|
+
# they extend any schema described by the metaschema, including those in the document containing
|
31
|
+
# the metaschema, and the metaschema itself.
|
32
|
+
# see {Schema#describes_schema!} param `schema_implementation_modules`.
|
32
33
|
# @param metaschema_root_ptr [JSI::Ptr] ptr to the root of the metaschema in the jsi_document
|
33
34
|
# @param root_schema_ptr [JSI::Ptr] ptr to the schema describing the root of the jsi_document
|
34
35
|
def initialize(
|
35
36
|
jsi_document,
|
36
37
|
jsi_ptr: Ptr[],
|
37
|
-
|
38
|
+
schema_implementation_modules: ,
|
38
39
|
metaschema_root_ptr: Ptr[],
|
39
40
|
root_schema_ptr: Ptr[],
|
40
|
-
jsi_schema_base_uri: nil
|
41
|
+
jsi_schema_base_uri: nil,
|
42
|
+
jsi_root_node: nil
|
41
43
|
)
|
42
44
|
jsi_initialize_memos
|
43
45
|
|
44
46
|
self.jsi_document = jsi_document
|
45
47
|
self.jsi_ptr = jsi_ptr
|
46
|
-
@
|
48
|
+
@schema_implementation_modules = Util.ensure_module_set(schema_implementation_modules)
|
47
49
|
@metaschema_root_ptr = metaschema_root_ptr
|
48
50
|
@root_schema_ptr = root_schema_ptr
|
51
|
+
raise(Bug, 'jsi_root_node') if jsi_ptr.root? ^ !jsi_root_node
|
52
|
+
@jsi_root_node = jsi_ptr.root? ? self : jsi_root_node
|
49
53
|
|
50
54
|
if jsi_ptr.root? && jsi_schema_base_uri
|
51
55
|
raise(NotImplementedError, "unsupported jsi_schema_base_uri on metaschema document root")
|
@@ -55,57 +59,58 @@ module JSI
|
|
55
59
|
jsi_node_content = self.jsi_node_content
|
56
60
|
|
57
61
|
if jsi_node_content.respond_to?(:to_hash)
|
58
|
-
extend
|
62
|
+
extend HashNode
|
59
63
|
end
|
60
64
|
if jsi_node_content.respond_to?(:to_ary)
|
61
|
-
extend
|
65
|
+
extend ArrayNode
|
62
66
|
end
|
63
67
|
|
64
68
|
instance_for_schemas = jsi_document
|
65
|
-
bootstrap_schema_class = JSI::SchemaClasses.bootstrap_schema_class(
|
69
|
+
bootstrap_schema_class = JSI::SchemaClasses.bootstrap_schema_class(schema_implementation_modules)
|
66
70
|
root_bootstrap_schema = bootstrap_schema_class.new(
|
67
71
|
jsi_document,
|
68
72
|
jsi_ptr: root_schema_ptr,
|
69
73
|
jsi_schema_base_uri: nil, # supplying jsi_schema_base_uri on root bootstrap schema is not supported
|
70
74
|
)
|
71
75
|
our_bootstrap_schemas = jsi_ptr.tokens.inject(SchemaSet[root_bootstrap_schema]) do |bootstrap_schemas, tok|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
child_app_schema.each_inplace_applicator_schema(child_instance_for_schemas) do |child_inpl_app_schema|
|
77
|
-
schemas << child_inpl_app_schema
|
78
|
-
end
|
79
|
-
end
|
80
|
-
end
|
81
|
-
end
|
82
|
-
instance_for_schemas = child_instance_for_schemas
|
83
|
-
bootstrap_schemas_for_instance
|
76
|
+
child_indicated_schemas = bootstrap_schemas.child_applicator_schemas(tok, instance_for_schemas)
|
77
|
+
child_schemas = child_indicated_schemas.inplace_applicator_schemas(instance_for_schemas[tok])
|
78
|
+
instance_for_schemas = instance_for_schemas[tok]
|
79
|
+
child_schemas
|
84
80
|
end
|
85
81
|
|
86
82
|
our_bootstrap_schemas.each do |bootstrap_schema|
|
87
83
|
if bootstrap_schema.jsi_ptr == metaschema_root_ptr
|
88
|
-
|
89
|
-
|
84
|
+
# this is described by the metaschema, i.e. this is a schema
|
85
|
+
schema_implementation_modules.each do |schema_implementation_module|
|
86
|
+
extend schema_implementation_module
|
90
87
|
end
|
91
88
|
end
|
92
89
|
if bootstrap_schema.jsi_ptr == jsi_ptr
|
90
|
+
# this is the metaschema (it is described by itself)
|
93
91
|
extend Metaschema
|
94
|
-
self.jsi_schema_instance_modules = metaschema_instance_modules
|
95
92
|
end
|
96
93
|
end
|
97
94
|
|
98
95
|
@jsi_schemas = SchemaSet.new(our_bootstrap_schemas) do |bootstrap_schema|
|
99
96
|
if bootstrap_schema.jsi_ptr == jsi_ptr
|
100
97
|
self
|
98
|
+
elsif bootstrap_schema.jsi_ptr.root?
|
99
|
+
@jsi_root_node
|
101
100
|
else
|
102
101
|
new_node(
|
103
102
|
jsi_ptr: bootstrap_schema.jsi_ptr,
|
104
103
|
jsi_schema_base_uri: bootstrap_schema.jsi_schema_base_uri,
|
104
|
+
jsi_root_node: @jsi_root_node,
|
105
105
|
)
|
106
106
|
end
|
107
107
|
end
|
108
108
|
|
109
|
+
# note: jsi_schemas must already be set for jsi_schema_module to be used/extended
|
110
|
+
if is_a?(Metaschema)
|
111
|
+
describes_schema!(schema_implementation_modules)
|
112
|
+
end
|
113
|
+
|
109
114
|
@jsi_schemas.each do |schema|
|
110
115
|
extend schema.jsi_schema_module
|
111
116
|
end
|
@@ -114,19 +119,19 @@ module JSI
|
|
114
119
|
begin # draft 4 boolean schema workaround
|
115
120
|
# in draft 4, boolean schemas are not described in the root, but on anyOf schemas on
|
116
121
|
# properties/additionalProperties and properties/additionalItems.
|
117
|
-
#
|
122
|
+
# these still describe schemas, despite not being described by the metaschema.
|
118
123
|
addtlPropsanyOf = metaschema_root_ptr["properties"]["additionalProperties"]["anyOf"]
|
119
124
|
addtlItemsanyOf = metaschema_root_ptr["properties"]["additionalItems"]["anyOf"]
|
120
125
|
|
121
126
|
if !jsi_ptr.root? && [addtlPropsanyOf, addtlItemsanyOf].include?(jsi_ptr.parent)
|
122
|
-
|
127
|
+
describes_schema!(schema_implementation_modules)
|
123
128
|
end
|
124
129
|
end
|
125
130
|
end
|
126
131
|
|
127
132
|
# Set of modules to apply to schemas which are instances of (described by) the metaschema
|
128
133
|
# @return [Set<Module>]
|
129
|
-
attr_reader :
|
134
|
+
attr_reader :schema_implementation_modules
|
130
135
|
|
131
136
|
# ptr to the root of the metaschema in the jsi_document
|
132
137
|
# @return [JSI::Ptr]
|
@@ -140,25 +145,6 @@ module JSI
|
|
140
145
|
# @return [JSI::SchemaSet]
|
141
146
|
attr_reader :jsi_schemas
|
142
147
|
|
143
|
-
# document root MetaschemaNode
|
144
|
-
# @return [MetaschemaNode]
|
145
|
-
def jsi_root_node
|
146
|
-
if jsi_ptr.root?
|
147
|
-
self
|
148
|
-
else
|
149
|
-
new_node(
|
150
|
-
jsi_ptr: Ptr[],
|
151
|
-
jsi_schema_base_uri: nil,
|
152
|
-
)
|
153
|
-
end
|
154
|
-
end
|
155
|
-
|
156
|
-
# parent MetaschemaNode
|
157
|
-
# @return [MetaschemaNode]
|
158
|
-
def jsi_parent_node
|
159
|
-
jsi_ptr.parent.evaluate(jsi_root_node)
|
160
|
-
end
|
161
|
-
|
162
148
|
# subscripts to return a child value identified by the given token.
|
163
149
|
#
|
164
150
|
# @param token (see JSI::Base#[])
|
@@ -177,7 +163,7 @@ module JSI
|
|
177
163
|
|
178
164
|
begin
|
179
165
|
if token_in_range
|
180
|
-
value_node = jsi_subinstance_memos[token]
|
166
|
+
value_node = jsi_subinstance_memos[token: token]
|
181
167
|
|
182
168
|
jsi_subinstance_as_jsi(value, value_node.jsi_schemas, as_jsi) do
|
183
169
|
value_node
|
@@ -194,7 +180,15 @@ module JSI
|
|
194
180
|
# in a (nondestructively) modified copy of this.
|
195
181
|
# @return [MetaschemaNode] modified copy of self
|
196
182
|
def jsi_modified_copy(&block)
|
197
|
-
|
183
|
+
if jsi_ptr.root?
|
184
|
+
modified_document = jsi_ptr.modified_document_copy(jsi_document, &block)
|
185
|
+
MetaschemaNode.new(modified_document, **our_initialize_params)
|
186
|
+
else
|
187
|
+
modified_jsi_root_node = jsi_root_node.jsi_modified_copy do |root|
|
188
|
+
jsi_ptr.modified_document_copy(root, &block)
|
189
|
+
end
|
190
|
+
modified_jsi_root_node.jsi_descendent_node(jsi_ptr)
|
191
|
+
end
|
198
192
|
end
|
199
193
|
|
200
194
|
# @private
|
@@ -219,25 +213,28 @@ module JSI
|
|
219
213
|
|
220
214
|
private
|
221
215
|
|
216
|
+
# note: does not include jsi_root_node
|
222
217
|
def our_initialize_params
|
223
218
|
{
|
224
219
|
jsi_ptr: jsi_ptr,
|
225
|
-
|
220
|
+
schema_implementation_modules: schema_implementation_modules,
|
226
221
|
metaschema_root_ptr: metaschema_root_ptr,
|
227
222
|
root_schema_ptr: root_schema_ptr,
|
228
223
|
jsi_schema_base_uri: jsi_schema_base_uri,
|
229
224
|
}
|
230
225
|
end
|
231
226
|
|
227
|
+
# note: not for root node
|
232
228
|
def new_node(params)
|
233
229
|
MetaschemaNode.new(jsi_document, **our_initialize_params.merge(params))
|
234
230
|
end
|
235
231
|
|
236
232
|
def jsi_subinstance_memos
|
237
|
-
jsi_memomap(:subinstance) do |token|
|
233
|
+
jsi_memomap(:subinstance) do |token: |
|
238
234
|
new_node(
|
239
235
|
jsi_ptr: jsi_ptr[token],
|
240
236
|
jsi_schema_base_uri: jsi_resource_ancestor_uri,
|
237
|
+
jsi_root_node: jsi_root_node,
|
241
238
|
)
|
242
239
|
end
|
243
240
|
end
|
data/lib/jsi/ptr.rb
CHANGED
@@ -31,7 +31,7 @@ module JSI
|
|
31
31
|
#
|
32
32
|
# JSI::Ptr[]
|
33
33
|
#
|
34
|
-
#
|
34
|
+
# instantiates a root pointer.
|
35
35
|
#
|
36
36
|
# JSI::Ptr['a', 'b']
|
37
37
|
# JSI::Ptr['a']['b']
|
@@ -99,9 +99,6 @@ module JSI
|
|
99
99
|
|
100
100
|
attr_reader :tokens
|
101
101
|
|
102
|
-
# @private @deprecated
|
103
|
-
alias_method :reference_tokens, :tokens
|
104
|
-
|
105
102
|
# takes a root json document and evaluates this pointer through the document, returning the value
|
106
103
|
# pointed to by this pointer.
|
107
104
|
#
|
@@ -109,9 +106,9 @@ module JSI
|
|
109
106
|
# @param a arguments are passed to each invocation of `#[]`
|
110
107
|
# @return [Object] the content of the document pointed to by this pointer
|
111
108
|
# @raise [JSI::Ptr::ResolutionError] the document does not contain the path this pointer references
|
112
|
-
def evaluate(document, *a)
|
109
|
+
def evaluate(document, *a, **kw)
|
113
110
|
res = tokens.inject(document) do |value, token|
|
114
|
-
_, child = node_subscript_token_child(value, token, *a)
|
111
|
+
_, child = node_subscript_token_child(value, token, *a, **kw)
|
115
112
|
child
|
116
113
|
end
|
117
114
|
res
|
@@ -151,28 +148,30 @@ module JSI
|
|
151
148
|
def parent
|
152
149
|
if root?
|
153
150
|
raise(Ptr::Error, "cannot access parent of root pointer: #{pretty_inspect.chomp}")
|
154
|
-
else
|
155
|
-
Ptr.new(tokens[0...-1])
|
156
151
|
end
|
152
|
+
Ptr.new(tokens[0...-1])
|
157
153
|
end
|
158
154
|
|
159
155
|
# whether this pointer contains the other_ptr - that is, whether this pointer is an ancestor
|
160
|
-
# of `other_ptr`, a
|
156
|
+
# of `other_ptr`, a descendent pointer. `contains?` is inclusive; a pointer does contain itself.
|
161
157
|
# @return [Boolean]
|
162
158
|
def contains?(other_ptr)
|
163
|
-
|
159
|
+
tokens == other_ptr.tokens[0...tokens.size]
|
164
160
|
end
|
165
161
|
|
166
162
|
# part of this pointer relative to the given ancestor_ptr
|
167
163
|
# @return [JSI::Ptr]
|
168
164
|
# @raise [JSI::Ptr::Error] if the given ancestor_ptr is not an ancestor of this pointer
|
169
|
-
def
|
165
|
+
def relative_to(ancestor_ptr)
|
170
166
|
unless ancestor_ptr.contains?(self)
|
171
167
|
raise(Error, "ancestor_ptr #{ancestor_ptr.inspect} is not ancestor of #{inspect}")
|
172
168
|
end
|
173
169
|
Ptr.new(tokens[ancestor_ptr.tokens.size..-1])
|
174
170
|
end
|
175
171
|
|
172
|
+
# @deprecated after v0.6
|
173
|
+
alias_method :ptr_relative_to, :relative_to
|
174
|
+
|
176
175
|
# a pointer with the tokens of this one plus the given `ptr`'s.
|
177
176
|
# @param ptr [JSI::Ptr, #to_ary]
|
178
177
|
# @return [JSI::Ptr]
|
@@ -182,9 +181,9 @@ module JSI
|
|
182
181
|
elsif ptr.respond_to?(:to_ary)
|
183
182
|
ptr_tokens = ptr
|
184
183
|
else
|
185
|
-
raise(TypeError, "ptr must be a
|
184
|
+
raise(TypeError, "ptr must be a #{Ptr} or Array of tokens; got: #{ptr.inspect}")
|
186
185
|
end
|
187
|
-
Ptr.new(
|
186
|
+
Ptr.new(tokens + ptr_tokens)
|
188
187
|
end
|
189
188
|
|
190
189
|
# a pointer consisting of the first `n` of our tokens
|
@@ -225,7 +224,7 @@ module JSI
|
|
225
224
|
# or hash in the path above the node we point to. this node's content is modified by the
|
226
225
|
# caller, and that is recursively merged up to the document root.
|
227
226
|
if empty?
|
228
|
-
|
227
|
+
Util.modified_copy(document, &block)
|
229
228
|
else
|
230
229
|
car = tokens[0]
|
231
230
|
cdr = Ptr.new(tokens[1..-1])
|
@@ -260,7 +259,7 @@ module JSI
|
|
260
259
|
|
261
260
|
private
|
262
261
|
|
263
|
-
def node_subscript_token_child(value, token, *a)
|
262
|
+
def node_subscript_token_child(value, token, *a, **kw)
|
264
263
|
if value.respond_to?(:to_ary)
|
265
264
|
if token.is_a?(String) && token =~ /\A\d|[1-9]\d+\z/
|
266
265
|
token = token.to_i
|
@@ -276,13 +275,25 @@ module JSI
|
|
276
275
|
raise(ResolutionError, "Invalid resolution: #{token.inspect} is not a valid index of #{value.inspect}")
|
277
276
|
end
|
278
277
|
|
279
|
-
|
278
|
+
ary = (value.respond_to?(:[]) ? value : value.to_ary)
|
279
|
+
if kw.empty?
|
280
|
+
# TODO remove eventually (keyword argument compatibility)
|
281
|
+
child = ary[token, *a]
|
282
|
+
else
|
283
|
+
child = ary[token, *a, **kw]
|
284
|
+
end
|
280
285
|
elsif value.respond_to?(:to_hash)
|
281
286
|
unless (value.respond_to?(:key?) ? value : value.to_hash).key?(token)
|
282
287
|
raise(ResolutionError, "Invalid resolution: #{token.inspect} is not a valid key of #{value.inspect}")
|
283
288
|
end
|
284
289
|
|
285
|
-
|
290
|
+
hsh = (value.respond_to?(:[]) ? value : value.to_hash)
|
291
|
+
if kw.empty?
|
292
|
+
# TODO remove eventually (keyword argument compatibility)
|
293
|
+
child = hsh[token, *a]
|
294
|
+
else
|
295
|
+
child = hsh[token, *a, **kw]
|
296
|
+
end
|
286
297
|
else
|
287
298
|
raise(ResolutionError, "Invalid resolution: #{token.inspect} cannot be resolved in #{value.inspect}")
|
288
299
|
end
|
@@ -4,11 +4,20 @@ module JSI
|
|
4
4
|
module Schema::Application::ChildApplication::Contains
|
5
5
|
# @private
|
6
6
|
def internal_applicate_contains(idx, instance, &block)
|
7
|
-
if
|
7
|
+
if keyword?('contains')
|
8
8
|
contains_schema = subschema(['contains'])
|
9
9
|
|
10
|
-
|
10
|
+
child_idx_valid = Hash.new { |h, i| h[i] = contains_schema.instance_valid?(instance[i]) }
|
11
|
+
|
12
|
+
if child_idx_valid[idx]
|
11
13
|
yield contains_schema
|
14
|
+
else
|
15
|
+
instance_valid = instance.each_index.any? { |i| child_idx_valid[i] }
|
16
|
+
|
17
|
+
unless instance_valid
|
18
|
+
# invalid application: if contains_schema does not validate against any child, it applies to every child
|
19
|
+
yield contains_schema
|
20
|
+
end
|
12
21
|
end
|
13
22
|
end
|
14
23
|
end
|
@@ -4,13 +4,13 @@ module JSI
|
|
4
4
|
module Schema::Application::ChildApplication::Items
|
5
5
|
# @private
|
6
6
|
def internal_applicate_items(idx, &block)
|
7
|
-
if schema_content['items'].respond_to?(:to_ary)
|
7
|
+
if keyword?('items') && schema_content['items'].respond_to?(:to_ary)
|
8
8
|
if schema_content['items'].each_index.to_a.include?(idx)
|
9
9
|
yield subschema(['items', idx])
|
10
|
-
elsif
|
10
|
+
elsif keyword?('additionalItems')
|
11
11
|
yield subschema(['additionalItems'])
|
12
12
|
end
|
13
|
-
elsif
|
13
|
+
elsif keyword?('items')
|
14
14
|
yield subschema(['items'])
|
15
15
|
end
|
16
16
|
end
|
@@ -5,11 +5,11 @@ module JSI
|
|
5
5
|
# @private
|
6
6
|
def internal_applicate_properties(property_name, &block)
|
7
7
|
apply_additional = true
|
8
|
-
if
|
8
|
+
if keyword?('properties') && schema_content['properties'].respond_to?(:to_hash) && schema_content['properties'].key?(property_name)
|
9
9
|
apply_additional = false
|
10
10
|
yield subschema(['properties', property_name])
|
11
11
|
end
|
12
|
-
if schema_content['patternProperties'].respond_to?(:to_hash)
|
12
|
+
if keyword?('patternProperties') && schema_content['patternProperties'].respond_to?(:to_hash)
|
13
13
|
schema_content['patternProperties'].each_key do |pattern|
|
14
14
|
if pattern.respond_to?(:to_str) && property_name.to_s =~ Regexp.new(pattern) # TODO map pattern to ruby syntax
|
15
15
|
apply_additional = false
|
@@ -17,7 +17,7 @@ module JSI
|
|
17
17
|
end
|
18
18
|
end
|
19
19
|
end
|
20
|
-
if apply_additional &&
|
20
|
+
if apply_additional && keyword?('additionalProperties')
|
21
21
|
yield subschema(['additionalProperties'])
|
22
22
|
end
|
23
23
|
end
|
@@ -30,9 +30,7 @@ module JSI
|
|
30
30
|
def each_child_applicator_schema(token, instance, &block)
|
31
31
|
return to_enum(__method__, token, instance) unless block
|
32
32
|
|
33
|
-
|
34
|
-
internal_child_applicate_keywords(token, instance, &block)
|
35
|
-
end
|
33
|
+
internal_child_applicate_keywords(token, instance, &block)
|
36
34
|
|
37
35
|
nil
|
38
36
|
end
|
@@ -4,7 +4,7 @@ module JSI
|
|
4
4
|
module Schema::Application::InplaceApplication::Dependencies
|
5
5
|
# @private
|
6
6
|
def internal_applicate_dependencies(instance, visited_refs, &block)
|
7
|
-
if
|
7
|
+
if keyword?('dependencies')
|
8
8
|
value = schema_content['dependencies']
|
9
9
|
# This keyword's value MUST be an object. Each property specifies a dependency. Each dependency
|
10
10
|
# value MUST be an array or a valid JSON Schema.
|
@@ -4,13 +4,13 @@ module JSI
|
|
4
4
|
module Schema::Application::InplaceApplication::IfThenElse
|
5
5
|
# @private
|
6
6
|
def internal_applicate_ifthenelse(instance, visited_refs, &block)
|
7
|
-
if
|
7
|
+
if keyword?('if')
|
8
8
|
if subschema(['if']).instance_valid?(instance)
|
9
|
-
if
|
9
|
+
if keyword?('then')
|
10
10
|
subschema(['then']).each_inplace_applicator_schema(instance, visited_refs: visited_refs, &block)
|
11
11
|
end
|
12
12
|
else
|
13
|
-
if
|
13
|
+
if keyword?('else')
|
14
14
|
subschema(['else']).each_inplace_applicator_schema(instance, visited_refs: visited_refs, &block)
|
15
15
|
end
|
16
16
|
end
|
@@ -4,7 +4,7 @@ module JSI
|
|
4
4
|
module Schema::Application::InplaceApplication::Ref
|
5
5
|
# @private
|
6
6
|
def internal_applicate_ref(instance, visited_refs, throw_done: false, &block)
|
7
|
-
if schema_content['$ref'].respond_to?(:to_str)
|
7
|
+
if keyword?('$ref') && schema_content['$ref'].respond_to?(:to_str)
|
8
8
|
ref = jsi_memoize(:ref) { Schema::Ref.new(schema_content['$ref'], self) }
|
9
9
|
unless visited_refs.include?(ref)
|
10
10
|
ref.deref_schema.each_inplace_applicator_schema(instance, visited_refs: visited_refs + [ref], &block)
|
@@ -4,24 +4,39 @@ module JSI
|
|
4
4
|
module Schema::Application::InplaceApplication::SomeOf
|
5
5
|
# @private
|
6
6
|
def internal_applicate_someOf(instance, visited_refs, &block)
|
7
|
-
if schema_content['allOf'].respond_to?(:to_ary)
|
7
|
+
if keyword?('allOf') && schema_content['allOf'].respond_to?(:to_ary)
|
8
8
|
schema_content['allOf'].each_index do |i|
|
9
9
|
subschema(['allOf', i]).each_inplace_applicator_schema(instance, visited_refs: visited_refs, &block)
|
10
10
|
end
|
11
11
|
end
|
12
|
-
if schema_content['anyOf'].respond_to?(:to_ary)
|
13
|
-
schema_content['anyOf'].each_index
|
14
|
-
|
15
|
-
|
16
|
-
|
12
|
+
if keyword?('anyOf') && schema_content['anyOf'].respond_to?(:to_ary)
|
13
|
+
anyOf = schema_content['anyOf'].each_index.map { |i| subschema(['anyOf', i]) }
|
14
|
+
validOf = anyOf.select { |schema| schema.instance_valid?(instance) }
|
15
|
+
if !validOf.empty?
|
16
|
+
applicators = validOf
|
17
|
+
else
|
18
|
+
# invalid application: if none of the anyOf were valid, we apply them all
|
19
|
+
applicators = anyOf
|
20
|
+
end
|
21
|
+
|
22
|
+
applicators.each do |applicator|
|
23
|
+
applicator.each_inplace_applicator_schema(instance, visited_refs: visited_refs, &block)
|
17
24
|
end
|
18
25
|
end
|
19
|
-
if schema_content['oneOf'].respond_to?(:to_ary)
|
20
|
-
|
21
|
-
|
26
|
+
if keyword?('oneOf') && schema_content['oneOf'].respond_to?(:to_ary)
|
27
|
+
oneOf_idxs = schema_content['oneOf'].each_index
|
28
|
+
subschema_idx_valid = Hash.new { |h, i| h[i] = subschema(['oneOf', i]).instance_valid?(instance) }
|
29
|
+
# count up to 2 `oneOf` subschemas which `instance` validates against
|
30
|
+
nvalid = oneOf_idxs.inject(0) { |n, i| n > 1 ? n : subschema_idx_valid[i] ? n + 1 : n }
|
31
|
+
if nvalid == 1
|
32
|
+
applicator_idxs = oneOf_idxs.select { |i| subschema_idx_valid[i] }
|
33
|
+
else
|
34
|
+
# invalid application: if none or multiple of the oneOf were valid, we apply them all
|
35
|
+
applicator_idxs = oneOf_idxs
|
22
36
|
end
|
23
|
-
|
24
|
-
|
37
|
+
|
38
|
+
applicator_idxs.each do |i|
|
39
|
+
subschema(['oneOf', i]).each_inplace_applicator_schema(instance, visited_refs: visited_refs, &block)
|
25
40
|
end
|
26
41
|
end
|
27
42
|
end
|
@@ -32,12 +32,7 @@ module JSI
|
|
32
32
|
return to_enum(__method__, instance, visited_refs: visited_refs) unless block
|
33
33
|
|
34
34
|
catch(:jsi_application_done) do
|
35
|
-
|
36
|
-
internal_inplace_applicate_keywords(instance, visited_refs, &block)
|
37
|
-
else
|
38
|
-
# self is the only applicator schema if there are no keywords
|
39
|
-
yield self
|
40
|
-
end
|
35
|
+
internal_inplace_applicate_keywords(instance, visited_refs, &block)
|
41
36
|
end
|
42
37
|
|
43
38
|
nil
|
data/lib/jsi/schema/ref.rb
CHANGED
@@ -53,7 +53,6 @@ module JSI
|
|
53
53
|
resolve_fragment_ptr = ref_schema.method(:resource_root_subschema)
|
54
54
|
else
|
55
55
|
# find the schema_resource_root from the non-fragment URI. we will resolve any fragment, either pointer or anchor, from there.
|
56
|
-
schema_resource_root = nil
|
57
56
|
|
58
57
|
if ref_uri_nofrag.absolute?
|
59
58
|
ref_abs_uri = ref_uri_nofrag
|
@@ -84,7 +83,7 @@ module JSI
|
|
84
83
|
else
|
85
84
|
# Note: Schema#resource_root_subschema will reinstantiate nonschemas as schemas.
|
86
85
|
# not implemented for remote refs when the schema_resource_root is not a schema.
|
87
|
-
resolve_fragment_ptr = -> (ptr) {
|
86
|
+
resolve_fragment_ptr = -> (ptr) { schema_resource_root.jsi_descendent_node(ptr) }
|
88
87
|
end
|
89
88
|
end
|
90
89
|
|
@@ -140,6 +139,8 @@ module JSI
|
|
140
139
|
%Q(\#<#{self.class.name} #{ref}>)
|
141
140
|
end
|
142
141
|
|
142
|
+
alias_method :to_s, :inspect
|
143
|
+
|
143
144
|
# pretty-prints a representation of self to the given printer
|
144
145
|
# @return [void]
|
145
146
|
def pretty_print(q)
|
@@ -7,16 +7,16 @@ module JSI
|
|
7
7
|
# the base URI used to resolve the ids of schemas at or below this JSI.
|
8
8
|
# this is always an absolute URI (with no fragment).
|
9
9
|
# this may be the absolute schema URI of a parent schema or the URI from which the document was retrieved.
|
10
|
-
# @private
|
10
|
+
# @api private
|
11
11
|
# @return [Addressable::URI, nil]
|
12
12
|
attr_reader :jsi_schema_base_uri
|
13
13
|
|
14
14
|
# resources which are ancestors of this JSI in the document. this does not include self.
|
15
|
-
# @private
|
15
|
+
# @api private
|
16
16
|
# @return [Array<JSI::Schema>]
|
17
17
|
def jsi_schema_resource_ancestors
|
18
18
|
return @jsi_schema_resource_ancestors if instance_variable_defined?(:@jsi_schema_resource_ancestors)
|
19
|
-
|
19
|
+
Util::EMPTY_ARY
|
20
20
|
end
|
21
21
|
|
22
22
|
# the URI of the resource containing this node.
|
@@ -25,18 +25,14 @@ module JSI
|
|
25
25
|
# or nil if not contained by a resource with a URI.
|
26
26
|
# @return [Addressable::URI, nil]
|
27
27
|
def jsi_resource_ancestor_uri
|
28
|
-
|
29
|
-
schema_absolute_uri
|
30
|
-
else
|
31
|
-
jsi_schema_base_uri
|
32
|
-
end
|
28
|
+
(is_a?(Schema) && schema_absolute_uri) || jsi_schema_base_uri
|
33
29
|
end
|
34
30
|
|
35
31
|
# a schema at or below this node with the given anchor.
|
36
32
|
#
|
37
33
|
# @return [JSI::Schema, nil]
|
38
34
|
def jsi_anchor_subschema(anchor)
|
39
|
-
subschemas = jsi_anchor_subschemas_map[anchor]
|
35
|
+
subschemas = jsi_anchor_subschemas_map[anchor: anchor]
|
40
36
|
if subschemas.size == 1
|
41
37
|
subschemas.first
|
42
38
|
else
|
@@ -48,7 +44,7 @@ module JSI
|
|
48
44
|
#
|
49
45
|
# @return [Array<JSI::Schema>]
|
50
46
|
def jsi_anchor_subschemas(anchor)
|
51
|
-
jsi_anchor_subschemas_map[anchor]
|
47
|
+
jsi_anchor_subschemas_map[anchor: anchor]
|
52
48
|
end
|
53
49
|
|
54
50
|
private
|
@@ -58,9 +54,7 @@ module JSI
|
|
58
54
|
end
|
59
55
|
|
60
56
|
def jsi_ptr=(jsi_ptr)
|
61
|
-
unless jsi_ptr.is_a?(Ptr)
|
62
|
-
raise(TypeError, "jsi_ptr must be a JSI::Ptr; got: #{jsi_ptr.inspect}")
|
63
|
-
end
|
57
|
+
raise(Bug, "jsi_ptr not #{Ptr}: #{jsi_ptr.inspect}") unless jsi_ptr.is_a?(Ptr)
|
64
58
|
@jsi_ptr = jsi_ptr
|
65
59
|
end
|
66
60
|
|
@@ -83,7 +77,7 @@ module JSI
|
|
83
77
|
unless jsi_schema_resource_ancestors.respond_to?(:to_ary)
|
84
78
|
raise(TypeError, "jsi_schema_resource_ancestors must be an array; got: #{jsi_schema_resource_ancestors.inspect}")
|
85
79
|
end
|
86
|
-
jsi_schema_resource_ancestors.each { |a| Schema.ensure_schema(a)
|
80
|
+
jsi_schema_resource_ancestors.each { |a| Schema.ensure_schema(a) }
|
87
81
|
# sanity check the ancestors are in order
|
88
82
|
last_anc_ptr = nil
|
89
83
|
jsi_schema_resource_ancestors.each do |anc|
|
@@ -104,13 +98,13 @@ module JSI
|
|
104
98
|
|
105
99
|
@jsi_schema_resource_ancestors = jsi_schema_resource_ancestors.to_ary.freeze
|
106
100
|
else
|
107
|
-
@jsi_schema_resource_ancestors =
|
101
|
+
@jsi_schema_resource_ancestors = Util::EMPTY_ARY
|
108
102
|
end
|
109
103
|
end
|
110
104
|
|
111
105
|
def jsi_anchor_subschemas_map
|
112
|
-
jsi_memomap(__method__) do |anchor|
|
113
|
-
|
106
|
+
jsi_memomap(__method__) do |anchor: |
|
107
|
+
jsi_each_descendent_node.select do |node|
|
114
108
|
node.is_a?(Schema) && node.respond_to?(:anchor) && node.anchor == anchor
|
115
109
|
end.freeze
|
116
110
|
end
|
@@ -4,7 +4,7 @@ module JSI
|
|
4
4
|
module Schema::Validation::ArrayLength
|
5
5
|
# @private
|
6
6
|
def internal_validate_maxItems(result_builder)
|
7
|
-
if
|
7
|
+
if keyword?('maxItems')
|
8
8
|
value = schema_content['maxItems']
|
9
9
|
# The value of this keyword MUST be a non-negative integer.
|
10
10
|
if internal_integer?(value) && value >= 0
|
@@ -24,7 +24,7 @@ module JSI
|
|
24
24
|
|
25
25
|
# @private
|
26
26
|
def internal_validate_minItems(result_builder)
|
27
|
-
if
|
27
|
+
if keyword?('minItems')
|
28
28
|
value = schema_content['minItems']
|
29
29
|
# The value of this keyword MUST be a non-negative integer.
|
30
30
|
if internal_integer?(value) && value >= 0
|
@@ -45,7 +45,7 @@ module JSI
|
|
45
45
|
module Schema::Validation::UniqueItems
|
46
46
|
# @private
|
47
47
|
def internal_validate_uniqueItems(result_builder)
|
48
|
-
if
|
48
|
+
if keyword?('uniqueItems')
|
49
49
|
value = schema_content['uniqueItems']
|
50
50
|
# The value of this keyword MUST be a boolean.
|
51
51
|
if value == false
|