jsi 0.4.0 → 0.6.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 (105) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +1 -1
  3. data/CHANGELOG.md +15 -0
  4. data/README.md +105 -38
  5. data/lib/jsi/base.rb +349 -155
  6. data/lib/jsi/jsi_coder.rb +5 -4
  7. data/lib/jsi/metaschema_node/bootstrap_schema.rb +100 -0
  8. data/lib/jsi/metaschema_node.rb +156 -129
  9. data/lib/jsi/pathed_node.rb +47 -49
  10. data/lib/jsi/ptr.rb +292 -0
  11. data/lib/jsi/schema/application/child_application/contains.rb +16 -0
  12. data/lib/jsi/schema/application/child_application/draft04.rb +22 -0
  13. data/lib/jsi/schema/application/child_application/draft06.rb +29 -0
  14. data/lib/jsi/schema/application/child_application/draft07.rb +29 -0
  15. data/lib/jsi/schema/application/child_application/items.rb +18 -0
  16. data/lib/jsi/schema/application/child_application/properties.rb +25 -0
  17. data/lib/jsi/schema/application/child_application.rb +40 -0
  18. data/lib/jsi/schema/application/draft04.rb +8 -0
  19. data/lib/jsi/schema/application/draft06.rb +8 -0
  20. data/lib/jsi/schema/application/draft07.rb +8 -0
  21. data/lib/jsi/schema/application/inplace_application/dependencies.rb +28 -0
  22. data/lib/jsi/schema/application/inplace_application/draft04.rb +26 -0
  23. data/lib/jsi/schema/application/inplace_application/draft06.rb +27 -0
  24. data/lib/jsi/schema/application/inplace_application/draft07.rb +33 -0
  25. data/lib/jsi/schema/application/inplace_application/ifthenelse.rb +20 -0
  26. data/lib/jsi/schema/application/inplace_application/ref.rb +18 -0
  27. data/lib/jsi/schema/application/inplace_application/someof.rb +29 -0
  28. data/lib/jsi/schema/application/inplace_application.rb +46 -0
  29. data/lib/jsi/schema/application.rb +12 -0
  30. data/lib/jsi/schema/draft04.rb +14 -0
  31. data/lib/jsi/schema/draft06.rb +14 -0
  32. data/lib/jsi/schema/draft07.rb +14 -0
  33. data/lib/jsi/schema/issue.rb +36 -0
  34. data/lib/jsi/schema/ref.rb +159 -0
  35. data/lib/jsi/schema/schema_ancestor_node.rb +119 -0
  36. data/lib/jsi/schema/validation/array.rb +69 -0
  37. data/lib/jsi/schema/validation/const.rb +20 -0
  38. data/lib/jsi/schema/validation/contains.rb +25 -0
  39. data/lib/jsi/schema/validation/core.rb +39 -0
  40. data/lib/jsi/schema/validation/dependencies.rb +49 -0
  41. data/lib/jsi/schema/validation/draft04/minmax.rb +91 -0
  42. data/lib/jsi/schema/validation/draft04.rb +112 -0
  43. data/lib/jsi/schema/validation/draft06.rb +122 -0
  44. data/lib/jsi/schema/validation/draft07.rb +159 -0
  45. data/lib/jsi/schema/validation/enum.rb +25 -0
  46. data/lib/jsi/schema/validation/ifthenelse.rb +46 -0
  47. data/lib/jsi/schema/validation/items.rb +54 -0
  48. data/lib/jsi/schema/validation/not.rb +20 -0
  49. data/lib/jsi/schema/validation/numeric.rb +121 -0
  50. data/lib/jsi/schema/validation/object.rb +45 -0
  51. data/lib/jsi/schema/validation/pattern.rb +34 -0
  52. data/lib/jsi/schema/validation/properties.rb +101 -0
  53. data/lib/jsi/schema/validation/property_names.rb +32 -0
  54. data/lib/jsi/schema/validation/ref.rb +40 -0
  55. data/lib/jsi/schema/validation/required.rb +27 -0
  56. data/lib/jsi/schema/validation/someof.rb +90 -0
  57. data/lib/jsi/schema/validation/string.rb +47 -0
  58. data/lib/jsi/schema/validation/type.rb +49 -0
  59. data/lib/jsi/schema/validation.rb +51 -0
  60. data/lib/jsi/schema.rb +486 -133
  61. data/lib/jsi/schema_classes.rb +157 -42
  62. data/lib/jsi/schema_registry.rb +141 -0
  63. data/lib/jsi/schema_set.rb +141 -0
  64. data/lib/jsi/simple_wrap.rb +2 -2
  65. data/lib/jsi/typelike_modules.rb +52 -37
  66. data/lib/jsi/util/attr_struct.rb +106 -0
  67. data/lib/jsi/util.rb +141 -25
  68. data/lib/jsi/validation/error.rb +34 -0
  69. data/lib/jsi/validation/result.rb +210 -0
  70. data/lib/jsi/validation.rb +15 -0
  71. data/lib/jsi/version.rb +3 -1
  72. data/lib/jsi.rb +55 -9
  73. data/lib/schemas/json-schema.org/draft-04/schema.rb +8 -3
  74. data/lib/schemas/json-schema.org/draft-06/schema.rb +8 -3
  75. data/lib/schemas/json-schema.org/draft-07/schema.rb +12 -0
  76. data/readme.rb +138 -0
  77. data/{resources}/schemas/json-schema.org/draft-04/schema.json +149 -0
  78. data/{resources}/schemas/json-schema.org/draft-06/schema.json +154 -0
  79. data/{resources}/schemas/json-schema.org/draft-07/schema.json +168 -0
  80. metadata +69 -118
  81. data/.simplecov +0 -3
  82. data/Rakefile.rb +0 -9
  83. data/jsi.gemspec +0 -28
  84. data/lib/jsi/base/to_rb.rb +0 -128
  85. data/lib/jsi/json/node.rb +0 -203
  86. data/lib/jsi/json/pointer.rb +0 -419
  87. data/lib/jsi/json-schema-fragments.rb +0 -61
  88. data/lib/jsi/json.rb +0 -10
  89. data/resources/icons/AGPL-3.0.png +0 -0
  90. data/test/base_array_test.rb +0 -323
  91. data/test/base_hash_test.rb +0 -337
  92. data/test/base_test.rb +0 -486
  93. data/test/jsi_coder_test.rb +0 -85
  94. data/test/jsi_json_arraynode_test.rb +0 -150
  95. data/test/jsi_json_hashnode_test.rb +0 -132
  96. data/test/jsi_json_node_test.rb +0 -257
  97. data/test/jsi_json_pointer_test.rb +0 -102
  98. data/test/jsi_test.rb +0 -11
  99. data/test/jsi_typelike_as_json_test.rb +0 -53
  100. data/test/metaschema_node_test.rb +0 -19
  101. data/test/schema_module_test.rb +0 -21
  102. data/test/schema_test.rb +0 -208
  103. data/test/spreedly_openapi_test.rb +0 -8
  104. data/test/test_helper.rb +0 -97
  105. 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.class_for_schema(preferences_json_schema)
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 [JSI::Schema, JSI::SchemaModule, Class < JSI::Base] a schema, a JSI schema class, or
29
- # a JSI schema module. #load will instantiate column data using the JSI schema represented.
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, "not a JSI schema, class, or module: #{schema.inspect}")
34
+ raise(ArgumentError, "schema param does not respond to #new_jsi: #{schema.inspect}")
35
35
  end
