jsi 0.7.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.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +6 -1
  3. data/CHANGELOG.md +15 -0
  4. data/README.md +19 -18
  5. data/jsi.gemspec +2 -3
  6. data/lib/jsi/base/mutability.rb +44 -0
  7. data/lib/jsi/base/node.rb +199 -34
  8. data/lib/jsi/base.rb +412 -228
  9. data/lib/jsi/jsi_coder.rb +18 -16
  10. data/lib/jsi/metaschema_node/bootstrap_schema.rb +57 -23
  11. data/lib/jsi/metaschema_node.rb +138 -107
  12. data/lib/jsi/ptr.rb +59 -37
  13. data/lib/jsi/schema/application/child_application/draft04.rb +0 -1
  14. data/lib/jsi/schema/application/child_application/draft06.rb +0 -1
  15. data/lib/jsi/schema/application/child_application/draft07.rb +0 -1
  16. data/lib/jsi/schema/application/child_application.rb +0 -25
  17. data/lib/jsi/schema/application/inplace_application/draft04.rb +0 -1
  18. data/lib/jsi/schema/application/inplace_application/draft06.rb +0 -1
  19. data/lib/jsi/schema/application/inplace_application/draft07.rb +0 -1
  20. data/lib/jsi/schema/application/inplace_application/ref.rb +1 -1
  21. data/lib/jsi/schema/application/inplace_application/someof.rb +1 -1
  22. data/lib/jsi/schema/application/inplace_application.rb +0 -27
  23. data/lib/jsi/schema/draft04.rb +0 -1
  24. data/lib/jsi/schema/draft06.rb +0 -1
  25. data/lib/jsi/schema/draft07.rb +0 -1
  26. data/lib/jsi/schema/ref.rb +44 -18
  27. data/lib/jsi/schema/schema_ancestor_node.rb +65 -56
  28. data/lib/jsi/schema/validation/contains.rb +1 -1
  29. data/lib/jsi/schema/validation/draft04/minmax.rb +2 -0
  30. data/lib/jsi/schema/validation/draft04.rb +0 -2
  31. data/lib/jsi/schema/validation/draft06.rb +0 -2
  32. data/lib/jsi/schema/validation/draft07.rb +0 -2
  33. data/lib/jsi/schema/validation/items.rb +3 -3
  34. data/lib/jsi/schema/validation/pattern.rb +1 -1
  35. data/lib/jsi/schema/validation/properties.rb +4 -4
  36. data/lib/jsi/schema/validation/ref.rb +1 -1
  37. data/lib/jsi/schema/validation.rb +0 -2
  38. data/lib/jsi/schema.rb +405 -194
  39. data/lib/jsi/schema_classes.rb +196 -127
  40. data/lib/jsi/schema_registry.rb +66 -17
  41. data/lib/jsi/schema_set.rb +76 -30
  42. data/lib/jsi/simple_wrap.rb +2 -7
  43. data/lib/jsi/util/private/attr_struct.rb +28 -14
  44. data/lib/jsi/util/private/memo_map.rb +75 -0
  45. data/lib/jsi/util/private.rb +73 -92
  46. data/lib/jsi/util/typelike.rb +28 -28
  47. data/lib/jsi/util.rb +120 -36
  48. data/lib/jsi/validation/error.rb +4 -0
  49. data/lib/jsi/validation/result.rb +18 -32
  50. data/lib/jsi/version.rb +1 -1
  51. data/lib/jsi.rb +67 -25
  52. data/lib/schemas/json-schema.org/draft-04/schema.rb +159 -4
  53. data/lib/schemas/json-schema.org/draft-06/schema.rb +161 -4
  54. data/lib/schemas/json-schema.org/draft-07/schema.rb +188 -4
  55. metadata +19 -5
  56. data/lib/jsi/metaschema.rb +0 -6
  57. data/lib/jsi/schema/validation/core.rb +0 -39
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
- def initialize(schema, array: false)
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,7 +48,8 @@ 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
- object = if @array
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
@@ -52,7 +57,6 @@ module JSI
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
- jsonifiable = begin
65
- if @array
66
- unless object.respond_to?(:to_ary)
67
- raise(TypeError, "expected array-like attribute; got: #{object.class}: #{object.inspect}")
68
- end
69
- object.to_ary.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::Util.as_json(object)
91
+ JSI::Util.as_json(object, **@as_json_opt)
90
92
  end
91
93
  end
92
94
  end
@@ -1,33 +1,37 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module JSI
4
- # 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
5
5
  # schema is represented but schemas describing the schema are not.
