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/jsi_coder.rb
CHANGED
@@ -29,12 +29,16 @@ module JSI
|
|
29
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
|
+
# @param jsi_opt [Hash] keyword arguments to pass to {Schema#new_jsi} when loading
|
33
|
+
# @param as_json_opt [Hash] keyword arguments to pass to `#as_json` when dumping
|
34
|
+
def initialize(schema, array: false, jsi_opt: Util::EMPTY_HASH, as_json_opt: Util::EMPTY_HASH)
|
33
35
|
unless schema.respond_to?(:new_jsi)
|
34
36
|
raise(ArgumentError, "schema param does not respond to #new_jsi: #{schema.inspect}")
|
35
37
|
end
|
36
38
|
@schema = schema
|
37
39
|
@array = array
|
40
|
+
@jsi_opt = jsi_opt
|
41
|
+
@as_json_opt = as_json_opt
|
38
42
|
end
|
39
43
|
|
40
44
|
# loads the database column to JSI instances of our schema
|
@@ -44,15 +48,15 @@ module JSI
|
|
44
48
|
# instance(s), or nil if data is nil
|
45
49
|
def load(data)
|
46
50
|
return nil if data.nil?
|
47
|
-
|
51
|
+
|
52
|
+
if @array
|
48
53
|
unless data.respond_to?(:to_ary)
|
49
54
|
raise TypeError, "expected array-like column data; got: #{data.class}: #{data.inspect}"
|
50
55
|
end
|
51
|
-
data.map { |el| load_object(el) }
|
56
|
+
data.to_ary.map { |el| load_object(el) }
|
52
57
|
else
|
53
58
|
load_object(data)
|
54
59
|
end
|
55
|
-
object
|
56
60
|
end
|
57
61
|
|
58
62
|
# dumps the object for the database
|
@@ -61,32 +65,30 @@ module JSI
|
|
61
65
|
# @return [Object, Array, nil] the schema instance(s) of the JSI(s), or nil if object is nil
|
62
66
|
def dump(object)
|
63
67
|
return nil if object.nil?
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
end
|
69
|
-
object.map do |el|
|
70
|
-
dump_object(el)
|
71
|
-
end
|
72
|
-
else
|
73
|
-
dump_object(object)
|
68
|
+
|
69
|
+
if @array
|
70
|
+
unless object.respond_to?(:to_ary)
|
71
|
+
raise(TypeError, "expected array-like attribute; got: #{object.class}: #{object.inspect}")
|
74
72
|
end
|
73
|
+
object.to_ary.map do |el|
|
74
|
+
dump_object(el)
|
75
|
+
end
|
76
|
+
else
|
77
|
+
dump_object(object)
|
75
78
|
end
|
76
|
-
jsonifiable
|
77
79
|
end
|
78
80
|
|
79
81
|
private
|
80
82
|
# @param data [Object]
|
81
83
|
# @return [JSI::Base]
|
82
84
|
def load_object(data)
|
83
|
-
@schema.new_jsi(data)
|
85
|
+
@schema.new_jsi(data, **@jsi_opt)
|
84
86
|
end
|
85
87
|
|
86
88
|
# @param object [JSI::Base, Object]
|
87
89
|
# @return [Object]
|
88
90
|
def dump_object(object)
|
89
|
-
JSI::
|
91
|
+
JSI::Util.as_json(object, **@as_json_opt)
|
90
92
|
end
|
91
93
|
end
|
92
94
|
end
|
@@ -1,32 +1,37 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module JSI
|
4
|
-
#
|
5
|
-
# internal class to bootstrap a metaschema. represents a schema without the complexity of JSI::Base. the
|
4
|
+
# internal class to bootstrap a meta-schema. represents a schema without the complexity of JSI::Base. the
|
6
5
|
# schema is represented but schemas describing the schema are not.
|
7
6
|
#
|
8
7
|
# this class is to only be instantiated on nodes in the document that are known to be schemas.
|
9
8
|
# Schema#subschema and Schema#resource_root_subschema are the intended mechanisms to instantiate subschemas
|
10
9
|
# and resolve references. #[] and #jsi_root_node are not implemented.
|
11
10
|
#
|
12
|
-
#
|
11
|
+
# schema implementation modules are included on generated subclasses of BootstrapSchema by
|
13
12
|
# {SchemaClasses.bootstrap_schema_class}. that subclass is instantiated with a document and
|
14
13
|
# pointer, representing a schema.
|
15
|
-
|
16
|
-
|
14
|
+
#
|
15
|
+
# BootstrapSchema does not support mutation; its document must be immutable.
|
16
|
+
#
|
17
|
+
# @api private
|
18
|
+
class MetaSchemaNode::BootstrapSchema
|
17
19
|
include Util::FingerprintHash
|
18
20
|
include Schema::SchemaAncestorNode
|
21
|
+
include Schema
|
19
22
|
|
20
23
|
class << self
|
21
24
|
def inspect
|
22
|
-
if self ==
|
23
|
-
name
|
25
|
+
if self == MetaSchemaNode::BootstrapSchema
|
26
|
+
name.freeze
|
24
27
|
else
|
25
|
-
"#{name ||
|
28
|
+
-"#{name || MetaSchemaNode::BootstrapSchema.name} (#{schema_implementation_modules.map(&:inspect).join(', ')})"
|
26
29
|
end
|
27
30
|
end
|
28
31
|
|
29
|
-
|
32
|
+
def to_s
|
33
|
+
inspect
|
34
|
+
end
|
30
35
|
end
|
31
36
|
|
32
37
|
# @param jsi_ptr [JSI::Ptr] pointer to the schema in the document
|
@@ -36,15 +41,17 @@ module JSI
|
|
36
41
|
jsi_ptr: Ptr[],
|
37
42
|
jsi_schema_base_uri: nil
|
38
43
|
)
|
39
|
-
unless respond_to?(:
|
40
|
-
raise(TypeError, "cannot instantiate #{self.class.inspect} which has no method #metaschema_instance_modules")
|
41
|
-
end
|
42
|
-
|
43
|
-
jsi_initialize_memos
|
44
|
+
raise(Bug, "no #schema_implementation_modules") unless respond_to?(:schema_implementation_modules)
|
44
45
|
|
45
46
|
self.jsi_ptr = jsi_ptr
|
46
47
|
self.jsi_document = jsi_document
|
47
48
|
self.jsi_schema_base_uri = jsi_schema_base_uri
|
49
|
+
self.jsi_schema_resource_ancestors = Util::EMPTY_ARY
|
50
|
+
|
51
|
+
@jsi_node_content = jsi_ptr.evaluate(jsi_document)
|
52
|
+
#chkbug raise(Bug, 'BootstrapSchema instance must be frozen') unless jsi_node_content.frozen?
|
53
|
+
|
54
|
+
super()
|
48
55
|
end
|
49
56
|
|
50
57
|
# document containing the schema content
|
@@ -53,13 +60,37 @@ module JSI
|
|
53
60
|
# JSI::Ptr pointing to this schema within the document
|
54
61
|
attr_reader :jsi_ptr
|
55
62
|
|
56
|
-
|
57
|
-
|
63
|
+
attr_reader(:jsi_node_content)
|
64
|
+
|
65
|
+
# overrides {Schema#subschema}
|
66
|
+
def subschema(subptr)
|
67
|
+
self.class.new(
|
68
|
+
jsi_document,
|
69
|
+
jsi_ptr: jsi_ptr + subptr,
|
70
|
+
jsi_schema_base_uri: jsi_resource_ancestor_uri,
|
71
|
+
)
|
72
|
+
end
|
73
|
+
|
74
|
+
# overrides {Schema#resource_root_subschema}
|
75
|
+
def resource_root_subschema(ptr)
|
76
|
+
# BootstrapSchema does not track jsi_schema_resource_ancestors used by Schema#schema_resource_root;
|
77
|
+
# resource_root_subschema is always relative to the document root.
|
78
|
+
# BootstrapSchema also does not implement jsi_root_node or #[]. we instantiate the ptr directly
|
79
|
+
# rather than as a subschema from the root.
|
80
|
+
self.class.new(
|
81
|
+
jsi_document,
|
82
|
+
jsi_ptr: Ptr.ary_ptr(ptr),
|
83
|
+
jsi_schema_base_uri: nil,
|
84
|
+
)
|
58
85
|
end
|
59
86
|
|
60
87
|
# @return [String]
|
61
88
|
def inspect
|
62
|
-
"\#<#{jsi_object_group_text.join(' ')} #{schema_content.inspect}>"
|
89
|
+
-"\#<#{jsi_object_group_text.join(' ')} #{schema_content.inspect}>"
|
90
|
+
end
|
91
|
+
|
92
|
+
def to_s
|
93
|
+
inspect
|
63
94
|
end
|
64
95
|
|
65
96
|
# pretty-prints a representation of self to the given printer
|
@@ -67,11 +98,9 @@ module JSI
|
|
67
98
|
def pretty_print(q)
|
68
99
|
q.text '#<'
|
69
100
|
q.text jsi_object_group_text.join(' ')
|
70
|
-
q.
|
71
|
-
q.nest(2) {
|
101
|
+
q.group(2) {
|
72
102
|
q.breakable ' '
|
73
103
|
q.pp schema_content
|
74
|
-
}
|
75
104
|
}
|
76
105
|
q.breakable ''
|
77
106
|
q.text '>'
|
@@ -81,20 +110,26 @@ module JSI
|
|
81
110
|
# @return [Array<String>]
|
82
111
|
def jsi_object_group_text
|
83
112
|
[
|
84
|
-
self.class.name ||
|
85
|
-
"(#{
|
113
|
+
self.class.name || MetaSchemaNode::BootstrapSchema.name,
|
114
|
+
-"(#{schema_implementation_modules.map(&:inspect).join(', ')})",
|
86
115
|
jsi_ptr.uri,
|
87
|
-
]
|
116
|
+
].freeze
|
88
117
|
end
|
89
118
|
|
90
|
-
#
|
119
|
+
# see {Util::Private::FingerprintHash}
|
120
|
+
# @api private
|
91
121
|
def jsi_fingerprint
|
92
122
|
{
|
93
123
|
class: self.class,
|
94
124
|
jsi_ptr: @jsi_ptr,
|
95
125
|
jsi_document: @jsi_document,
|
96
|
-
|
97
|
-
|
126
|
+
}.freeze
|
127
|
+
end
|
128
|
+
|
129
|
+
private
|
130
|
+
|
131
|
+
def jsi_memomap_class
|
132
|
+
Util::MemoMap::Immutable
|
98
133
|
end
|
99
134
|
end
|
100
135
|
end
|
data/lib/jsi/metaschema_node.rb
CHANGED
@@ -1,134 +1,140 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module JSI
|
4
|
-
#
|
5
|
-
#
|
4
|
+
# A MetaSchemaNode is a JSI instance representing a node in a document that contains a meta-schema.
|
5
|
+
# The root of the meta-schema is pointed to by metaschema_root_ptr.
|
6
6
|
# the schema describing the root of the document is pointed to by root_schema_ptr.
|
7
7
|
#
|
8
8
|
# like JSI::Base's normal subclasses, this class represents an instance of a schema set, an instance
|
9
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
|
10
|
+
# is the same, and a schema (the meta-schema) may be an instance of itself.
|
11
11
|
#
|
12
12
|
# unlike JSI::Base's normal subclasses, the schemas describing the instance are not part of the class.
|
13
|
-
#
|
13
|
+
# Since the meta-schema describes itself, attempting to construct a class from the JSI Schema Module of a
|
14
14
|
# schema which is itself an instance of that class results in a causality loop.
|
15
|
-
# instead, a
|
15
|
+
# instead, a MetaSchemaNode calculates its {#jsi_schemas} and extends itself with their JSI Schema
|
16
16
|
# modules during initialization.
|
17
|
-
#
|
17
|
+
# The MetaSchemaNode of the meta-schema is extended with its own JSI Schema Module.
|
18
18
|
#
|
19
|
-
# if the
|
19
|
+
# if the MetaSchemaNode's schemas include its self, it is extended with {JSI::Schema::MetaSchema}.
|
20
20
|
#
|
21
|
-
# a
|
22
|
-
# the
|
23
|
-
class
|
21
|
+
# a MetaSchemaNode is extended with JSI::Schema when it represents a schema - this is the case when
|
22
|
+
# the meta-schema is one of its schemas.
|
23
|
+
class MetaSchemaNode < Base
|
24
24
|
autoload :BootstrapSchema, 'jsi/metaschema_node/bootstrap_schema'
|
25
25
|
|
26
|
-
|
27
|
-
|
28
|
-
# @param
|
29
|
-
#
|
30
|
-
#
|
31
|
-
#
|
32
|
-
#
|
26
|
+
include(Base::Immutable)
|
27
|
+
|
28
|
+
# @param jsi_document the document containing the meta-schema.
|
29
|
+
# this must be frozen recursively; MetaSchemaNode does support mutation.
|
30
|
+
# @param jsi_ptr [JSI::Ptr] ptr to this MetaSchemaNode in jsi_document
|
31
|
+
# @param schema_implementation_modules [Enumerable<Module>] modules which implement the functionality
|
32
|
+
# of the schema. These are included on the {Schema#jsi_schema_module} of the meta-schema.
|
33
|
+
# They extend any schema described by the meta-schema, including those in the document containing
|
34
|
+
# the meta-schema, and the meta-schema itself.
|
35
|
+
# see {Schema#describes_schema!} param `schema_implementation_modules`.
|
36
|
+
# @param metaschema_root_ptr [JSI::Ptr] ptr to the root of the meta-schema in the jsi_document
|
33
37
|
# @param root_schema_ptr [JSI::Ptr] ptr to the schema describing the root of the jsi_document
|
34
38
|
def initialize(
|
35
39
|
jsi_document,
|
36
40
|
jsi_ptr: Ptr[],
|
37
|
-
|
41
|
+
schema_implementation_modules: ,
|
38
42
|
metaschema_root_ptr: Ptr[],
|
39
43
|
root_schema_ptr: Ptr[],
|
40
|
-
jsi_schema_base_uri: nil
|
44
|
+
jsi_schema_base_uri: nil,
|
45
|
+
jsi_schema_registry: nil,
|
46
|
+
jsi_content_to_immutable: DEFAULT_CONTENT_TO_IMMUTABLE,
|
47
|
+
jsi_root_node: nil
|
41
48
|
)
|
42
|
-
|
49
|
+
super(jsi_document,
|
50
|
+
jsi_ptr: jsi_ptr,
|
51
|
+
jsi_indicated_schemas: SchemaSet[],
|
52
|
+
jsi_schema_base_uri: jsi_schema_base_uri,
|
53
|
+
jsi_schema_registry: jsi_schema_registry,
|
54
|
+
jsi_content_to_immutable: jsi_content_to_immutable,
|
55
|
+
jsi_root_node: jsi_root_node,
|
56
|
+
)
|
43
57
|
|
44
|
-
|
45
|
-
self.jsi_ptr = jsi_ptr
|
46
|
-
@metaschema_instance_modules = Util.ensure_module_set(metaschema_instance_modules)
|
58
|
+
@schema_implementation_modules = schema_implementation_modules = Util.ensure_module_set(schema_implementation_modules)
|
47
59
|
@metaschema_root_ptr = metaschema_root_ptr
|
48
60
|
@root_schema_ptr = root_schema_ptr
|
49
61
|
|
50
62
|
if jsi_ptr.root? && jsi_schema_base_uri
|
51
|
-
raise(NotImplementedError, "unsupported jsi_schema_base_uri on
|
63
|
+
raise(NotImplementedError, "unsupported jsi_schema_base_uri on meta-schema document root")
|
52
64
|
end
|
53
|
-
self.jsi_schema_base_uri = jsi_schema_base_uri
|
54
65
|
|
55
|
-
|
66
|
+
#chkbug raise(Bug, 'MetaSchemaNode instance must be frozen') unless jsi_node_content.frozen?
|
56
67
|
|
57
|
-
|
58
|
-
extend PathedHashNode
|
59
|
-
end
|
60
|
-
if jsi_node_content.respond_to?(:to_ary)
|
61
|
-
extend PathedArrayNode
|
62
|
-
end
|
68
|
+
extends = Set[]
|
63
69
|
|
64
70
|
instance_for_schemas = jsi_document
|
65
|
-
bootstrap_schema_class = JSI::SchemaClasses.bootstrap_schema_class(
|
71
|
+
bootstrap_schema_class = JSI::SchemaClasses.bootstrap_schema_class(schema_implementation_modules)
|
66
72
|
root_bootstrap_schema = bootstrap_schema_class.new(
|
67
73
|
jsi_document,
|
68
74
|
jsi_ptr: root_schema_ptr,
|
69
75
|
jsi_schema_base_uri: nil, # supplying jsi_schema_base_uri on root bootstrap schema is not supported
|
70
76
|
)
|
71
|
-
|
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
|
77
|
+
our_bootstrap_indicated_schemas = jsi_ptr.tokens.inject(SchemaSet[root_bootstrap_schema]) do |bootstrap_indicated_schemas, tok|
|
78
|
+
bootstrap_schemas = bootstrap_indicated_schemas.inplace_applicator_schemas(instance_for_schemas)
|
79
|
+
child_indicated_schemas = bootstrap_schemas.child_applicator_schemas(tok, instance_for_schemas)
|
80
|
+
instance_for_schemas = instance_for_schemas[tok]
|
81
|
+
child_indicated_schemas
|
84
82
|
end
|
83
|
+
@indicated_schemas_map = jsi_memomap { bootstrap_schemas_to_msn(our_bootstrap_indicated_schemas) }
|
84
|
+
|
85
|
+
our_bootstrap_schemas = our_bootstrap_indicated_schemas.inplace_applicator_schemas(instance_for_schemas)
|
85
86
|
|
87
|
+
describes_self = false
|
86
88
|
our_bootstrap_schemas.each do |bootstrap_schema|
|
87
89
|
if bootstrap_schema.jsi_ptr == metaschema_root_ptr
|
88
|
-
|
89
|
-
|
90
|
+
# this is described by the meta-schema, i.e. this is a schema
|
91
|
+
extend Schema
|
92
|
+
schema_implementation_modules.each do |schema_implementation_module|
|
93
|
+
extend schema_implementation_module
|
90
94
|
end
|
95
|
+
extends += schema_implementation_modules
|
91
96
|
end
|
92
97
|
if bootstrap_schema.jsi_ptr == jsi_ptr
|
93
|
-
|
94
|
-
|
98
|
+
# this is the meta-schema (it is described by itself)
|
99
|
+
describes_self = true
|
95
100
|
end
|
96
101
|
end
|
97
102
|
|
98
|
-
@jsi_schemas =
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
jsi_ptr: bootstrap_schema.jsi_ptr,
|
104
|
-
jsi_schema_base_uri: bootstrap_schema.jsi_schema_base_uri,
|
105
|
-
)
|
106
|
-
end
|
103
|
+
@jsi_schemas = bootstrap_schemas_to_msn(our_bootstrap_schemas)
|
104
|
+
|
105
|
+
# note: jsi_schemas must already be set for jsi_schema_module to be used/extended
|
106
|
+
if describes_self
|
107
|
+
describes_schema!(schema_implementation_modules)
|
107
108
|
end
|
108
109
|
|
109
|
-
|
110
|
-
|
110
|
+
extends_for_instance = JSI::SchemaClasses.includes_for(jsi_node_content)
|
111
|
+
extends.merge(extends_for_instance)
|
112
|
+
extends.freeze
|
113
|
+
|
114
|
+
conflicting_modules = Set[self.class] + extends + @jsi_schemas.map(&:jsi_schema_module)
|
115
|
+
reader_modules = @jsi_schemas.map do |schema|
|
116
|
+
JSI::SchemaClasses.schema_property_reader_module(schema, conflicting_modules: conflicting_modules)
|
111
117
|
end
|
112
118
|
|
113
|
-
|
114
|
-
|
115
|
-
# in draft 4, boolean schemas are not described in the root, but on anyOf schemas on
|
116
|
-
# properties/additionalProperties and properties/additionalItems.
|
117
|
-
# since these describe schemas, their jsi_schema_instance_modules are the metaschema_instance_modules.
|
118
|
-
addtlPropsanyOf = metaschema_root_ptr["properties"]["additionalProperties"]["anyOf"]
|
119
|
-
addtlItemsanyOf = metaschema_root_ptr["properties"]["additionalItems"]["anyOf"]
|
119
|
+
readers = reader_modules.map(&:jsi_property_readers).inject(Set[], &:merge).freeze
|
120
|
+
define_singleton_method(:jsi_property_readers) { readers }
|
120
121
|
|
121
|
-
|
122
|
-
|
123
|
-
|
122
|
+
reader_modules.each { |reader_module| extend reader_module }
|
123
|
+
|
124
|
+
extends_for_instance.each do |m|
|
125
|
+
extend m
|
126
|
+
end
|
127
|
+
|
128
|
+
@jsi_schemas.each do |schema|
|
129
|
+
extend schema.jsi_schema_module
|
124
130
|
end
|
125
131
|
end
|
126
132
|
|
127
|
-
# Set of modules to apply to schemas
|
133
|
+
# Set of modules to apply to schemas that are instances of (described by) the meta-schema
|
128
134
|
# @return [Set<Module>]
|
129
|
-
attr_reader :
|
135
|
+
attr_reader :schema_implementation_modules
|
130
136
|
|
131
|
-
# ptr to the root of the
|
137
|
+
# ptr to the root of the meta-schema in the jsi_document
|
132
138
|
# @return [JSI::Ptr]
|
133
139
|
attr_reader :metaschema_root_ptr
|
134
140
|
|
@@ -136,110 +142,132 @@ module JSI
|
|
136
142
|
# @return [JSI::Ptr]
|
137
143
|
attr_reader :root_schema_ptr
|
138
144
|
|
139
|
-
# JSI Schemas describing this
|
145
|
+
# JSI Schemas describing this MetaSchemaNode
|
140
146
|
# @return [JSI::SchemaSet]
|
141
147
|
attr_reader :jsi_schemas
|
142
148
|
|
143
|
-
#
|
144
|
-
# @return [
|
145
|
-
def
|
146
|
-
|
147
|
-
self
|
148
|
-
else
|
149
|
-
new_node(
|
150
|
-
jsi_ptr: Ptr[],
|
151
|
-
jsi_schema_base_uri: nil,
|
152
|
-
)
|
153
|
-
end
|
149
|
+
# See {Base#jsi_indicated_schemas}
|
150
|
+
# @return [JSI::SchemaSet]
|
151
|
+
def jsi_indicated_schemas
|
152
|
+
@indicated_schemas_map[]
|
154
153
|
end
|
155
154
|
|
156
|
-
#
|
157
|
-
|
158
|
-
|
159
|
-
jsi_ptr.parent.evaluate(jsi_root_node)
|
160
|
-
end
|
155
|
+
# see {Base#jsi_child}
|
156
|
+
def jsi_child(token, as_jsi: )
|
157
|
+
child_node = @root_descendent_node_map[ptr: jsi_ptr[token]]
|
161
158
|
|
162
|
-
|
163
|
-
|
164
|
-
# @param token (see JSI::Base#[])
|
165
|
-
# @param as_jsi (see JSI::Base#[])
|
166
|
-
# @return (see JSI::Base#[])
|
167
|
-
def [](token, as_jsi: :auto)
|
168
|
-
if respond_to?(:to_hash)
|
169
|
-
token_in_range = jsi_node_content_hash_pubsend(:key?, token)
|
170
|
-
value = jsi_node_content_hash_pubsend(:[], token)
|
171
|
-
elsif respond_to?(:to_ary)
|
172
|
-
token_in_range = jsi_node_content_ary_pubsend(:each_index).include?(token)
|
173
|
-
value = jsi_node_content_ary_pubsend(:[], token)
|
174
|
-
else
|
175
|
-
raise(NoMethodError, "cannot subscript (using token: #{token.inspect}) from content: #{jsi_node_content.pretty_inspect.chomp}")
|
159
|
+
jsi_child_as_jsi(child_node.jsi_node_content, child_node.jsi_schemas, as_jsi) do
|
160
|
+
child_node
|
176
161
|
end
|
162
|
+
end
|
163
|
+
private :jsi_child
|
177
164
|
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
jsi_subinstance_as_jsi(value, value_node.jsi_schemas, as_jsi) do
|
183
|
-
value_node
|
184
|
-
end
|
185
|
-
else
|
186
|
-
# I think I will not support Hash#default/#default_proc in this case.
|
187
|
-
nil
|
188
|
-
end
|
189
|
-
end
|
165
|
+
# See {Base#jsi_default_child}
|
166
|
+
def jsi_default_child(token, as_jsi: )
|
167
|
+
jsi_node_content_child(token)
|
190
168
|
end
|
169
|
+
private :jsi_default_child # internals for #[] but idk, could be public
|
191
170
|
|
192
|
-
# instantiates a new
|
171
|
+
# instantiates a new MetaSchemaNode whose instance is a modified copy of this MetaSchemaNode's instance
|
193
172
|
# @yield [Object] the node content of the instance. the block should result
|
194
173
|
# in a (nondestructively) modified copy of this.
|
195
|
-
# @return [
|
174
|
+
# @return [MetaSchemaNode] modified copy of self
|
196
175
|
def jsi_modified_copy(&block)
|
197
|
-
|
176
|
+
if jsi_ptr.root?
|
177
|
+
modified_document = jsi_ptr.modified_document_copy(jsi_document, &block)
|
178
|
+
modified_document = jsi_content_to_immutable.call(modified_document) if jsi_content_to_immutable
|
179
|
+
MetaSchemaNode.new(modified_document, **our_initialize_params)
|
180
|
+
else
|
181
|
+
modified_jsi_root_node = jsi_root_node.jsi_modified_copy do |root|
|
182
|
+
jsi_ptr.modified_document_copy(root, &block)
|
183
|
+
end
|
184
|
+
modified_jsi_root_node.jsi_descendent_node(jsi_ptr)
|
185
|
+
end
|
198
186
|
end
|
199
187
|
|
200
188
|
# @private
|
201
189
|
# @return [Array<String>]
|
202
190
|
def jsi_object_group_text
|
203
191
|
if jsi_schemas && jsi_schemas.any?
|
204
|
-
class_n_schemas = "#{self.class} (#{jsi_schemas.map { |s| s.jsi_ptr.uri }.join(' ')})"
|
192
|
+
class_n_schemas = -"#{self.class} (#{jsi_schemas.map { |s| s.jsi_schema_module.name_from_ancestor || s.jsi_ptr.uri }.join(' ')})"
|
205
193
|
else
|
206
194
|
class_n_schemas = self.class.to_s
|
207
195
|
end
|
208
196
|
[
|
209
197
|
class_n_schemas,
|
210
|
-
is_a?(
|
211
|
-
*(jsi_node_content.respond_to?(:jsi_object_group_text) ? jsi_node_content.jsi_object_group_text :
|
212
|
-
].compact
|
198
|
+
is_a?(Schema::MetaSchema) ? "Meta-Schema" : is_a?(Schema) ? "Schema" : nil,
|
199
|
+
*(jsi_node_content.respond_to?(:jsi_object_group_text) ? jsi_node_content.jsi_object_group_text : nil),
|
200
|
+
].compact.freeze
|
213
201
|
end
|
214
202
|
|
215
|
-
#
|
203
|
+
# see {Util::Private::FingerprintHash}
|
204
|
+
# @api private
|
216
205
|
def jsi_fingerprint
|
217
|
-
{class: self.class, jsi_document: jsi_document}.merge(our_initialize_params)
|
206
|
+
{class: self.class, jsi_document: jsi_document}.merge(our_initialize_params).freeze
|
218
207
|
end
|
219
208
|
|
209
|
+
protected
|
210
|
+
|
211
|
+
attr_reader :root_descendent_node_map
|
212
|
+
|
220
213
|
private
|
221
214
|
|
215
|
+
def jsi_memomaps_initialize
|
216
|
+
if jsi_ptr.root?
|
217
|
+
@root_descendent_node_map = jsi_memomap(&method(:jsi_root_descendent_node_compute))
|
218
|
+
else
|
219
|
+
@root_descendent_node_map = @jsi_root_node.root_descendent_node_map
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
# note: does not include jsi_root_node
|
222
224
|
def our_initialize_params
|
223
225
|
{
|
224
226
|
jsi_ptr: jsi_ptr,
|
225
|
-
|
227
|
+
schema_implementation_modules: schema_implementation_modules,
|
226
228
|
metaschema_root_ptr: metaschema_root_ptr,
|
227
229
|
root_schema_ptr: root_schema_ptr,
|
228
230
|
jsi_schema_base_uri: jsi_schema_base_uri,
|
229
|
-
|
231
|
+
jsi_schema_registry: jsi_schema_registry,
|
232
|
+
jsi_content_to_immutable: jsi_content_to_immutable,
|
233
|
+
}.freeze
|
230
234
|
end
|
231
235
|
|
232
|
-
|
233
|
-
|
236
|
+
# note: not for root node
|
237
|
+
def new_node(**params)
|
238
|
+
MetaSchemaNode.new(jsi_document, jsi_root_node: jsi_root_node, **our_initialize_params, **params)
|
234
239
|
end
|
235
240
|
|
236
|
-
def
|
237
|
-
|
241
|
+
def jsi_root_descendent_node_compute(ptr: )
|
242
|
+
#chkbug raise(Bug) unless jsi_ptr.root?
|
243
|
+
if ptr.root?
|
244
|
+
self
|
245
|
+
else
|
238
246
|
new_node(
|
239
|
-
jsi_ptr:
|
247
|
+
jsi_ptr: ptr,
|
240
248
|
jsi_schema_base_uri: jsi_resource_ancestor_uri,
|
241
249
|
)
|
242
250
|
end
|
243
251
|
end
|
252
|
+
|
253
|
+
# @param bootstrap_schemas [Enumerable<BootstrapSchema>]
|
254
|
+
# @return [SchemaSet<MetaSchemaNode>]
|
255
|
+
def bootstrap_schemas_to_msn(bootstrap_schemas)
|
256
|
+
SchemaSet.new(bootstrap_schemas) do |bootstrap_schema|
|
257
|
+
if bootstrap_schema.jsi_ptr == jsi_ptr
|
258
|
+
self
|
259
|
+
elsif bootstrap_schema.jsi_ptr.root?
|
260
|
+
@jsi_root_node
|
261
|
+
else
|
262
|
+
new_node(
|
263
|
+
jsi_ptr: bootstrap_schema.jsi_ptr,
|
264
|
+
jsi_schema_base_uri: bootstrap_schema.jsi_schema_base_uri,
|
265
|
+
)
|
266
|
+
end
|
267
|
+
end
|
268
|
+
end
|
244
269
|
end
|
270
|
+
|
271
|
+
# @deprecated after v0.7.0, alias of {MetaSchemaNode}
|
272
|
+
MetaschemaNode = MetaSchemaNode
|
245
273
|
end
|