36
36
  @schema = schema
37
37
  @array = array
@@ -55,6 +55,7 @@ module JSI
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
@@ -0,0 +1,100 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JSI
4
+ # @private
5
+ # internal class to bootstrap a metaschema. represents a schema without the complexity of JSI::Base. the
6
+ # schema is represented but schemas describing the schema are not.
7
+ #
8
+ # this class is to only be instantiated on nodes in the document that are known to be schemas.
9
+ # Schema#subschema and Schema#resource_root_subschema are the intended mechanisms to instantiate subschemas
10
+ # and resolve references. #[] and #jsi_root_node are not implemented.
11
+ #
12
+ # metaschema instance modules are attached to generated subclasses of BootstrapSchema by
13
+ # {SchemaClasses.bootstrap_schema_class}. that subclass is instantiated with a document and
14
+ # pointer, representing a schema.
15
+ class MetaschemaNode::BootstrapSchema
16
+ include Util::Memoize
17
+ include Util::FingerprintHash
18
+ include Schema::SchemaAncestorNode
19
+
20
+ class << self
21
+ def inspect
22
+ if self == MetaschemaNode::BootstrapSchema
23
+ name
24
+ else
25
+ "#{name || MetaschemaNode::BootstrapSchema.name} (#{metaschema_instance_modules.map(&:inspect).join(', ')})"
26
+ end
27
+ end
28
+
29
+ alias_method :to_s, :inspect
30
+ end
31
+
32
+ # @param jsi_ptr [JSI::Ptr] pointer to the schema in the document
33
+ # @param jsi_document [#to_hash, #to_ary, Boolean, Object] document containing the schema
34
+ def initialize(
35
+ jsi_document,
36
+ jsi_ptr: Ptr[],
37
+ jsi_schema_base_uri: nil
38
+ )
39
+ unless respond_to?(:metaschema_instance_modules)
40
+ raise(TypeError, "cannot instantiate #{self.class.inspect} which has no method #metaschema_instance_modules")
41
+ end
42
+
43
+ jsi_initialize_memos
44
+
45
+ self.jsi_ptr = jsi_ptr
46
+ self.jsi_document = jsi_document
47
+ self.jsi_schema_base_uri = jsi_schema_base_uri
48
+ end
49
+
50
+ # document containing the schema content
51
+ attr_reader :jsi_document
52
+
53
+ # JSI::Ptr pointing to this schema within the document
54
+ attr_reader :jsi_ptr
55
+
56
+ def jsi_node_content
57
+ jsi_ptr.evaluate(jsi_document)
58
+ end
59
+
60
+ # @return [String]
61
+ def inspect
62
+ "\#<#{jsi_object_group_text.join(' ')} #{schema_content.inspect}>"
63
+ end
64
+
65
+ # pretty-prints a representation of self to the given printer
66
+ # @return [void]
67
+ def pretty_print(q)
68
+ q.text '#<'
69
+ q.text jsi_object_group_text.join(' ')
70
+ q.group_sub {
71
+ q.nest(2) {
72
+ q.breakable ' '
73
+ q.pp schema_content
74
+ }
75
+ }
76
+ q.breakable ''
77
+ q.text '>'
78
+ end
79
+
80
+ # @private
81
+ # @return [Array<String>]
82
+ def jsi_object_group_text
83
+ [
84
+ self.class.name || MetaschemaNode::BootstrapSchema.name,
85
+ "(#{metaschema_instance_modules.map(&:inspect).join(', ')})",
86
+ jsi_ptr.uri,
87
+ ]
88
+ end
89
+
90
+ # @private
91
+ def jsi_fingerprint
92
+ {
93
+ class: self.class,
94
+ jsi_ptr: @jsi_ptr,
95
+ jsi_document: @jsi_document,
96
+ metaschema_instance_modules: metaschema_instance_modules,
97
+ }
98
+ end
99
+ end
100
+ end
@@ -1,218 +1,245 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module JSI
4
- # a MetaschemaNode is a PathedNode whose node_document contains a metaschema.
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 of the root of the document is pointed to by root_schema_ptr.
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
- # schema and the instance is the same, and a schema may be an instance of itself.
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 document containing the metaschema, its subschemas, and instances of those
14
- # subschemas is the node_document.
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
- # the schema instance is the content in the document pointed to by the MetaschemaNode's node_ptr.
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
- # its schema is the metaschema.
25
- class MetaschemaNode
26
- include PathedNode
27
- include Util::Memoize
28
-
29
- # not every MetaschemaNode is actually an Enumerable, but it's better to include Enumerable on
30
- # the class than to conditionally extend the instance.
31
- include Enumerable
32
-
33
- # @param node_document the document containing the metaschema
34
- # @param node_ptr [JSI::JSON::Pointer] ptr to this MetaschemaNode in node_document
35
- # @param metaschema_root_ptr [JSI::JSON::Pointer] ptr to the root of the metaschema in node_document
36
- # @param root_schema_ptr [JSI::JSON::Pointer] ptr to the schema of the root of the node_document
37
- def initialize(node_document, node_ptr: JSI::JSON::Pointer[], metaschema_root_ptr: JSI::JSON::Pointer[], root_schema_ptr: JSI::JSON::Pointer[])
38
- @node_document = node_document
39
- @node_ptr = node_ptr
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 metaschema_instance_modules [Enumerable<Module>] modules which implement the functionality of the
29
+ # schema, to be applied to every schema which is an instance of the metaschema. this must include
30
+ # JSI::Schema directly or indirectly. these are the {Schema#jsi_schema_instance_modules} of the
31
+ # metaschema.
32
+ # @param metaschema_root_ptr [JSI::Ptr] ptr to the root of the metaschema in the jsi_document
33
+ # @param root_schema_ptr [JSI::Ptr] ptr to the schema describing the root of the jsi_document
34
+ def initialize(
35
+ jsi_document,
36
+ jsi_ptr: Ptr[],
37
+ metaschema_instance_modules: ,
38
+ metaschema_root_ptr: Ptr[],
39
+ root_schema_ptr: Ptr[],
40
+ jsi_schema_base_uri: nil
41
+ )
42
+ jsi_initialize_memos
43
+
44
+ self.jsi_document = jsi_document
45
+ self.jsi_ptr = jsi_ptr
46
+ @metaschema_instance_modules = Util.ensure_module_set(metaschema_instance_modules)
40
47
  @metaschema_root_ptr = metaschema_root_ptr