6
6
  #
7
7
  # this class is to only be instantiated on nodes in the document that are known to be schemas.
8
8
  # Schema#subschema and Schema#resource_root_subschema are the intended mechanisms to instantiate subschemas
9
9
  # and resolve references. #[] and #jsi_root_node are not implemented.
10
10
  #
11
- # schema implementation modules are attached to generated subclasses of BootstrapSchema by
11
+ # schema implementation modules are included on generated subclasses of BootstrapSchema by
12
12
  # {SchemaClasses.bootstrap_schema_class}. that subclass is instantiated with a document and
13
13
  # pointer, representing a schema.
14
14
  #
15
+ # BootstrapSchema does not support mutation; its document must be immutable.
16
+ #
15
17
  # @api private
16
- class MetaschemaNode::BootstrapSchema
17
- include Util::Memoize
18
+ class MetaSchemaNode::BootstrapSchema
18
19
  include Util::FingerprintHash
19
20
  include Schema::SchemaAncestorNode
21
+ include Schema
20
22
 
21
23
  class << self
22
24
  def inspect
23
- if self == MetaschemaNode::BootstrapSchema
24
- name
25
+ if self == MetaSchemaNode::BootstrapSchema
26
+ name.freeze
25
27
  else
26
- "#{name || MetaschemaNode::BootstrapSchema.name} (#{schema_implementation_modules.map(&:inspect).join(', ')})"
28
+ -"#{name || MetaSchemaNode::BootstrapSchema.name} (#{schema_implementation_modules.map(&:inspect).join(', ')})"
27
29
  end
28
30
  end
29
31
 
30
- alias_method :to_s, :inspect
32
+ def to_s
33
+ inspect
34
+ end
31
35
  end
32
36
 
33
37
  # @param jsi_ptr [JSI::Ptr] pointer to the schema in the document
@@ -39,11 +43,15 @@ module JSI
39
43
  )
40
44
  raise(Bug, "no #schema_implementation_modules") unless respond_to?(:schema_implementation_modules)
41
45
 
42
- jsi_initialize_memos
43
-
44
46
  self.jsi_ptr = jsi_ptr
45
47
  self.jsi_document = jsi_document
46
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()
47
55
  end
48
56
 
49
57
  # document containing the schema content
@@ -52,27 +60,47 @@ module JSI
52
60
  # JSI::Ptr pointing to this schema within the document
53
61
  attr_reader :jsi_ptr
54
62
 
55
- def jsi_node_content
56
- jsi_ptr.evaluate(jsi_document)
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
+ )
57
85
  end
58
86
 
59
87
  # @return [String]
60
88
  def inspect
61
- "\#<#{jsi_object_group_text.join(' ')} #{schema_content.inspect}>"
89
+ -"\#<#{jsi_object_group_text.join(' ')} #{schema_content.inspect}>"
62
90
  end
63
91
 
64
- alias_method :to_s, :inspect
92
+ def to_s
93
+ inspect
94
+ end
65
95
 
66
96
  # pretty-prints a representation of self to the given printer
67
97
  # @return [void]
68
98
  def pretty_print(q)
69
99
  q.text '#<'
70
100
  q.text jsi_object_group_text.join(' ')
71
- q.group_sub {
72
- q.nest(2) {
101
+ q.group(2) {
73
102
  q.breakable ' '
74
103
  q.pp schema_content
75
- }
76
104
  }
77
105
  q.breakable ''
78
106
  q.text '>'
@@ -82,20 +110,26 @@ module JSI
82
110
  # @return [Array<String>]
83
111
  def jsi_object_group_text
84
112
  [
85
- self.class.name || MetaschemaNode::BootstrapSchema.name,
86
- "(#{schema_implementation_modules.map(&:inspect).join(', ')})",
113
+ self.class.name || MetaSchemaNode::BootstrapSchema.name,
114
+ -"(#{schema_implementation_modules.map(&:inspect).join(', ')})",
87
115
  jsi_ptr.uri,
88
- ]
116
+ ].freeze
89
117
  end
90
118
 
91
- # @private
119
+ # see {Util::Private::FingerprintHash}
120
+ # @api private
92
121
  def jsi_fingerprint
93
122
  {
94
123
  class: self.class,
95
124
  jsi_ptr: @jsi_ptr,
96
125
  jsi_document: @jsi_document,
97
- schema_implementation_modules: schema_implementation_modules,
98
- }
126
+ }.freeze
127
+ end
128
+
129
+ private
130
+
131
+ def jsi_memomap_class
132
+ Util::MemoMap::Immutable
99
133
  end
