jsi 0.4.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
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