41
48
  @root_schema_ptr = root_schema_ptr
42
49
 
43
- node_content = self.node_content
50
+ if jsi_ptr.root? && jsi_schema_base_uri
51
+ raise(NotImplementedError, "unsupported jsi_schema_base_uri on metaschema document root")
52
+ end
53
+ self.jsi_schema_base_uri = jsi_schema_base_uri
44
54
 
45
- if node_content.respond_to?(:to_hash)
55
+ jsi_node_content = self.jsi_node_content
56
+
57
+ if jsi_node_content.respond_to?(:to_hash)
46
58
  extend PathedHashNode
47
- elsif node_content.respond_to?(:to_ary)
59
+ end
60
+ if jsi_node_content.respond_to?(:to_ary)
48
61
  extend PathedArrayNode
49
62
  end
50
63
 
51
- instance_for_schema = node_document
52
- schema_ptrs = node_ptr.reference_tokens.inject(Set.new << root_schema_ptr) do |ptrs, tok|
53
- if instance_for_schema.respond_to?(:to_ary)
54
- subschema_ptrs_for_token = ptrs.map do |ptr|
55
- ptr.schema_subschema_ptrs_for_index(node_document, tok)
56
- end.inject(Set.new, &:|)
57
- else
58
- subschema_ptrs_for_token = ptrs.map do |ptr|
59
- ptr.schema_subschema_ptrs_for_property_name(node_document, tok)
60
- end.inject(Set.new, &:|)
64
+ instance_for_schemas = jsi_document
65
+ bootstrap_schema_class = JSI::SchemaClasses.bootstrap_schema_class(metaschema_instance_modules)
66
+ root_bootstrap_schema = bootstrap_schema_class.new(
67
+ jsi_document,
68
+ jsi_ptr: root_schema_ptr,
69
+ jsi_schema_base_uri: nil, # supplying jsi_schema_base_uri on root bootstrap schema is not supported
70
+ )
71
+ our_bootstrap_schemas = jsi_ptr.tokens.inject(SchemaSet[root_bootstrap_schema]) do |bootstrap_schemas, tok|
72
+ child_instance_for_schemas = instance_for_schemas[tok]
73
+ bootstrap_schemas_for_instance = SchemaSet.build do |schemas|
74
+ bootstrap_schemas.each do |bootstrap_schema|
75
+ bootstrap_schema.each_child_applicator_schema(tok, instance_for_schemas) do |child_app_schema|
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
61
81
  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