100
134
  end
101
135
  end
@@ -1,36 +1,39 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module JSI
4
- # a MetaschemaNode is a JSI instance representing a node in a document which contains a metaschema.
5
- # the root of the metaschema is pointed to by metaschema_root_ptr.
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 metaschema) may be an instance of itself.
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
- # since the metaschema describes itself, attempting to construct a class from the JSI Schema Module of a
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 MetaschemaNode calculates its {#jsi_schemas} and extends itself with their JSI Schema
15
+ # instead, a MetaSchemaNode calculates its {#jsi_schemas} and extends itself with their JSI Schema
16
16
  # modules during initialization.
17
- # the MetaschemaNode of the metaschema is extended with its own JSI Schema Module.
17
+ # The MetaSchemaNode of the meta-schema is extended with its own JSI Schema Module.
18
18
  #
19
- # if the MetaschemaNode's schemas include its self, it is extended with JSI::Metaschema.
19
+ # if the MetaSchemaNode's schemas include its self, it is extended with {JSI::Schema::MetaSchema}.
20
20
  #
21
- # a MetaschemaNode is extended with JSI::Schema when it represents a schema - this is the case when
22
- # the metaschema is one of its schemas.
23
- class MetaschemaNode < Base
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
- # @param jsi_document the document containing the metaschema
27
- # @param jsi_ptr [JSI::Ptr] ptr to this MetaschemaNode in jsi_document
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
28
31
  # @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
+ # 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.
32
35
  # 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
36
+ # @param metaschema_root_ptr [JSI::Ptr] ptr to the root of the meta-schema in the jsi_document
34
37
  # @param root_schema_ptr [JSI::Ptr] ptr to the schema describing the root of the jsi_document
35
38
  def initialize(
36
39
  jsi_document,
@@ -39,31 +42,30 @@ module JSI
39
42
  metaschema_root_ptr: Ptr[],
40
43
  root_schema_ptr: Ptr[],
41
44
  jsi_schema_base_uri: nil,
45
+ jsi_schema_registry: nil,
46
+ jsi_content_to_immutable: DEFAULT_CONTENT_TO_IMMUTABLE,
42
47
  jsi_root_node: nil
43
48
  )
44
- jsi_initialize_memos
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
+ )
45
57
 
46
- self.jsi_document = jsi_document
47
- self.jsi_ptr = jsi_ptr
48
- @schema_implementation_modules = Util.ensure_module_set(schema_implementation_modules)
58
+ @schema_implementation_modules = schema_implementation_modules = Util.ensure_module_set(schema_implementation_modules)
49
59
  @metaschema_root_ptr = metaschema_root_ptr
50
60
  @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
61
 
54
62
  if jsi_ptr.root? && jsi_schema_base_uri
55
- raise(NotImplementedError, "unsupported jsi_schema_base_uri on metaschema document root")
63
+ raise(NotImplementedError, "unsupported jsi_schema_base_uri on meta-schema document root")
56
64
  end
57
- self.jsi_schema_base_uri = jsi_schema_base_uri
58
65
 
59
- jsi_node_content = self.jsi_node_content
66
+ #chkbug raise(Bug, 'MetaSchemaNode instance must be frozen') unless jsi_node_content.frozen?
60
67
 
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
68
+ extends = Set[]
67
69
 
68
70
  instance_for_schemas = jsi_document
69
71
  bootstrap_schema_class = JSI::SchemaClasses.bootstrap_schema_class(schema_implementation_modules)
@@ -72,68 +74,67 @@ module JSI
72
74
  jsi_ptr: root_schema_ptr,
73
75
  jsi_schema_base_uri: nil, # supplying jsi_schema_base_uri on root bootstrap schema is not supported
74
76
  )
75
- our_bootstrap_schemas = jsi_ptr.tokens.inject(SchemaSet[root_bootstrap_schema]) do |bootstrap_schemas, tok|
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)
76
79
  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
80
  instance_for_schemas = instance_for_schemas[tok]
79
- child_schemas
81
+ child_indicated_schemas
80
82
  end
83
+ @indicated_schemas_map = jsi_memomap { bootstrap_schemas_to_msn(our_bootstrap_indicated_schemas) }
81
84
 
85
+ our_bootstrap_schemas = our_bootstrap_indicated_schemas.inplace_applicator_schemas(instance_for_schemas)
86
+
87
+ describes_self = false
82
88
  our_bootstrap_schemas.each do |bootstrap_schema|
