jsi 0.4.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/.yardopts +1 -1
- data/CHANGELOG.md +33 -0
- data/LICENSE.md +1 -1
- data/README.md +114 -42
- data/jsi.gemspec +14 -12
- data/lib/jsi/base/node.rb +183 -0
- data/lib/jsi/base.rb +388 -220
- data/lib/jsi/jsi_coder.rb +8 -7
- data/lib/jsi/metaschema.rb +0 -1
- data/lib/jsi/metaschema_node/bootstrap_schema.rb +101 -0
- data/lib/jsi/metaschema_node.rb +159 -135
- data/lib/jsi/ptr.rb +303 -0
- data/lib/jsi/schema/application/child_application/contains.rb +25 -0
- data/lib/jsi/schema/application/child_application/draft04.rb +22 -0
- data/lib/jsi/schema/application/child_application/draft06.rb +29 -0
- data/lib/jsi/schema/application/child_application/draft07.rb +29 -0
- data/lib/jsi/schema/application/child_application/items.rb +18 -0
- data/lib/jsi/schema/application/child_application/properties.rb +25 -0
- data/lib/jsi/schema/application/child_application.rb +38 -0
- data/lib/jsi/schema/application/draft04.rb +8 -0
- data/lib/jsi/schema/application/draft06.rb +8 -0
- data/lib/jsi/schema/application/draft07.rb +8 -0
- data/lib/jsi/schema/application/inplace_application/dependencies.rb +28 -0
- data/lib/jsi/schema/application/inplace_application/draft04.rb +26 -0
- data/lib/jsi/schema/application/inplace_application/draft06.rb +27 -0
- data/lib/jsi/schema/application/inplace_application/draft07.rb +33 -0
- data/lib/jsi/schema/application/inplace_application/ifthenelse.rb +20 -0
- data/lib/jsi/schema/application/inplace_application/ref.rb +18 -0
- data/lib/jsi/schema/application/inplace_application/someof.rb +44 -0
- data/lib/jsi/schema/application/inplace_application.rb +41 -0
- data/lib/jsi/schema/application.rb +12 -0
- data/lib/jsi/schema/draft04.rb +14 -0
- data/lib/jsi/schema/draft06.rb +14 -0
- data/lib/jsi/schema/draft07.rb +14 -0
- data/lib/jsi/schema/issue.rb +36 -0
- data/lib/jsi/schema/ref.rb +160 -0
- data/lib/jsi/schema/schema_ancestor_node.rb +113 -0
- data/lib/jsi/schema/validation/array.rb +69 -0
- data/lib/jsi/schema/validation/const.rb +20 -0
- data/lib/jsi/schema/validation/contains.rb +25 -0
- data/lib/jsi/schema/validation/core.rb +39 -0
- data/lib/jsi/schema/validation/dependencies.rb +49 -0
- data/lib/jsi/schema/validation/draft04/minmax.rb +91 -0
- data/lib/jsi/schema/validation/draft04.rb +112 -0
- data/lib/jsi/schema/validation/draft06.rb +122 -0
- data/lib/jsi/schema/validation/draft07.rb +159 -0
- data/lib/jsi/schema/validation/enum.rb +25 -0
- data/lib/jsi/schema/validation/ifthenelse.rb +46 -0
- data/lib/jsi/schema/validation/items.rb +54 -0
- data/lib/jsi/schema/validation/not.rb +20 -0
- data/lib/jsi/schema/validation/numeric.rb +121 -0
- data/lib/jsi/schema/validation/object.rb +45 -0
- data/lib/jsi/schema/validation/pattern.rb +34 -0
- data/lib/jsi/schema/validation/properties.rb +101 -0
- data/lib/jsi/schema/validation/property_names.rb +32 -0
- data/lib/jsi/schema/validation/ref.rb +40 -0
- data/lib/jsi/schema/validation/required.rb +27 -0
- data/lib/jsi/schema/validation/someof.rb +90 -0
- data/lib/jsi/schema/validation/string.rb +47 -0
- data/lib/jsi/schema/validation/type.rb +49 -0
- data/lib/jsi/schema/validation.rb +51 -0
- data/lib/jsi/schema.rb +508 -149
- data/lib/jsi/schema_classes.rb +199 -59
- data/lib/jsi/schema_registry.rb +151 -0
- data/lib/jsi/schema_set.rb +181 -0
- data/lib/jsi/simple_wrap.rb +23 -4
- data/lib/jsi/util/private/attr_struct.rb +127 -0
- data/lib/jsi/util/private.rb +204 -0
- data/lib/jsi/util/typelike.rb +229 -0
- data/lib/jsi/util.rb +89 -53
- data/lib/jsi/validation/error.rb +34 -0
- data/lib/jsi/validation/result.rb +210 -0
- data/lib/jsi/validation.rb +15 -0
- data/lib/jsi/version.rb +3 -1
- data/lib/jsi.rb +44 -14
- data/lib/schemas/json-schema.org/draft-04/schema.rb +10 -3
- data/lib/schemas/json-schema.org/draft-06/schema.rb +10 -3
- data/lib/schemas/json-schema.org/draft-07/schema.rb +14 -0
- data/readme.rb +138 -0
- data/{resources}/schemas/json-schema.org/draft-04/schema.json +149 -0
- data/{resources}/schemas/json-schema.org/draft-06/schema.json +154 -0
- data/{resources}/schemas/json-schema.org/draft-07/schema.json +168 -0
- metadata +75 -122
- data/.simplecov +0 -3
- data/Rakefile.rb +0 -9
- data/lib/jsi/base/to_rb.rb +0 -128
- data/lib/jsi/json/node.rb +0 -203
- data/lib/jsi/json/pointer.rb +0 -419
- data/lib/jsi/json-schema-fragments.rb +0 -61
- data/lib/jsi/json.rb +0 -10
- data/lib/jsi/pathed_node.rb +0 -118
- data/lib/jsi/typelike_modules.rb +0 -240
- data/resources/icons/AGPL-3.0.png +0 -0
- data/test/base_array_test.rb +0 -323
- data/test/base_hash_test.rb +0 -337
- data/test/base_test.rb +0 -486
- data/test/jsi_coder_test.rb +0 -85
- data/test/jsi_json_arraynode_test.rb +0 -150
- data/test/jsi_json_hashnode_test.rb +0 -132
- data/test/jsi_json_node_test.rb +0 -257
- data/test/jsi_json_pointer_test.rb +0 -102
- data/test/jsi_test.rb +0 -11
- data/test/jsi_typelike_as_json_test.rb +0 -53
- data/test/metaschema_node_test.rb +0 -19
- data/test/schema_module_test.rb +0 -21
- data/test/schema_test.rb +0 -208
- data/test/spreedly_openapi_test.rb +0 -8
- data/test/test_helper.rb +0 -97
- data/test/util_test.rb +0 -62
data/lib/jsi/jsi_coder.rb
CHANGED
|
@@ -11,7 +11,7 @@ module JSI
|
|
|
11
11
|
# `preferences_json` which is an actual json column, and `preferences_txt`
|
|
12
12
|
# which is a string:
|
|
13
13
|
#
|
|
14
|
-
# Preferences = JSI.
|
|
14
|
+
# Preferences = JSI.new_schema_module(preferences_json_schema)
|
|
15
15
|
# class Foo < ActiveRecord::Base
|
|
16
16
|
# # as a single serializer, loads a Preferences instance from a json column
|
|
17
17
|
# serialize 'preferences_json', JSI::JSICoder.new(Preferences)
|
|
@@ -25,13 +25,13 @@ module JSI
|
|
|
25
25
|
# (represented as one json object) or an array of them (represented as a json
|
|
26
26
|
# array of json objects), indicated by the keyword argument `array`.
|
|
27
27
|
class JSICoder
|
|
28
|
-
# @param schema [
|
|
29
|
-
#
|
|
28
|
+
# @param schema [#new_jsi] a Schema, SchemaSet, or JSI schema module. #load
|
|
29
|
+
# will instantiate column data using the JSI schemas represented.
|
|
30
30
|
# @param array [Boolean] whether the dumped data represent one instance of the schema,
|
|
31
31
|
# or an array of them. note that it may be preferable to simply use an array schema.
|
|
32
32
|
def initialize(schema, array: false)
|
|
33
33
|
unless schema.respond_to?(:new_jsi)
|
|
34
|
-
raise(ArgumentError, "
|
|
34
|
+
raise(ArgumentError, "schema param does not respond to #new_jsi: #{schema.inspect}")
|
|
35
35
|
end
|
|
36
36
|
@schema = schema
|
|
37
37
|
@array = array
|
|
@@ -48,13 +48,14 @@ module JSI
|
|
|
48
48
|
unless data.respond_to?(:to_ary)
|
|
49
49
|
raise TypeError, "expected array-like column data; got: #{data.class}: #{data.inspect}"
|
|
50
50
|
end
|
|
51
|
-
data.map { |el| load_object(el) }
|
|
51
|
+
data.to_ary.map { |el| load_object(el) }
|
|
52
52
|
else
|
|
53
53
|
load_object(data)
|
|
54
54
|
end
|
|
55
55
|
object
|
|
56
56
|
end
|
|
57
57
|
|
|
58
|
+
# dumps the object for the database
|
|
58
59
|
# @param object [JSI::Base, Array<JSI::Base>, nil] the JSI or array of JSIs containing
|
|
59
60
|
# the schema instance(s)
|
|
60
61
|
# @return [Object, Array, nil] the schema instance(s) of the JSI(s), or nil if object is nil
|
|
@@ -65,7 +66,7 @@ module JSI
|
|
|
65
66
|
unless object.respond_to?(:to_ary)
|
|
66
67
|
raise(TypeError, "expected array-like attribute; got: #{object.class}: #{object.inspect}")
|
|
67
68
|
end
|
|
68
|
-
object.map do |el|
|
|
69
|
+
object.to_ary.map do |el|
|
|
69
70
|
dump_object(el)
|
|
70
71
|
end
|
|
71
72
|
else
|
|
@@ -85,7 +86,7 @@ module JSI
|
|
|
85
86
|
# @param object [JSI::Base, Object]
|
|
86
87
|
# @return [Object]
|
|
87
88
|
def dump_object(object)
|
|
88
|
-
JSI::
|
|
89
|
+
JSI::Util.as_json(object)
|
|
89
90
|
end
|
|
90
91
|
end
|
|
91
92
|
end
|
data/lib/jsi/metaschema.rb
CHANGED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module JSI
|
|
4
|
+
# internal class to bootstrap a metaschema. represents a schema without the complexity of JSI::Base. the
|
|
5
|
+
# schema is represented but schemas describing the schema are not.
|
|
6
|
+
#
|
|
7
|
+
# this class is to only be instantiated on nodes in the document that are known to be schemas.
|
|
8
|
+
# Schema#subschema and Schema#resource_root_subschema are the intended mechanisms to instantiate subschemas
|
|
9
|
+
# and resolve references. #[] and #jsi_root_node are not implemented.
|
|
10
|
+
#
|
|
11
|
+
# schema implementation modules are attached to generated subclasses of BootstrapSchema by
|
|
12
|
+
# {SchemaClasses.bootstrap_schema_class}. that subclass is instantiated with a document and
|
|
13
|
+
# pointer, representing a schema.
|
|
14
|
+
#
|
|
15
|
+
# @api private
|
|
16
|
+
class MetaschemaNode::BootstrapSchema
|
|
17
|
+
include Util::Memoize
|
|
18
|
+
include Util::FingerprintHash
|
|
19
|
+
include Schema::SchemaAncestorNode
|
|
20
|
+
|
|
21
|
+
class << self
|
|
22
|
+
def inspect
|
|
23
|
+
if self == MetaschemaNode::BootstrapSchema
|
|
24
|
+
name
|
|
25
|
+
else
|
|
26
|
+
"#{name || MetaschemaNode::BootstrapSchema.name} (#{schema_implementation_modules.map(&:inspect).join(', ')})"
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
alias_method :to_s, :inspect
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# @param jsi_ptr [JSI::Ptr] pointer to the schema in the document
|
|
34
|
+
# @param jsi_document [#to_hash, #to_ary, Boolean, Object] document containing the schema
|
|
35
|
+
def initialize(
|
|
36
|
+
jsi_document,
|
|
37
|
+
jsi_ptr: Ptr[],
|
|
38
|
+
jsi_schema_base_uri: nil
|
|
39
|
+
)
|
|
40
|
+
raise(Bug, "no #schema_implementation_modules") unless respond_to?(:schema_implementation_modules)
|
|
41
|
+
|
|
42
|
+
jsi_initialize_memos
|
|
43
|
+
|
|
44
|
+
self.jsi_ptr = jsi_ptr
|
|
45
|
+
self.jsi_document = jsi_document
|
|
46
|
+
self.jsi_schema_base_uri = jsi_schema_base_uri
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# document containing the schema content
|
|
50
|
+
attr_reader :jsi_document
|
|
51
|
+
|
|
52
|
+
# JSI::Ptr pointing to this schema within the document
|
|
53
|
+
attr_reader :jsi_ptr
|
|
54
|
+
|
|
55
|
+
def jsi_node_content
|
|
56
|
+
jsi_ptr.evaluate(jsi_document)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# @return [String]
|
|
60
|
+
def inspect
|
|
61
|
+
"\#<#{jsi_object_group_text.join(' ')} #{schema_content.inspect}>"
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
alias_method :to_s, :inspect
|
|
65
|
+
|
|
66
|
+
# pretty-prints a representation of self to the given printer
|
|
67
|
+
# @return [void]
|
|
68
|
+
def pretty_print(q)
|
|
69
|
+
q.text '#<'
|
|
70
|
+
q.text jsi_object_group_text.join(' ')
|
|
71
|
+
q.group_sub {
|
|
72
|
+
q.nest(2) {
|
|
73
|
+
q.breakable ' '
|
|
74
|
+
q.pp schema_content
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
q.breakable ''
|
|
78
|
+
q.text '>'
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# @private
|
|
82
|
+
# @return [Array<String>]
|
|
83
|
+
def jsi_object_group_text
|
|
84
|
+
[
|
|
85
|
+
self.class.name || MetaschemaNode::BootstrapSchema.name,
|
|
86
|
+
"(#{schema_implementation_modules.map(&:inspect).join(', ')})",
|
|
87
|
+
jsi_ptr.uri,
|
|
88
|
+
]
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# @private
|
|
92
|
+
def jsi_fingerprint
|
|
93
|
+
{
|
|
94
|
+
class: self.class,
|
|
95
|
+
jsi_ptr: @jsi_ptr,
|
|
96
|
+
jsi_document: @jsi_document,
|
|
97
|
+
schema_implementation_modules: schema_implementation_modules,
|
|
98
|
+
}
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
data/lib/jsi/metaschema_node.rb
CHANGED
|
@@ -1,218 +1,242 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module JSI
|
|
4
|
-
# a MetaschemaNode is a
|
|
5
|
-
# as with any PathedNode the node_ptr points to the content of a node.
|
|
4
|
+
# a MetaschemaNode is a JSI instance representing a node in a document which contains a metaschema.
|
|
6
5
|
# the root of the metaschema is pointed to by metaschema_root_ptr.
|
|
7
|
-
# the schema
|
|
6
|
+
# the schema describing the root of the document is pointed to by root_schema_ptr.
|
|
8
7
|
#
|
|
9
|
-
# like JSI::Base, this class represents an instance of a schema, an instance
|
|
10
|
-
# which may itself be a schema. unlike JSI::Base, the document containing the
|
|
11
|
-
#
|
|
8
|
+
# like JSI::Base's normal subclasses, this class represents an instance of a schema set, an instance
|
|
9
|
+
# which may itself be a schema. unlike JSI::Base, the document containing the instance and its schemas
|
|
10
|
+
# is the same, and a schema (the metaschema) may be an instance of itself.
|
|
12
11
|
#
|
|
13
|
-
# the
|
|
14
|
-
#
|
|
12
|
+
# unlike JSI::Base's normal subclasses, the schemas describing the instance are not part of the class.
|
|
13
|
+
# since the metaschema describes itself, attempting to construct a class from the JSI Schema Module of a
|
|
14
|
+
# schema which is itself an instance of that class results in a causality loop.
|
|
15
|
+
# instead, a MetaschemaNode calculates its {#jsi_schemas} and extends itself with their JSI Schema
|
|
16
|
+
# modules during initialization.
|
|
17
|
+
# the MetaschemaNode of the metaschema is extended with its own JSI Schema Module.
|
|
15
18
|
#
|
|
16
|
-
#
|
|
17
|
-
#
|
|
18
|
-
# unlike with JSI::Base, the schema is not part of the class, since a metaschema
|
|
19
|
-
# needs the ability to have its schema be the instance itself.
|
|
20
|
-
#
|
|
21
|
-
# if the MetaschemaNode's schema is its self, it will be extended with JSI::Metaschema.
|
|
19
|
+
# if the MetaschemaNode's schemas include its self, it is extended with JSI::Metaschema.
|
|
22
20
|
#
|
|
23
21
|
# a MetaschemaNode is extended with JSI::Schema when it represents a schema - this is the case when
|
|
24
|
-
#
|
|
25
|
-
class MetaschemaNode
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
#
|
|
30
|
-
#
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
#
|
|
34
|
-
#
|
|
35
|
-
# @param metaschema_root_ptr [JSI::
|
|
36
|
-
# @param root_schema_ptr [JSI::
|
|
37
|
-
def initialize(
|
|
38
|
-
|
|
39
|
-
|
|
22
|
+
# the metaschema is one of its schemas.
|
|
23
|
+
class MetaschemaNode < Base
|
|
24
|
+
autoload :BootstrapSchema, 'jsi/metaschema_node/bootstrap_schema'
|
|
25
|
+
|
|
26
|
+
# @param jsi_document the document containing the metaschema
|
|
27
|
+
# @param jsi_ptr [JSI::Ptr] ptr to this MetaschemaNode in jsi_document
|
|
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`.
|
|
33
|
+
# @param metaschema_root_ptr [JSI::Ptr] ptr to the root of the metaschema in the jsi_document
|
|
34
|
+
# @param root_schema_ptr [JSI::Ptr] ptr to the schema describing the root of the jsi_document
|
|
35
|
+
def initialize(
|
|
36
|
+
jsi_document,
|
|
37
|
+
jsi_ptr: Ptr[],
|
|
38
|
+
schema_implementation_modules: ,
|
|
39
|
+
metaschema_root_ptr: Ptr[],
|
|
40
|
+
root_schema_ptr: Ptr[],
|
|
41
|
+
jsi_schema_base_uri: nil,
|
|
42
|
+
jsi_root_node: nil
|
|
43
|
+
)
|
|
44
|
+
jsi_initialize_memos
|
|
45
|
+
|
|
46
|
+
self.jsi_document = jsi_document
|
|
47
|
+
self.jsi_ptr = jsi_ptr
|
|
48
|
+
@schema_implementation_modules = Util.ensure_module_set(schema_implementation_modules)
|
|
40
49
|
@metaschema_root_ptr = metaschema_root_ptr
|
|
41
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
|
|
53
|
+
|
|
54
|
+
if jsi_ptr.root? && jsi_schema_base_uri
|
|
55
|
+
raise(NotImplementedError, "unsupported jsi_schema_base_uri on metaschema document root")
|
|
56
|
+
end
|
|
57
|
+
self.jsi_schema_base_uri = jsi_schema_base_uri
|
|
58
|
+
|
|
59
|
+
jsi_node_content = self.jsi_node_content
|
|
42
60
|
|
|
43
|
-
|
|
61
|
+
if jsi_node_content.respond_to?(:to_hash)
|
|
62
|
+
extend HashNode
|
|
63
|
+
end
|
|
64
|
+
if jsi_node_content.respond_to?(:to_ary)
|
|
65
|
+
extend ArrayNode
|
|
66
|
+
end
|
|
44
67
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
68
|
+
instance_for_schemas = jsi_document
|
|
69
|
+
bootstrap_schema_class = JSI::SchemaClasses.bootstrap_schema_class(schema_implementation_modules)
|
|
70
|
+
root_bootstrap_schema = bootstrap_schema_class.new(
|
|
71
|
+
jsi_document,
|
|
72
|
+
jsi_ptr: root_schema_ptr,
|
|
73
|
+
jsi_schema_base_uri: nil, # supplying jsi_schema_base_uri on root bootstrap schema is not supported
|
|
74
|
+
)
|
|
75
|
+
our_bootstrap_schemas = jsi_ptr.tokens.inject(SchemaSet[root_bootstrap_schema]) do |bootstrap_schemas, tok|
|
|
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
|
|
49
80
|
end
|
|
50
81
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
82
|
+
our_bootstrap_schemas.each do |bootstrap_schema|
|
|
83
|
+
if bootstrap_schema.jsi_ptr == metaschema_root_ptr
|
|
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
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
if bootstrap_schema.jsi_ptr == jsi_ptr
|
|
90
|
+
# this is the metaschema (it is described by itself)
|
|
91
|
+
extend Metaschema
|
|
61
92
|
end
|
|
62
|
-
instance_for_schema = instance_for_schema[tok]
|
|
63
|
-
ptrs_for_instance = subschema_ptrs_for_token.map do |ptr|
|
|
64
|
-
ptr.schema_match_ptrs_to_instance(node_document, instance_for_schema)
|
|
65
|
-
end.inject(Set.new, &:|)
|
|
66
|
-
ptrs_for_instance
|
|
67
93
|
end
|
|
68
94
|
|
|
69
|
-
@jsi_schemas =
|
|
70
|
-
if
|
|
95
|
+
@jsi_schemas = SchemaSet.new(our_bootstrap_schemas) do |bootstrap_schema|
|
|
96
|
+
if bootstrap_schema.jsi_ptr == jsi_ptr
|
|
71
97
|
self
|
|
98
|
+
elsif bootstrap_schema.jsi_ptr.root?
|
|
99
|
+
@jsi_root_node
|
|
72
100
|
else
|
|
73
|
-
new_node(
|
|
101
|
+
new_node(
|
|
102
|
+
jsi_ptr: bootstrap_schema.jsi_ptr,
|
|
103
|
+
jsi_schema_base_uri: bootstrap_schema.jsi_schema_base_uri,
|
|
104
|
+
jsi_root_node: @jsi_root_node,
|
|
105
|
+
)
|
|
74
106
|
end
|
|
75
|
-
end
|
|
107
|
+
end
|
|
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
|
|
76
113
|
|
|
77
114
|
@jsi_schemas.each do |schema|
|
|
78
|
-
|
|
79
|
-
extend JSI::Schema
|
|
80
|
-
end
|
|
81
|
-
if schema.node_ptr == node_ptr
|
|
82
|
-
extend Metaschema
|
|
83
|
-
end
|
|
84
|
-
extend(JSI::SchemaClasses.accessor_module_for_schema(schema, conflicting_modules: [Metaschema, Schema, MetaschemaNode, PathedArrayNode, PathedHashNode]))
|
|
115
|
+
extend schema.jsi_schema_module
|
|
85
116
|
end
|
|
86
117
|
|
|
87
118
|
# workarounds
|
|
88
119
|
begin # draft 4 boolean schema workaround
|
|
89
120
|
# in draft 4, boolean schemas are not described in the root, but on anyOf schemas on
|
|
90
121
|
# properties/additionalProperties and properties/additionalItems.
|
|
91
|
-
#
|
|
122
|
+
# these still describe schemas, despite not being described by the metaschema.
|
|
92
123
|
addtlPropsanyOf = metaschema_root_ptr["properties"]["additionalProperties"]["anyOf"]
|
|
93
124
|
addtlItemsanyOf = metaschema_root_ptr["properties"]["additionalItems"]["anyOf"]
|
|
94
125
|
|
|
95
|
-
if !
|
|
96
|
-
|
|
126
|
+
if !jsi_ptr.root? && [addtlPropsanyOf, addtlItemsanyOf].include?(jsi_ptr.parent)
|
|
127
|
+
describes_schema!(schema_implementation_modules)
|
|
97
128
|
end
|
|
98
129
|
end
|
|
99
130
|
end
|
|
100
131
|
|
|
101
|
-
#
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
# ptr to the root of the metaschema in the
|
|
132
|
+
# Set of modules to apply to schemas which are instances of (described by) the metaschema
|
|
133
|
+
# @return [Set<Module>]
|
|
134
|
+
attr_reader :schema_implementation_modules
|
|
135
|
+
|
|
136
|
+
# ptr to the root of the metaschema in the jsi_document
|
|
137
|
+
# @return [JSI::Ptr]
|
|
106
138
|
attr_reader :metaschema_root_ptr
|
|
107
|
-
# ptr to the schema of the root of the node_document
|
|
108
|
-
attr_reader :root_schema_ptr
|
|
109
|
-
# JSI::Schemas describing this MetaschemaNode
|
|
110
|
-
attr_reader :jsi_schemas
|
|
111
139
|
|
|
112
|
-
#
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
end
|
|
140
|
+
# ptr to the schema of the root of the jsi_document
|
|
141
|
+
# @return [JSI::Ptr]
|
|
142
|
+
attr_reader :root_schema_ptr
|
|
116
143
|
|
|
117
|
-
#
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
end
|
|
144
|
+
# JSI Schemas describing this MetaschemaNode
|
|
145
|
+
# @return [JSI::SchemaSet]
|
|
146
|
+
attr_reader :jsi_schemas
|
|
121
147
|
|
|
122
|
-
#
|
|
123
|
-
#
|
|
124
|
-
#
|
|
125
|
-
#
|
|
126
|
-
|
|
148
|
+
# subscripts to return a child value identified by the given token.
|
|
149
|
+
#
|
|
150
|
+
# @param token (see JSI::Base#[])
|
|
151
|
+
# @param as_jsi (see JSI::Base#[])
|
|
152
|
+
# @return (see JSI::Base#[])
|
|
153
|
+
def [](token, as_jsi: :auto)
|
|
127
154
|
if respond_to?(:to_hash)
|
|
128
|
-
token_in_range =
|
|
129
|
-
value =
|
|
155
|
+
token_in_range = jsi_node_content_hash_pubsend(:key?, token)
|
|
156
|
+
value = jsi_node_content_hash_pubsend(:[], token)
|
|
130
157
|
elsif respond_to?(:to_ary)
|
|
131
|
-
token_in_range =
|
|
132
|
-
value =
|
|
158
|
+
token_in_range = jsi_node_content_ary_pubsend(:each_index).include?(token)
|
|
159
|
+
value = jsi_node_content_ary_pubsend(:[], token)
|
|
133
160
|
else
|
|
134
|
-
raise(NoMethodError, "cannot
|
|
161
|
+
raise(NoMethodError, "cannot subscript (using token: #{token.inspect}) from content: #{jsi_node_content.pretty_inspect.chomp}")
|
|
135
162
|
end
|
|
136
163
|
|
|
137
|
-
|
|
164
|
+
begin
|
|
138
165
|
if token_in_range
|
|
139
|
-
value_node =
|
|
166
|
+
value_node = jsi_subinstance_memos[token: token]
|
|
140
167
|
|
|
141
|
-
|
|
168
|
+
jsi_subinstance_as_jsi(value, value_node.jsi_schemas, as_jsi) do
|
|
142
169
|
value_node
|
|
143
|
-
else
|
|
144
|
-
value
|
|
145
170
|
end
|
|
146
171
|
else
|
|
147
172
|
# I think I will not support Hash#default/#default_proc in this case.
|
|
148
173
|
nil
|
|
149
174
|
end
|
|
150
175
|
end
|
|
151
|
-
result
|
|
152
|
-
end
|
|
153
|
-
|
|
154
|
-
# if this MetaschemaNode is a $ref then the $ref is followed. otherwise this MetaschemaNode is returned.
|
|
155
|
-
# @return [MetaschemaNode]
|
|
156
|
-
def deref(&block)
|
|
157
|
-
node_ptr_deref do |deref_ptr|
|
|
158
|
-
return new_node(node_ptr: deref_ptr).tap(&(block || Util::NOOP))
|
|
159
|
-
end
|
|
160
|
-
return self
|
|
161
176
|
end
|
|
162
177
|
|
|
178
|
+
# instantiates a new MetaschemaNode whose instance is a modified copy of this MetaschemaNode's instance
|
|
163
179
|
# @yield [Object] the node content of the instance. the block should result
|
|
164
180
|
# in a (nondestructively) modified copy of this.
|
|
165
181
|
# @return [MetaschemaNode] modified copy of self
|
|
166
|
-
def
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
q.text '#<'
|
|
177
|
-
q.text object_group_text.join(' ')
|
|
178
|
-
q.group_sub {
|
|
179
|
-
q.nest(2) {
|
|
180
|
-
q.breakable ' '
|
|
181
|
-
q.pp node_content
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
q.breakable ''
|
|
185
|
-
q.text '>'
|
|
182
|
+
def jsi_modified_copy(&block)
|
|
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
|
|
186
192
|
end
|
|
187
193
|
|
|
194
|
+
# @private
|
|
188
195
|
# @return [Array<String>]
|
|
189
|
-
def
|
|
190
|
-
if jsi_schemas.any?
|
|
191
|
-
class_n_schemas = "#{self.class} (#{jsi_schemas.map { |s| s.
|
|
196
|
+
def jsi_object_group_text
|
|
197
|
+
if jsi_schemas && jsi_schemas.any?
|
|
198
|
+
class_n_schemas = "#{self.class} (#{jsi_schemas.map { |s| s.jsi_ptr.uri }.join(' ')})"
|
|
192
199
|
else
|
|
193
200
|
class_n_schemas = self.class.to_s
|
|
194
201
|
end
|
|
195
202
|
[
|
|
196
203
|
class_n_schemas,
|
|
197
204
|
is_a?(Metaschema) ? "Metaschema" : is_a?(Schema) ? "Schema" : nil,
|
|
198
|
-
*(
|
|
205
|
+
*(jsi_node_content.respond_to?(:jsi_object_group_text) ? jsi_node_content.jsi_object_group_text : []),
|
|
199
206
|
].compact
|
|
200
207
|
end
|
|
201
208
|
|
|
202
|
-
#
|
|
209
|
+
# an opaque fingerprint of this MetaschemaNode for FingerprintHash
|
|
203
210
|
def jsi_fingerprint
|
|
204
|
-
{class: self.class,
|
|
211
|
+
{class: self.class, jsi_document: jsi_document}.merge(our_initialize_params)
|
|
205
212
|
end
|
|
206
|
-
include Util::FingerprintHash
|
|
207
213
|
|
|
208
214
|
private
|
|
209
215
|
|
|
216
|
+
# note: does not include jsi_root_node
|
|
210
217
|
def our_initialize_params
|
|
211
|
-
{
|
|
218
|
+
{
|
|
219
|
+
jsi_ptr: jsi_ptr,
|
|
220
|
+
schema_implementation_modules: schema_implementation_modules,
|
|
221
|
+
metaschema_root_ptr: metaschema_root_ptr,
|
|
222
|
+
root_schema_ptr: root_schema_ptr,
|
|
223
|
+
jsi_schema_base_uri: jsi_schema_base_uri,
|
|
224
|
+
}
|
|
212
225
|
end
|
|
213
226
|
|
|
227
|
+
# note: not for root node
|
|
214
228
|
def new_node(params)
|
|
215
|
-
MetaschemaNode.new(
|
|
229
|
+
MetaschemaNode.new(jsi_document, **our_initialize_params.merge(params))
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
def jsi_subinstance_memos
|
|
233
|
+
jsi_memomap(:subinstance) do |token: |
|
|
234
|
+
new_node(
|
|
235
|
+
jsi_ptr: jsi_ptr[token],
|
|
236
|
+
jsi_schema_base_uri: jsi_resource_ancestor_uri,
|
|
237
|
+
jsi_root_node: jsi_root_node,
|
|
238
|
+
)
|
|
239
|
+
end
|
|
216
240
|
end
|
|
217
241
|
end
|
|
218
242
|
end
|