82
+ instance_for_schemas = child_instance_for_schemas
83
+ bootstrap_schemas_for_instance
67
84
  end
68
85
 
69
- @jsi_schemas = schema_ptrs.map do |schema_ptr|
70
- if schema_ptr == node_ptr
86
+ our_bootstrap_schemas.each do |bootstrap_schema|
87
+ if bootstrap_schema.jsi_ptr == metaschema_root_ptr
88
+ metaschema_instance_modules.each do |metaschema_instance_module|
89
+ extend metaschema_instance_module
90
+ end
91
+ end
92
+ if bootstrap_schema.jsi_ptr == jsi_ptr
93
+ extend Metaschema
94
+ self.jsi_schema_instance_modules = metaschema_instance_modules
95
+ end
96
+ end
97
+
98
+ @jsi_schemas = SchemaSet.new(our_bootstrap_schemas) do |bootstrap_schema|
99
+ if bootstrap_schema.jsi_ptr == jsi_ptr
71
100
  self
72
101
  else
73
- new_node(node_ptr: schema_ptr)
102
+ new_node(
103
+ jsi_ptr: bootstrap_schema.jsi_ptr,
104
+ jsi_schema_base_uri: bootstrap_schema.jsi_schema_base_uri,
105
+ )
74
106
  end