83
89
  if bootstrap_schema.jsi_ptr == metaschema_root_ptr
84
- # this is described by the metaschema, i.e. this is a schema
90
+ # this is described by the meta-schema, i.e. this is a schema
91
+ extend Schema
85
92
  schema_implementation_modules.each do |schema_implementation_module|
86
93
  extend schema_implementation_module
87
94
  end
95
+ extends += schema_implementation_modules
88
96
  end
89
97
  if bootstrap_schema.jsi_ptr == jsi_ptr
90
- # this is the metaschema (it is described by itself)
91
- extend Metaschema
98
+ # this is the meta-schema (it is described by itself)
99
+ describes_self = true
92
100
  end
93
101
  end
94
102
 
95
- @jsi_schemas = SchemaSet.new(our_bootstrap_schemas) do |bootstrap_schema|
96
- if bootstrap_schema.jsi_ptr == jsi_ptr
97
- self
98
- elsif bootstrap_schema.jsi_ptr.root?
99
- @jsi_root_node
100
- else
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
- )
106
- end
107
- end
103
+ @jsi_schemas = bootstrap_schemas_to_msn(our_bootstrap_schemas)
108
104
 
109
105
  # note: jsi_schemas must already be set for jsi_schema_module to be used/extended
110
- if is_a?(Metaschema)
106
+ if describes_self
111
107
  describes_schema!(schema_implementation_modules)
112
108
  end
113
109
 
114
- @jsi_schemas.each do |schema|
115
- extend schema.jsi_schema_module
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)
116
117
  end
117
118
 
118
- # workarounds
119
- begin # draft 4 boolean schema workaround
120
- # in draft 4, boolean schemas are not described in the root, but on anyOf schemas on
121
- # properties/additionalProperties and properties/additionalItems.
122
- # these still describe schemas, despite not being described by the metaschema.
123
- addtlPropsanyOf = metaschema_root_ptr["properties"]["additionalProperties"]["anyOf"]
124
- 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 }
125
121
 
126
- if !jsi_ptr.root? && [addtlPropsanyOf, addtlItemsanyOf].include?(jsi_ptr.parent)
127
- describes_schema!(schema_implementation_modules)
128
- end
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
129
130
  end
130
131
  end
131
132
 
132
- # Set of modules to apply to schemas which are instances of (described by) the metaschema
133
+ # Set of modules to apply to schemas that are instances of (described by) the meta-schema
133
134
  # @return [Set<Module>]
134
135
  attr_reader :schema_implementation_modules
135
136
 
136
- # ptr to the root of the metaschema in the jsi_document
137
+ # ptr to the root of the meta-schema in the jsi_document
137
138
  # @return [JSI::Ptr]
138
139
  attr_reader :metaschema_root_ptr
139
140
 
@@ -141,48 +142,41 @@ module JSI
141
142
  # @return [JSI::Ptr]
142
143
  attr_reader :root_schema_ptr
143
144
 
144
- # JSI Schemas describing this MetaschemaNode
145
+ # JSI Schemas describing this MetaSchemaNode
145
146
  # @return [JSI::SchemaSet]
146
147
  attr_reader :jsi_schemas
147
148
 
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)
154
- if respond_to?(:to_hash)
155
- token_in_range = jsi_node_content_hash_pubsend(:key?, token)
156
- value = jsi_node_content_hash_pubsend(:[], token)
157
- elsif respond_to?(:to_ary)
158
- token_in_range = jsi_node_content_ary_pubsend(:each_index).include?(token)
159
- value = jsi_node_content_ary_pubsend(:[], token)
160
- else
161
- raise(NoMethodError, "cannot subscript (using token: #{token.inspect}) from content: #{jsi_node_content.pretty_inspect.chomp}")
162
- end
149
+ # See {Base#jsi_indicated_schemas}
150
+ # @return [JSI::SchemaSet]
151
+ def jsi_indicated_schemas
152
+ @indicated_schemas_map[]
153
+ end
163
154
 
164
- begin
165
- if token_in_range
166
- value_node = jsi_subinstance_memos[token: token]
155
+ # see {Base#jsi_child}
156
+ def jsi_child(token, as_jsi: )
157
+ child_node = @root_descendent_node_map[ptr: jsi_ptr[token]]
167
158
 