75
- end.to_set
107
+ end
76
108
 
77
109
  @jsi_schemas.each do |schema|
78
- if schema.node_ptr == metaschema_root_ptr
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]))
110
+ extend schema.jsi_schema_module
85
111
  end
86
112
 
87
113
  # workarounds
88
114
  begin # draft 4 boolean schema workaround
89
115
  # in draft 4, boolean schemas are not described in the root, but on anyOf schemas on
90
116
  # properties/additionalProperties and properties/additionalItems.
91
- # we need to extend those as DescribesSchema.
117
+ # since these describe schemas, their jsi_schema_instance_modules are the metaschema_instance_modules.
92
118
  addtlPropsanyOf = metaschema_root_ptr["properties"]["additionalProperties"]["anyOf"]
93
119
  addtlItemsanyOf = metaschema_root_ptr["properties"]["additionalItems"]["anyOf"]
94
120
 
95
- if !node_ptr.root? && [addtlPropsanyOf, addtlItemsanyOf].include?(node_ptr.parent)
96
- extend JSI::Schema::DescribesSchema
121
+ if !jsi_ptr.root? && [addtlPropsanyOf, addtlItemsanyOf].include?(jsi_ptr.parent)
122
+ self.jsi_schema_instance_modules = metaschema_instance_modules
97
123
  end
98
124
  end
99
125
  end
100
126
 
101
- # document containing the metaschema. see PathedNode#node_document.
102
- attr_reader :node_document
103
- # ptr to this metaschema node. see PathedNode#node_ptr.
104
- attr_reader :node_ptr
105
- # ptr to the root of the metaschema in the node_document
127
+ # Set of modules to apply to schemas which are instances of (described by) the metaschema
128
+ # @return [Set<Module>]
129
+ attr_reader :metaschema_instance_modules
130
+
131
+ # ptr to the root of the metaschema in the jsi_document
132
+ # @return [JSI::Ptr]
106
133
  attr_reader :metaschema_root_ptr
107
- # ptr to the schema of the root of the node_document
134
+
135
+ # ptr to the schema of the root of the jsi_document
136
+ # @return [JSI::Ptr]
108
137
  attr_reader :root_schema_ptr
109
- # JSI::Schemas describing this MetaschemaNode
138
+
139
+ # JSI Schemas describing this MetaschemaNode
140
+ # @return [JSI::SchemaSet]
110
141
  attr_reader :jsi_schemas
111
142
 
112
- # @return [MetaschemaNode] document root MetaschemaNode
113
- def document_root_node
114
- new_node(node_ptr: JSI::JSON::Pointer[])
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
115
154
  end
116
155
 
117
- # @return [MetaschemaNode] parent MetaschemaNode
118
- def parent_node
119
- new_node(node_ptr: node_ptr.parent)
156
+ # parent MetaschemaNode
157
+ # @return [MetaschemaNode]
158
+ def jsi_parent_node
159
+ jsi_ptr.parent.evaluate(jsi_root_node)
120
160
  end
121
161
 
122
- # @param token [String, Integer, Object] the token to subscript
123
- # @return [MetaschemaNode, Object] the node content's subscript value at the given token.
124
- # if there is a subschema defined for that token on this MetaschemaNode's schema,
125
- # returns that value as a MetaschemaNode instantiation of that subschema.
126
- def [](token)
162
+ # subscripts to return a child value identified by the given token.
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)
127
168
  if respond_to?(:to_hash)
128
- token_in_range = node_content_hash_pubsend(:key?, token)
129
- value = node_content_hash_pubsend(:[], token)
169
+ token_in_range = jsi_node_content_hash_pubsend(:key?, token)
170
+ value = jsi_node_content_hash_pubsend(:[], token)
130
171
  elsif respond_to?(:to_ary)
131
- token_in_range = node_content_ary_pubsend(:each_index).include?(token)
132
- value = node_content_ary_pubsend(:[], token)
172
+ token_in_range = jsi_node_content_ary_pubsend(:each_index).include?(token)
173
+ value = jsi_node_content_ary_pubsend(:[], token)
133
174
  else
134
- raise(NoMethodError, "cannot subcript (using token: #{token.inspect}) from content: #{node_content.pretty_inspect.chomp}")
175
+ raise(NoMethodError, "cannot subscript (using token: #{token.inspect}) from content: #{jsi_node_content.pretty_inspect.chomp}")
135
176
  end
136
177
 
137
- result = jsi_memoize(:[], token, value, token_in_range) do |token, value, token_in_range|
178
+ begin
138
179
  if token_in_range
139
- value_node = new_node(node_ptr: node_ptr[token])
180
+ value_node = jsi_subinstance_memos[token]
140
181
 
141
- if value_node.is_a?(Schema) || value.respond_to?(:to_hash) || value.respond_to?(:to_ary)
182
+ jsi_subinstance_as_jsi(value, value_node.jsi_schemas, as_jsi) do
142
183
  value_node
143
- else
144
- value
145
184
  end
146
185
  else
147
186
  # I think I will not support Hash#default/#default_proc in this case.
148
187
  nil
149
188
  end
150
189
  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
190
  end
162
191
 
192
+ # instantiates a new MetaschemaNode whose instance is a modified copy of this MetaschemaNode's instance
163
193
  # @yield [Object] the node content of the instance. the block should result
164
194
  # in a (nondestructively) modified copy of this.
165
195
  # @return [MetaschemaNode] modified copy of self
166
- def modified_copy(&block)
167
- MetaschemaNode.new(node_ptr.modified_document_copy(node_document, &block), our_initialize_params)
168
- end
169
-
170
- # @return [String]
171
- def inspect
172
- "\#<#{object_group_text.join(' ')} #{node_content.inspect}>"
173
- end
174
-
175
- def pretty_print(q)
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 '>'
196
+ def jsi_modified_copy(&block)
197
+ MetaschemaNode.new(jsi_ptr.modified_document_copy(jsi_document, &block), **our_initialize_params)
186
198
  end
187
199
 
200
+ # @private
188
201
  # @return [Array<String>]
189
- def object_group_text
190
- if jsi_schemas.any?
191
- class_n_schemas = "#{self.class} (#{jsi_schemas.map { |s| s.node_ptr.uri }.join(' ')})"
202
+ def jsi_object_group_text
203
+ if jsi_schemas && jsi_schemas.any?
204
+ class_n_schemas = "#{self.class} (#{jsi_schemas.map { |s| s.jsi_ptr.uri }.join(' ')})"
192
205
  else
193
206
  class_n_schemas = self.class.to_s
194
207
  end
195
208
  [
196
209
  class_n_schemas,
197
210
  is_a?(Metaschema) ? "Metaschema" : is_a?(Schema) ? "Schema" : nil,
198
- *(node_content.respond_to?(:object_group_text) ? node_content.object_group_text : []),
211
+ *(jsi_node_content.respond_to?(:jsi_object_group_text) ? jsi_node_content.jsi_object_group_text : []),
199
212
  ].compact
200
213
  end
201
214
 
202
- # @return [Object] an opaque fingerprint of this MetaschemaNode for FingerprintHash
215
+ # an opaque fingerprint of this MetaschemaNode for FingerprintHash
203
216
  def jsi_fingerprint
204
- {class: self.class, node_document: node_document}.merge(our_initialize_params)
217
+ {class: self.class, jsi_document: jsi_document}.merge(our_initialize_params)
205
218
  end
206
- include Util::FingerprintHash
207
219
 
208
220
  private
209
221
 
210
222
  def our_initialize_params
211
- {node_ptr: node_ptr, metaschema_root_ptr: metaschema_root_ptr, root_schema_ptr: root_schema_ptr}
223
+ {
224
+ jsi_ptr: jsi_ptr,
225
+ metaschema_instance_modules: metaschema_instance_modules,
226
+ metaschema_root_ptr: metaschema_root_ptr,
227
+ root_schema_ptr: root_schema_ptr,
228
+ jsi_schema_base_uri: jsi_schema_base_uri,
229
+ }
212
230
  end
213
231
 
214
232
  def new_node(params)
215
- MetaschemaNode.new(node_document, our_initialize_params.merge(params))
233
+ MetaschemaNode.new(jsi_document, **our_initialize_params.merge(params))
234
+ end
235
+
236
+ def jsi_subinstance_memos
237
+ jsi_memomap(:subinstance) do |token|
238
+ new_node(
239
+ jsi_ptr: jsi_ptr[token],
240
+ jsi_schema_base_uri: jsi_resource_ancestor_uri,
241
+ )
242
+ end
216
243
  end
217
244
  end
218
245
  end