168
- jsi_subinstance_as_jsi(value, value_node.jsi_schemas, as_jsi) do
169
- value_node
170
- end
171
- else
172
- # I think I will not support Hash#default/#default_proc in this case.
173
- nil
174
- end
159
+ jsi_child_as_jsi(child_node.jsi_node_content, child_node.jsi_schemas, as_jsi) do
160
+ child_node
175
161
  end
176
162
  end
163
+ private :jsi_child
164
+
165
+ # See {Base#jsi_default_child}
166
+ def jsi_default_child(token, as_jsi: )
167
+ jsi_node_content_child(token)
168
+ end
169
+ private :jsi_default_child # internals for #[] but idk, could be public
177
170
 
178
- # instantiates a new MetaschemaNode whose instance is a modified copy of this MetaschemaNode's instance
171
+ # instantiates a new MetaSchemaNode whose instance is a modified copy of this MetaSchemaNode's instance
179
172
  # @yield [Object] the node content of the instance. the block should result
180
173
  # in a (nondestructively) modified copy of this.
181
- # @return [MetaschemaNode] modified copy of self
174
+ # @return [MetaSchemaNode] modified copy of self
182
175
  def jsi_modified_copy(&block)
183
176
  if jsi_ptr.root?
184
177
  modified_document = jsi_ptr.modified_document_copy(jsi_document, &block)
185
- MetaschemaNode.new(modified_document, **our_initialize_params)
178
+ modified_document = jsi_content_to_immutable.call(modified_document) if jsi_content_to_immutable
179
+ MetaSchemaNode.new(modified_document, **our_initialize_params)
186
180
  else
187
181
  modified_jsi_root_node = jsi_root_node.jsi_modified_copy do |root|
188
182
  jsi_ptr.modified_document_copy(root, &block)
@@ -195,24 +189,37 @@ module JSI
195
189
  # @return [Array<String>]
196
190
  def jsi_object_group_text
197
191
  if jsi_schemas && jsi_schemas.any?
198
- 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(' ')})"
199
193
  else
200
194
  class_n_schemas = self.class.to_s
201
195
  end
202
196
  [
203
197
  class_n_schemas,
204
- is_a?(Metaschema) ? "Metaschema" : is_a?(Schema) ? "Schema" : nil,
205
- *(jsi_node_content.respond_to?(:jsi_object_group_text) ? jsi_node_content.jsi_object_group_text : []),
206
- ].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
207
201
  end
208
202
 
209
- # an opaque fingerprint of this MetaschemaNode for FingerprintHash
203
+ # see {Util::Private::FingerprintHash}
204
+ # @api private
210
205
  def jsi_fingerprint
211
- {class: self.class, jsi_document: jsi_document}.merge(our_initialize_params)
206
+ {class: self.class, jsi_document: jsi_document}.merge(our_initialize_params).freeze
212
207
  end
213
208
 
209
+ protected
210
+
211
+ attr_reader :root_descendent_node_map
212
+
214
213
  private
215
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
+
216
223
  # note: does not include jsi_root_node
217
224
  def our_initialize_params
218
225
  {
@@ -221,22 +228,46 @@ module JSI
221
228
  metaschema_root_ptr: metaschema_root_ptr,
222
229
  root_schema_ptr: root_schema_ptr,
223
230
  jsi_schema_base_uri: jsi_schema_base_uri,
224
- }
231
+ jsi_schema_registry: jsi_schema_registry,
232
+ jsi_content_to_immutable: jsi_content_to_immutable,
233
+ }.freeze
225
234
  end
226
235
 
227
236
  # note: not for root node
228
- def new_node(params)
229
- MetaschemaNode.new(jsi_document, **our_initialize_params.merge(params))
237
+ def new_node(**params)
238
+ MetaSchemaNode.new(jsi_document, jsi_root_node: jsi_root_node, **our_initialize_params, **params)
230
239
  end
231
240
 
232
- def jsi_subinstance_memos
233
- jsi_memomap(:subinstance) do |token: |
241
+ def jsi_root_descendent_node_compute(ptr: )
242
+ #chkbug raise(Bug) unless jsi_ptr.root?
243
+ if ptr.root?
244
+ self
245
+ else
234
246
  new_node(
235
- jsi_ptr: jsi_ptr[token],
247
+ jsi_ptr: ptr,
236
248
  jsi_schema_base_uri: jsi_resource_ancestor_uri,
237
- jsi_root_node: jsi_root_node,
238
249
  )
239
250
  end
240
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
241
269
  end
270
+
271
+ # @deprecated after v0.7.0, alias of {MetaSchemaNode}
272
+ MetaschemaNode = MetaSchemaNode
242
273
  end